2016-12-04 69 views
0

我有兩個函數具有相同的返回類型:爲什麼這個類似的函數不會拋出相同的錯誤?

char * getRandomWord(char wordlist[WORDLIST_LENGTH][WORD_LENGTH]) { 
    int random = rand() % WORDLIST_LENGTH; 
    return wordlist[random]; 
} 

char * revealInString(char * s, int * r) { 
    size_t strLength = strlen(s); 
    char revealedString[strLength + 1]; 
    for (int i = 0; i < strLength; i++) { 
     revealedString[i] = '_'; 
    } 
    for (int i = 0; i < strLength; i++) { 
     if (r[i] != NULL) { 
      int positionToReveal = r[i]; 
      revealedString[positionToReveal] = s[positionToReveal]; 
     } 
    } 
    revealedString[strLength - 1] = '\0'; 
    return revealedString; 
} 

的第一個作品沒有問題,而我的IDE(克利翁)顯示了第二個問題:Value escapes the local scope

爲什麼第二個函數顯示錯誤,而第一個函數也返回一個沒有問題的字符數組?

回答

1

語法char revealedString[N]定義了在堆棧上分配的VLA(C99功能)。

...但你的revealInString函數然後返回一個指向棧分配內存的指針。這是一個錯誤:當你的函數返回堆棧被彈出,所以revealedString現在指向無效的內存。

比較起來,你的第一個例子返回一個指向被調用函數之前分配的內存的指針。

雖然函數在堆棧上分配,然後返回,可以工作(如果調用者沒有進一步調用),這是一個非常糟糕的主意,因爲它取決於未定義的行爲。

您有固定的問題兩個選項:

  1. 有來電在棧上分配VLA之前調用revealInString
  2. 在堆上分配(與callocmalloc)的陣列,並確保當他們完成時,來電者撥打free

實施例1:

char revealedStringBuffer[ strlen(s) + 1 ]; 
revealInString(revealedStringBuffer, r); // and change `revealInString` to return void 

實施例2:

char * revealInString(char * s, int * r) { 
    size_t strLength = strlen(s); 
    char* revealedString = calloc(strLength + 1, sizeof(char)); 
    if(revealedString == NULL) die("calloc failure."); 

    for (int i = 0; i < strLength; i++) { 
     revealedString[i] = '_'; 
    } 
    for (int i = 0; i < strLength; i++) { 
     if (r[i] != NULL) { 
      int positionToReveal = r[i]; 
      revealedString[positionToReveal] = s[positionToReveal]; 
     } 
    } 
    revealedString[strLength - 1] = '\0'; 
    return revealedString; 
} 

// Usage: 
char* revealedString = revealInString(s, r); 
free(revealedString); 
1

他們都不返回一個數組。他們返回一個指針(至char)。

在第二個函數中,返回的指針指向一個局部變量。當函數返回時局部變量被銷燬,所以返回的指針變爲無效。這就是編譯器警告你的原因。

在第一種情況下,你返回一個由調用者傳入的指針,所以如果它是有效的,那麼它在函數返回時仍然有效。