1. 程式人生 > >char a[](字串陣列)和char *a(字串指標)區別

char a[](字串陣列)和char *a(字串指標)區別

C語言中,對字串的操作主要有兩種方式,一是使用字元陣列,char str[];二是使用字元指標。那麼二者有什麼區別呢?下面將分述二者的使用,最後進行比較。

一、字元陣列

        使用char str[]定義一個字元陣列str,中括號內可以寫上數字表示陣列大小,也可以不寫。如果不寫數字,則必須為字元陣列提供初始值,以便編譯器進行記憶體分配。

可以使用字串字面值(string literal)來初始化字元陣列,也可使用字元字面值(character literal)初始化,如:

[cpp] view plain copy  print?
  1. char str1[10]=
    "Hello";  
  2. char str2[]="World";  
  3. char str3[]={'H','e','l','l','o'};  

只能對字元陣列元素的賦值,而不能用賦值語句對整個陣列賦值,如: [cpp] view plain copy  print?
  1. char str4[10];  
  2. str4={'H','e','l','l','o'};    // 錯誤
  3. str4="Hello";                  // 錯誤
  4. str4[0]='H';str4[1]='e';str4[2]='l';str4[3]='l';str4[4]='o';   // 正確

可以使用迴圈將字元陣列中的字元一個一個輸出,也可以使用cout<<str1直接輸出整個陣列。

需要注意的是,上述程式碼中str1和str2是C風格字串,而str3不是。C風格字串,是指以\0結尾的字元陣列。C++為了相容C,而保留了C中字串的使用方法。

str1和str2使用字串字面值進行初始化,字串字面值使用\0表示字串結束。因此str2長度為6,需要將\0計算在內。使用strlen函式,計算的是字串的實際長度,不包含\0。

而str3則不一樣,它沒有\0作為結束標誌,因而不是C風格字串,使用cout<<str3可能會出現意想不到的結果。

二、字元指標

可以使用char *str指向一個字串。如:

[cpp] view plain copy  print
?
  1. char *ptr="C++";  
  2. char strArr[]="C++";  
  3. char *ptr2=strArr;  

使用cout<<ptr即可輸出整個字串,而使用cout<<*ptr則輸出字串的首字元。

字元指標也可指向C風格字串,如ptr就是指向的C風格字串。如果讓ptr指向上節中的str3,輸出ptr會出現同樣的意想不到的結果。畢竟陣列名其實就是一種指標。

三、區別

前面簡單介紹了一下兩種操作字串的方法,這部分進行比較,是本文的重點。如下程式碼:

[cpp] view plain copy  print?
  1. char s[]="abc";  
  2. char *ptr="abc";  
  3. cout<<s<<endl;               // abc
  4. cout<<*s<<endl;              // a
  5. cout<<&s<<endl;              // 地址
  6. cout<<(s+1)<<endl;           // bc
  7. cout<<*(s+1)<<endl;          // b
  8. cout<<&s[1]<<endl<<endl;     // a
  9. cout<<ptr<<endl;             // abc
  10. cout<<*ptr<<endl;            // a
  11. cout<<&ptr<<endl;            // 地址
  12. cout<<(ptr+1)<<endl;         // bc
  13. cout<<*(ptr+1)<<endl;        // b
  14. cout<<&ptr[1]<<endl;         // a
這些程式碼應該能夠說明char s[]和char *ptr之間的相似點了。它們都是指向字串的指標。

下面說二者的不同之處。如下一段程式碼:

[cpp] view plain copy  print?
  1. char ss[]="C++";  
  2. ss[0]='c';                  // 合法
  3. char *p="C++";  
  4. p[0]='c';                   // 合法但不正確
該段程式碼在VS2010下編譯可以通過,但是執行時程式會停止工作,為什麼呢?原因在於p[0]='c'這一語句。該語句試圖修改p指向的字串的首個字元,出現了錯誤。

原因在於兩種方式對字元陣列操作的機制不同。使用char *p="C++"語句後,編譯器在記憶體的文字常量區分配一塊記憶體,儲存”C++“這一字串字面值,然後在棧上分配記憶體儲存p,p的內容為"C++"的地址。p[0]='c'試圖修改常量”C++“,程式當然就會崩潰了。而char ss[]="C++"語句,定義了一個數組,編譯器為其在棧上分配了記憶體空間,因而可以進行修改操作。

因此,可以總結如下:

(1)char ss[]定義了一個數組,ss可認為是一個常指標,ss不可改變,但ss指向的內容可以發生改變。

(2)char *p定義了一個可變指標,p可以指向其它物件。但對於char *p=”abc“這樣的情況,p指向的是常量,故內容不能改變。

如下程式碼進一步說明char ss[]和char *p的區別:

[cpp] view plain copy  print?
  1. char *strA()  
  2. {  
  3.     char str[]="Hello";  
  4.     return str;  
  5. }  

呼叫該函式,不一定能夠得到正確的結果。因為str定義了一個區域性資料,是區域性變數,存在於函式strA中的棧幀中。當函式呼叫完成後,棧幀恢復到函式strA呼叫前的狀態,臨時空間被重置,為函式分配的棧空間被收回,str所指向的地址也就不存在了。

將上述程式碼修改:

[cpp] view plain copy  print?
  1. char *strA()  
  2. {  
  3.     char *str="Hello";  
  4.     return str;  
  5. }  

該函式能夠正常執行,因為str指向的字串字面值被儲存在只讀的資料段,是全域性的,當函式呼叫完成後,str指向的地址未發生變化。

綜上,可以看出使用char []較容易出錯,可能出現不確定的結果。C++提供的string類相比之下,要安全的多了。