2010-10-13 93 views
3

下面編譯給出的代碼段,並且當運行給出結果爲:奇怪指針問題

$ make 
gcc -g -Wall -o test test.c 
$ ./test 
string 

/* CODE1 */

#include<stdio.h> 
char *somefunc1() 
{ 
    char *temp="string"; 
    return temp; 
} 
int main(int argc,char *argv[]) 
{ 
    puts(somefunc1()); 
    return 0; 
} 

而輕微修改這個代碼給出不同的結果:

$ make 
gcc -g -Wall -o test test.c 
test.c: In function ‘somefunc1’: 
test.c:5: warning: function returns address of local variable 
$ ./test 

/* code 2 */ 

#include<stdio.h> 
char *somefunc1() 
{ 
    char temp[] ="string"; 
    return temp; 
} 
int main(int argc,char *argv[]) 
{ 
    puts(somefunc1()); 
    return 0; 
} 

爲什麼會發生這種情況?

+2

當然你可以想出比「奇怪指針問題」更好的標題。 – Eyal 2010-10-13 10:09:47

回答

4

char *temp = "string";將創建一個指針temp指向一個字符串litteral。該字符串文字存儲在可執行代碼的數據段中。它是不可變的,函數返回後地址仍然有效。

char temp[] = "string";將在堆棧上分配7個字符,並將它們設置爲'string'。這些是可變字符。在你的例子中,返回值指向當函數返回時不再有效的字符。

+0

s /銷燬/不再有效/? – 2010-10-13 10:11:50

+0

它們確實被摧毀了,有多奇怪,我並不期待:D(p.s.,我永遠不會使用char [])。 – 2010-10-13 10:13:34

+0

@Hassan Syed:正如你所說的,你可以聲明'temp' static來在函數調用後保存它,但這不是非常好的設計。 – JoshD 2010-10-13 10:15:33

-1

當你做char * temp =「string」; temp的內存分配在堆中,並保持在那裏直到程序執行。而當你做char temp [] =「string」; 內存分配在堆棧上,一旦超出範圍,將被刪除或無效。在第二種情況下的程序中,一旦你在函數something1之外,返回的指針將變爲無效。在第一種情況下,因爲數組在堆上,所以內存不會失效。但是,你已經成功地泄漏了內存。

+0

關於內存泄漏的好處。 – 2010-10-13 10:01:16

+2

char * temp =「string」不會在堆上分配。 – JoshD 2010-10-13 10:06:29

+1

-1。這裏沒有堆分配。只有在調用函數'malloc','calloc'或'realloc'時纔會發生堆分配。因此在第一個程序中也沒有內存泄漏。 – 2010-10-13 10:07:03

4

在第一個示例中,您正在返回字符串文字的地址。只要程序執行,這個字面就存在,所以代碼是安全的。

在第二個示例中,您將創建一個(函數本地)數組,該數組被初始化爲包含字符串string。然後繼續返回該數組(的第一個元素)的地址,但是一旦離開該函數,數組就會被銷燬。這是你的編譯器警告你的。 使用從somefunc1返回的指針導致未定義的行爲,因爲它不再引用現有對象。

+0

非常好的解釋(和第一個正確的)+1。 – JoshD 2010-10-13 10:09:03

1

退出函數後堆棧變量丟失,因此在第二種情況下出現「奇怪的行爲」。