2014-04-24 69 views
0

我用C編寫了一個小程序,編譯完美並且工作,當我通過我的Makefileclang進行編譯時,然而,在Xcode中,這個函數表現得不像它應該的那樣而鏗鏘無視它)。C strcpy的怪異行爲

size_t getUrlForArgAndPlatform(char **dest, const char *arg, const char *platform) { 
    int isLinux = strcmp(platform, "Linux"); 
    int isOSX = strcmp(platform, "Darwin"); 

    char *platformUrlDelimiter = malloc(6 + 1); 
    if (isLinux == 0) { 
     strcpy(platformUrlDelimiter, "linux"); 
    } else if (isOSX == 0) { 
     strcpy(platformUrlDelimiter, "osx"); 
    } else { 
     strcpy(platformUrlDelimiter, "common"); 
    } 

    int length = (int) strlen(kBaseUrl); 
    length += strlen(platformUrlDelimiter); 
    length += strlen(arg); 
    length += 5; 

    char *buffer = (char *) malloc(length); 
    if (buffer == NULL) { 
     exit(EXIT_FAILURE); 
    } 
    strcpy(buffer, kBaseUrl); 
    strcat(buffer, "/"); 
    strcat(buffer, platformUrlDelimiter); 
    strcat(buffer, "/"); 
    strcat(buffer, arg); 
    strcat(buffer, ".md"); 

    *dest = malloc(strlen(buffer) + 1); 
    strcpy(*dest, buffer); 

    free(platformUrlDelimiter); 
    free(buffer); 

    return strlen(buffer) + 1; 
} 

它的工作原理4次滿分10分。在其他的6倍,Xcode是告訴我它的失敗在strcpy(*dest, buffer)一個SIGBRT。如果我看看調試器,我看到buffer包含兩次相同的字符串。爲什麼?

回答

2

你計算buffer大小是不太正確的:

int length = (int) strlen(kBaseUrl); 
length += strlen(platformUrlDelimiter); 
length += strlen(arg); 
length += 5; 

最後一部分應該是「+6」,因爲你需要的2倍"/"空間,爲終止NUL".md"

+0

Hooray!是的,就是這樣。但爲什麼它不會每次都失敗呢? – Leandros

+0

這是由於*未定義的行爲*的性質。有時候,這樣的錯誤代碼似乎很長一段時間才能正常工作,直到... –

0

(不正確的長度已經提到。)

有很多無謂的複製在你的代碼怎麼回事。由於您不修改platformUrlDelimiter,因此無需複製兩次。這更簡單:

const char *platformUrlDelimiter = "common"; 
if (isLinux == 0) { 
    platformUrlDelimiter = "linux"; 
} else if (isOSX == 0) { 
    platformUrlDelimiter = "osx"; 
} 

並刪除對free (platformUrlDelimiter)的呼叫。

strcat()(可能)的每個調用都必須不必要地循環遍歷緩衝區。我會寫:

int length = strlen(kBaseUrl) 
      + strlen(platformUrlDelimiter) 
      + strlen(arg) 
      + 6; 

*dest = malloc(length); 
if (*dest) { 
    sprintf (*dest, "%s/%s/%s.md", kBaseUrl, platformUrlDelimiter, arg); 
} else { 
    /* Error */ 
} 

return length; 

現在根本沒有必要使用buffer

此外,還有一個真正的錯誤就在你的代碼的末尾:

free(buffer); 

return strlen(buffer) + 1; 

不得使用buffer值以任何方式已被釋放之後。