2012-11-07 23 views
0

我不能賦值在循環中的字符數組,做它包含在每一個陣列值分配環路值字符數組指針

例如這工作

char* foo[3]; 

foo[0] = "mango"; foo[1] = "kiwi"; foo[2] = "banana"; 

int i=0; for(i=0;i<3;i++) 
{ 
    printf("%s\n",foo[i]); 
} 

但相同的值這不,我不明白爲什麼。

char* foo[3]; int i=0; 

for(i=0;i<3;i++) { 
    char temp[5]; 
    sprintf(temp,"VAL:%d",i); 
    foo[i] = temp; 
} 

for(i=0;i<3;i++) 
{ 
    printf("%s\n",foo[i]); 
} 

請提前感謝幫助和

+2

'爲(I = 0; I <3;我++){炭溫度[ 5];的sprintf(溫度, 「VAL:%d」,i)的; foo [i] = temp; }在循環體完成之後,將一個指針賦給一個不存在的局部變量。你的編譯器沒有警告過這個嗎? –

+0

我正在使用gcc的code :: blocks,日誌窗口被關閉了,因爲我認爲它不會花費太多時間來記住一些東西,對不起這個 – Rayum

回答

2

您必須記住,在C中,char*實際上並不存儲字符串,但它存儲了將被視爲字符串的第一個字符的內存位置的地址。

在第一個示例中,foo數組的每個元素都包含不同字符串的地址。 在第二個示例中,使foo陣列的每個元素都指向本地變量temp。儘管循環中的每次迭代都會產生一個單獨的temp實例,但任何理智的編譯器都會將所有這些實例放在彼此之上,從而給出您體驗的結果。

的解決方法是,使用一個二維數組:

char foo[3][6]; int i=0; 

for (i=0; i<3; i++) { sprintf(foo[i],"VAL:%d", i); } 

for (i=0; i<3; i++) { printf("%s\n", foo[i]); } 

或者使用動態分配:

char* foo[3]; int i=0; 

for (i=0; i<3; i++) { char* temp = malloc(6); sprintf(temp, "VAL:%d", i); foo[i] = temp; } 

for (i=0; i<3; i++) { printf("%s\n", foo[i]); free(foo[i]); } 
+0

「任何理智的編譯器都會把所有的這些實例在彼此之上「但是你沒有解釋他做了什麼*錯誤*。你聽起來像是編譯器工作的一個奇怪的僥倖。但編譯器可能(或不可能)使用相同位置的原因是它在第一次迭代之後超出了範圍,所以變量不再「存在」。所以OP的問題是他維護一個指向超出範圍的東西,這是未定義的行爲 – newacct

+0

@newacct:你對未定義的行爲是正確的。我故意沒有提及它,因爲我認爲把重點放在如何獲得工作解決方案上更重要,而不是指出並詳細解釋非工作代碼中的所有錯誤。 –

3

在第二片段中的問題是,在foo點的所有元件以相同的變量,temp,執行第二for時,這是超出範圍,這是未定義的行爲。即使它沒有超出範圍,foo中的所有元素都會指向相同的不正確的緩衝區。

若要更正,您需要複製temp並將其存儲在foo的每個元素中。這可以通過使用strdup()來實現(如果可用)(如果不是malloc()strcpy()):

for (i = 0; i < sizeof(foo)/sizeof(foo[0]); i++) 
{ 
    char temp[6]; 
    snprintf(temp, sizeof(temp), "VAL:%d", i); 
    foo[i] = strdup(temp); /* Must be free()d later. */ 
} 

或改變foo類型(如已被unwind建議):

char foo[3][6]; 
int i; 
for (i = 0; i < sizeof(foo)/sizeof(foo[0]);i++) 
{ 
    snprintf(foo[i], sizeof(foo[i]), "VAL:%d", i); 
} 

其他變化:

  • temp增加到6的大小,因爲它需要5 characters VAL:%dplus null terminator附加sprintf()。發佈的代碼由於此而具有緩衝區溢出。
  • 使用snprintf()來避免緩衝區溢出。
  • 使用sizeof(foo)/sizeof(foo[0])來計算數組foo中的元素數,而不是對元素數進行硬編碼。
+0

謝謝不知道snprintf() – Rayum

0

在迴路中的temp變量在每次迭代相同的內存可能重新使用,所以你最終寫相同的地址到每個foo[]插槽。然後,更糟糕的是,當您退出循環時,該地址將無法訪問,導致未定義的行爲。

您需要動態分配每個字符串,或者將字符串數組與空間用於實際字符串(char foo[3][20];或其他)。

0

兩個問題:

1)您已經聲明tempchar temp[5]和你有超過4個字符的餡是:通過使sprintf的寫入超過數組結束

sprintf(temp,"VAL:%d",i); 

有因爲它必須寫入終止\0

2)變量temp是for循環的局部變量,並且一旦循環結束,它就會超出範圍。