| 特性 | 字符指針 char *p | 字符數組 char arr[] |
|---|---|---|
| 存儲內容 | 字符串首地址 | 字符串所有字符 |
| 字符串位置 | 常量區(只讀)或堆/棧 | 棧/數據區(可讀寫) |
| 賦值方式 | p = "str" 合法 | arr = "str" 非法 (左值錯誤) |
| 修改內容 | 未定義行為 (常量區崩潰) | 合法,可逐字符修改 |
| sizeof 結果 | 指針大小 (4/8) | 數組總字節數 (含 \0) |
char *p = "C Language"; // OK
// p = "New"; // OK,改變指向
char arr[20] = "C Language"; // OK,初始化
// arr = "New"; // 編譯錯誤:左值必須可修改
// 必須用 strcpy/逐字符賦值
int main() {
char str1[40] = "hello world!";
// char *str1 = "hello world!"; // 取消註釋將崩潰
str1[4] = 'A'; // 數組:合法 → "hellA world!"
// *str1 = 'A'; // 指針:運行時段錯誤 (SIGSEGV)
printf("%s\n", str1);
return 0;
}
char *p = "abc":編譯器在只讀數據段創建字符串常量,p 指向其首地址。嘗試修改觸發硬件異常;char a[] = "abc":編譯器在棧/數據段分配數組,並將常量區內容複製進數組。數組擁有獨立可寫副本。// 錯誤:傳入字符串常量會崩潰
// void strlower(char *s) { while(*s) *s = tolower(*s); }
// 正確:const 修飾輸入,內部拷貝副本修改
char* strlower(const char *input) {
char *copy = strdup(input); // 需 free
for (char *p = copy; *p; ++p) *p = tolower(*p);
return copy;
}
// 或要求調用者傳入可修改緩衝區
void strlower_inplace(char *buf) { // buf 必須指向可寫內存
for (; *buf; ++buf) *buf = tolower(*buf);
}
// 錯誤:野指針
char *name;
scanf("%s", name); // 未分配內存,未定義行為
// 修正 1:用數組
char name[20];
scanf("%19s", name);
// 修正 2:動態分配
char *name = malloc(50);
scanf("%49s", name);
// 使用後 free(name)
void reverse_print(const char *s) {
if (!*s) return;
reverse_print(s + 1); // 先遞歸到末尾
putchar(*s); // 回溯時輸出,實現反序
}
「指針指向常量,數組擁有副本」是 C 語言字符串處理的分水嶺。牢記:只讀用 const char*,可寫用數組或動態分配,杜絕段錯誤與未定義行為。