在〈字元陣列與字串〉談過 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;
}