在〈字元陣列與字串〉談過 C 風格字串,本質上就是個字元陣列,而陣列名稱具有指標性質,那可以如下建立字串嗎?
char *text = "hello";
gcc 沒提出任何警訊,然而 text 儲存了字串常量的位址值,字串常量建立的內容是唯讀的,如果試圖透過 text 改變字元,會發生不可預期的結果:
char *text = "hello";
text[0] = 'H'; // 不可預期
因此對於字面常量,建議加上 const:
const char *text = "hello";
如此一來,試圖透過 text 改變字元,編譯器會失敗,從而避免了執行時期的錯誤。
上述方式中,text 只是個型態為 const char* 的指標,是與以下不同的,底下建立的 text 內容並不是唯讀的,因為 text 是個陣列,text 是將 "hello" 複製至各索引處:
char text[] = "hello";
對於 wchar_t 等其他為了支援 Unicode 的型態,都有這類特性。
然而,無論是哪個形式,都可以傳遞位址,例如:
char text1[] = "hello";
const char *text2 = "hello";
const char *text = text1; // OK
text = text2; // OK
不過,底下不行:
char text1[] = "hello";
const char *text2 = "hello";
char *text = text1; // OK
text = text2; // error: invalid conversion from 'const char*' to 'char*'
錯誤該行如果真的想通過編譯,就必須明確告訴編譯器,你要去除 const 修飾:
char text1[] = "hello";
const char *text2 = "hello";
char *text = text1; // OK
text = (char*) text2; // 強制去除 const
會需要這麼做的情況,可能是在使用一些舊的函式,它們在參數上宣告的是 char*,而不是 const char*。
那麼,如何建立字串陣列呢?
#include <stdio.h>
int main(void) {
const char *names[] = {"Justin", "Monica", "Irene"};
for(int i = 0; i < 3; i++) {
const char *name = names[i];
printf("%s\n", name);
}
return 0;
}
留意一下底下的不同:
const char *names1[] = {"Justin", "Monica", "Irene"};
char names2[][10] = {"Justin", "Monica", "Irene"};
name1 的每個元素,儲存了各個字串常量的位址值;然而,name2 是有三個長度為 10 的 char 陣列,並複製了各個字串常量的 char。
可以透過 typedef 為 const char* 建立別名,令字串陣列的建立易讀、易寫一些:
#include <stdio.h>
typedef const char* String;
int main(void) {
String names[] = {"Justin", "Monica", "Irene"};
for(int i = 0; i < 3; i++) {
String name = names[i];
printf("%s\n", name);
}
return 0;
}

