1. 程式人生 > >char *p="abc" 與 char p[]="abc" 的區別

char *p="abc" 與 char p[]="abc" 的區別

有這樣一段程式碼:

#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()函式執行完就釋放了棧區記憶體,所

以根本就不存在存有"hello world!"宣告時的記憶體,也就不可能有所輸出。

第二個問題:"abc"是常量嗎?答案:有時是,有時不是 
(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");