代碼中以雙引號括起的字符串字面量,編譯器會自動在末尾添加 \0。"abc" 實際存儲為 "abc\0"。
| 場景 | 代碼示例 | 存儲位置 | 可修改性 | 本質 |
|---|---|---|---|---|
| 初始化字符數組 | char str[] = "abc"; | 棧區(函數內)或數據段(全局) | ✅ 可修改 | 數組元素逐個拷貝字面量內容 |
| 賦值給字符指針 | char *ptr = "abc"; | 只讀常量區 | ❌ 不可修改(運行時崩潰) | 指針指向字面量原始地址 |
char str[] = "abc";
// 編譯器等效展開為:
char str[4] = {'a', 'b', 'c', '\0'};
str[0] = 'x'; 完全合法。
char *ptr = "abc";
ptr[0] = 'x'; 編譯通過,但運行時觸發段錯誤(寫保護內存)。const char *ptr = "abc";,編譯期即可攔截修改嘗試。
void func() {
char *ptr = "abc"; // "abc\0" 在常量區,ptr 變量在棧上
}
指針變量 ptr 自身是局部變量,存儲在棧上;它指向的內容 在常量區。兩者存儲位置獨立。
char s1[3]; // 類型:char[3]
char s2[4]; // 類型:char[4]
// 雖然都是字符數組,但類型不同,不可互賦值
"abcdef" // 類型視為 const char[7] (含 \0)
sizeof(int)、sizeof(a)(a 為 int 變量)均為 4。sizeof(expr) 等價於 sizeof(type of expr),不計算表達式值。
void func(char sa[100], int ia[20], char *p);
// 編譯器內部等效為:
void func(char *sa, int *ia, char *p);
// 參數類型均為指針,sizeof(sa) == sizeof(ia) == sizeof(p) == 指針大小(4/8)
數組作參數退化為指針,失去大小信息。
| 代碼 | sizeof 結果 | 原因 |
|---|---|---|
char str[] = "abcdef"; | sizeof(str) == 7 | 類型 char[7] |
sizeof("abcdef") | 7 | 字面量類型 const char[7] |
char *ptr = "abcdef"; | sizeof(ptr) == 4/8 | ptr 類型 char*(指針大小) |
char str2[10] = "abcdef"; | sizeof(str2) == 10 | 類型 char[10],編譯期固定 |
函數參數 char sa[100] | sizeof(sa) == 4/8 | 退化為 char* |
const char * 習慣:讓編譯器幫你守護只讀內存。徹底理解這些機制,是寫出無內存錯誤、高性能 C 代碼的基石。