玩轉常量字符串

1.Reference: http://hi.baidu.com/benzhan/item/8c52be37ca4c9bd76c15e9f9
warning: 原文沒有參考文獻
2.
先擼段代碼來看看

char str1[] = "abc";
char str2[] = "abc";

const char str3[] = "abc";
const char str4[] = "abc";

const char *str5 = "abc";
const char *str6 = "abc";

char *str7 = "abc";
char *str8 = "abc";


cout << ( str1 == str2 ) << endl;
cout << ( str3 == str4 ) << endl;
cout << ( str5 == str6 ) << endl;
cout << ( str7 == str8 ) << endl;

*注:以上bool型的cout我在gcc下編譯沒通過,不清楚原作者是用什麼編譯器:(
因此,引用作者的程序結果,是:0 0 1 1
str1,str2,str3,str4是數組變量,它們有各自的內存空間;
而str5,str6,str7,str8是指針,它們指向相同的常量區域。

再來一段代碼會更清楚點。

#include <stdio.h>

char *returnStr_P()
{
    char *temp = "pointer";
    return temp;
}

char *returnStr_A()
{
    char temp[] = "array";
    return temp;
}

char *returnStr_A_S()
{
    static char temp[] = "static array";
    return temp;
}

int main()
{
    char *str_p = NULL;
    char *str_a = NULL;
    char *str_a_s = NULL;

    str_p = returnStr_P();
    str_a = returnStr_A();
    str_a_s = returnStr_A_S();

    printf("str_P = %s\n", str_p);
    printf("str_a = %s\n", str_a);
    printf("str_a_s = %s\n", str_a_s);

    return 0;
}

運行結果是

str_P = pointer
str_a = ����Зc���8�}�
str_a_s = static array

看出點問題了嗎?以下我將原作者的思想用我的話以及我的程序結果來表述一下。

(1)因爲”pointer”是一個字符串常量,存放在靜態數據區,把該字符串常量存放的靜態數據區的首地址賦值給了指針temp,所以returnStr_P函數退出時,該字符串常量所在內存不會被回收,故能夠通過指針順利無誤的訪問。

(2)“array“依然也是一個字符串常量,依然存放在靜態數據區,但是把一個字符串常量賦值給了一個局部變量(char型數組temp),該局部變量存放在棧中,這樣就有兩塊內容一樣的內存,也就是說“char temp[]=”array”;”這條語句讓“array”這個字符串在內存中有兩份拷貝,一份在動態分配的棧中,另一份在靜態存儲區。這是與returnStr_P()最本質的區別。當returnStr_A函數退出時,棧要清空,局部變量的內存也被清空了,所以這時的函數返回的是一個已被釋放的內存地址,所以打印出來的是亂碼。其實強大的gcc已經給了warning了:

test.c: In function ‘returnStr_A’:
test.c:12:2: warning: function returns address of local variable [-Wreturn-local-addr]
  return temp;
  ^

(3)針對前兩點總結下,就是雖然returnStr_P()與returnStr_A()返回的都是一個內存地址,但是returnStr_A()中temp是先將”array” copy一份在自己的內存地址上,當函數結束時,棧空間釋放,該地址上自然沒用內容給str_a了。而由此我做個推斷(如果有誤還望細心的讀者指出),起碼靜態存儲區上的生命週期是整個程序。( PS. 經過小心求證後結果確實是如此:) )

(4)如果非得要返回局部變量的地址,那麼該局部變量一定要申明爲static類型,強行將temp申明爲靜態變量,存儲於靜態存儲區。相信從上面的代碼可以清楚的體驗出來。

3.重點來了
原作者的中心思想看似有理有據,但是在沒有參考文獻的前提下我還是抱着半信半疑的態度翻閱了其他的一些資料,終於在 歐立奇等. 程序員面試寶典. 電子工業出版社 中找到了一些解釋。

內存的分配方式有5種:靜態存儲區、棧區、堆區、文字常量區、程序代碼區。靜態存儲區,內存在編譯時已經分配好空間,並且生命週期爲整個程序,例如全局變量、static變量。文字常量區,常量字符串就是存放在此處,生命週期也是整個程序,待程序結束後由系統釋放,例如int i = 123; char *p = “hello”; 等,等號右邊的這些常量均試存放再文字常量區的。這與該作者的“存放在靜態存儲區“有些出入。而我本人還是願意選擇更加相信後者。但我覺得通過此次,解釋了平日的一些困惑,總之該作者的主思想是正確的,就是對於字符串常量的存放位置可能理解方面有些不同。仁者見仁智者見智。

以上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章