char *p="abc" 與 char p[]="abc" 的區別
阿新 • • 發佈:2019-01-05
有這樣一段程式碼:
輸出:#include "stdio.h" char *get_string_1() { char p[] = "hello world!"; return p; } char *get_string_2() { char *p = "hello world!"; return p; } int main() { char *p; p = get_string_1(); printf("get_string_1:%s/n",p); p = get_string_2(); printf("get_string_2:%s/n",p); return 0; }
get_string_1:(亂碼或者沒有輸出,linux下沒有任何輸出)
get_string_2:hello world!
1.為什麼輸出結果是這樣?
2.字串"abc"是常量嗎?
3.char *p = "abc";這樣寫到底合不合法,實際應用中能不能這樣寫?
解析:
char *p = "hello world!";與char p[] = "hello world!"; 兩者都用來宣告一個字串,並將其初始化為hello world!,但是表示的意義確是大不相同。
從其宣告的物件來說:
char p[] = "hello world!"; //用來宣告一個數組p,陣列大小為12位元組。
char *p = "hello world!"; //用來宣告一個指標p,指向“hello world!”字串起始位置。
從儲存位置來說:
char p[] = "hello world!"; //p陣列作為區域性變數被儲存在棧區;
char *p = "hello world!"; //在這個宣告中,"hello world!"被儲存在靜態資料區 ,而且是全域性的,p僅僅就是個指標,指向這個區域。不信的話可以試試下邊的程式碼,看是不是同一個地址:
char *p1 = "hello world!";
char *p2 = "hello world!";
printf("p1:%x/np2:%x/n",p1,p2);
第一個問題:為什麼輸出結果是這樣?
由於C函式執行完之後對棧區進行清除操作,對靜態資料區和堆則沒有,因此get_string_1()函式執行完就釋放了棧區記憶體,所
(1)不是常量的情況:
"abc"作為字元陣列初始值的時候就不是,如
char str[] = "abc";
因為定義的是一個字元陣列,所以就相當於定義了一些空間(注意!)來存放"abc",而又因為字元陣列就是把字元一個一個地存放的,所以編譯器把這個語句解析為
char str[3] = {'a','b','c'};
以字串形式出現的,編譯器都會為該字串自動新增一個0作為結束符,所以char str[] = "abc";的最終結果是
char str[4] = {'a','b','c','\0'};
做一下擴充套件,如果char str[] = "abc";是在函式內部寫的話,那麼這裡的"abc\0"因為不是常量,所以應該被放在棧上。 (2)是常量的情況:
把"abc"賦給一個字元指標變數時,如
char* ptr = "abc";
因為定義的是一個普通指標,並沒有定義空間(注意!)來存放"abc",所以編譯器得幫我們找地方來放"abc",顯然,把這裡的"abc"當成常量並把它放到程式的常量區是編譯器最合適的選擇。所以儘管ptr的型別不是const char*,並且ptr[0] = 'x';也能編譯通過,但是執行ptr[0] = 'x';就會發生執行時異常,因為這個語句試圖去修改程式常量區中的東西。
第三個問題,char *p = "hello world!";這樣寫到底合不合法? 記得哪本書中曾經說過char* ptr = "abc";這種寫法原來在c++標準中是不允許的,但是因為這種寫法在c中實在是太多了,為了相容c,不允許也得允許。雖然允許,但是建議的寫法應該是 const char* ptr = "abc";這樣如果後面寫ptr[0] = 'x'的話編譯器就不會讓它編譯通過,也就避免了上面說的執行時異常。
再擴充套件一下: 1.如果char* ptr = "abc";寫在函式體內,那麼雖然這裡的"abc\0"被放在常量區中,但是ptr本身只是一個普通的指標變數,所以ptr是被放在棧上的,只不過是它所指向的東西被放 在常量區罷了。
2.字串常量的型別可以理解為相應字元常量陣列的型別,如"abcdef"的型別就可以看成是const char[7] 。
3.如果真的需要使用"abcd"作為指標,建議寫為const char * p="abcd";
4.如果是初始化字串陣列,建議寫為char p[]="abcd";
5.如果p為指標,需要初始化,應該是char *p;p=malloc(STR_SIZE);strcpy(p,"abcd");