c++ | String in C

http://www.cnblogs.com/oomusou/archive/2007/03/04/663234.html

 char s[]字串和char *s字串有什麼差別? (C/C++) (C)

Abstract
C語言有兩種字串宣告方式char s[]和char *s,兩者有什麼差異呢?

Introduction

char s[] = "Hello World";
char *s  = "Hello World";


皆宣告了s字串,在C-style string的函數皆可使用,但兩者背後意義卻不相同。

char s[] = "Hello World";


的s是個char array,含12個byte(包含結尾\0),"Hello World"對s來說是initializer,將字元一個一個地copy進s陣列。

char *s = "Hello World";


的s是一個pointer指向char,由於"Hello World"本身就是一個string literal,所以s指向"Hello World"這個string literal的起始記憶體位置。

做個簡單的實驗證明兩者不同

 1#include <iostream>
 2
 3using namespace std;
 4
 5int main() {
 6 char s1[] = "Hello World";
 7 char *s2  = "Hello World";
 8 
 9 cout << "size of s1: " << sizeof(s1) << endl;
10 cout << "size of s2: " << sizeof(s2) << endl;
11}


執行結果

size of s1: 12
size of s2: 4


s1是陣列,所以占了12 byte,而s2只是pointer,所以占了4 byte,實驗結果與預期相同。

實際使用有什麼不同嗎?兩種寫法皆可使用substring和pointer寫法,但只有char *s可以直接使用*s++寫法。

char s[]

 1#include <iostream>
 2
 3using namespace std;
 4
 5int main() {
 6 char s[] = "Hello World";
 7 
 8 for(int i = 0; i != 11; ++i) {
 9  cout << s[i];
10 }

11 cout << endl;
12 
13 for(int i = 0; i != 11; ++i) {
14  cout << *(s + i);
15 }

16 cout << endl;
17}

18


執行結果

Hello World
Hello World


char *s

 1#include <iostream>
 2
 3using namespace std;
 4
 5int main() {
 6 char *s = "Hello World";
 7 
 8 for(int i = 0; i != 11; ++i) {
 9  cout << s[i];
10 }

11 cout << endl;
12 
13 for(int i = 0; i != 11; ++i) {
14  cout << *(s + i);
15 }

16 cout << endl;
17}


執行結果

Hello World
Hello World


但卻只有char *s可以使用*s++寫法。

 1#include <iostream>
 2
 3using namespace std;
 4
 5int main() {
 6 char *s = "Hello World";
 7 
 8 while(*s) 
 9  cout << *s++;
10}

11
12


執行結果

Hello World


理由何在呢?

char s[]為陣列,雖然s = &s[0],但s是『常數』,恆等於&s[0]無法改變,但char *s為pointer,指向s[0],但卻是變數,可以任意改變,故可用*s++任意更改pointer值。

Conclusion
一般人很少分辨char s[]和char *s的差異,大部分狀況下用法相同,但char *s速度略快,因為不需copy的動作,且*s++為C語言常用的寫法,只有char *s才支援。

Reference
C Primer Plus 5/e中文版 p.480

分类: C/C++C


請問..C語言 字元陣列與字串有何不同?

發問者:阿福 ( 初學者 1 級)
發問時間:2012-02-26 01:51:55
解決時間:2012-02-29 09:26:21
解答贈點:共有 0 人贊助 )
回答:1 評論: 0 意見: 10
檢舉 ]
網友正面評價80%
剛剛在yahoo知識家看到有人寫:

3. 字串 

希望你知道什麼叫「陣列」。事實上 C 語言裡面的 "字串" 指的是 "字元陣列",只是陣列的結尾一定要用 '\0' 表示,才可以稱為是字串。如

char name1[] = {'a', 'b', 'c' , '\0'} ; 

它是字元陣列,可稱字串,因結尾是用 '\0;

char name2[] = {'a', 'b', 'c'} 

它是字元陣列,但不是字串,因結尾不是用 '\0'

至於看到另一些程式碼會這麼寫

char name3[] = "ABC" 

它是字元陣列,也是字串,實際上上述的寫法已經幫你在結尾的部份補上了 '\0' 這個東西。另再注意, '\0' 這個字元在 ASCII Table 裡面,就是 0 所對應之字元。

請問..字元陣列與字串有何不同?

我想原發問者可以這樣理解:

1) 嚴格來說 C 語言本身並沒有什麼字串,字串只存在人的心裡。說穿了你只是拿一種比較小的整數陣列來存放字碼,至於尾端加 '\0' 則是一種古時候傳下來的使用習慣(當然,當所有人、包含標準程式庫都這麼做的時候,你不跟就會很難過)。

如果你去看比較咬文嚼字的「法典」,你會發現裡面不太講「字串」,只稱 char array,而 string 出現大多是因為 string literal。

2) char 是一種整數,char 陣列和 int 陣列的行為無差別,除了可以用 string literal 初始化

3) 字元常數(Character constants):亦即用 ' ' 包夾的東西,在 C/C++ 當中字元常數被視為一種整數,和 66、99 這些數值沒有差別。有趣的是,假如你用 C 語言的話字元常數型別應該是 int,在 C++ 則是 char。

你可以寫
char s[] = {65, 66, 67};
也可以寫
char s[] = {'A', 'B', 'C'};

如果希望符合其他人對字串的期待,最好加'\0'
char s[] = {'A', 'B', 'C', '\0'};

4) String literal:亦即用 " " 包夾的東西。通常你可以將 string literal 想成一種特殊的字元陣列,自動以 '\0' 收尾,而且存放在某個不能修改的記憶體裡面。

由於 string literal 也是陣列(嚴格來說是陣列的位址),所以這樣是完全合法的:
char c = "abc"[1];  // c 被初始化為 'b'
但你不能修改內容: "abc"[0] = 'x';

你可以用指標去指向一個 string literal,和你用指標去指其他陣列一樣,但是注意在 C++ 下 string literal 具有 const 屬性
char* str = "string literal";       // 不好的寫法,C++編譯器會拒絕
char const *str = "string literal"; // 嚴謹的寫法

所有的陣列都可以用 {...} 初始化,但 C/C++ 特許字元陣列用 string literal 代替 {...} 初始化
char s[] = "ABC";
完全等於
char s[] = {'A', 'B', 'C', '\0'};
這是在本地建立陣列並初始化,所以未來可以修改內容。和前面用指標指向唯讀的 string literal 意義完全不同。

-----
結論:字串只是一種使用慣例罷了,你只要理解字元陣列和 string literal 就可以了。

Comments