C 語言無原生字符串類型,字符串本質是以 \0 結尾的字符陣列。本文系統梳理字符串的兩種定義方式、\0 的核心作用、strlen 行為、字符串陣列兩種形式,並附帶常見陷阱避坑指南。
| 方式 | 代碼 | 類型 | 可修改性 | 存儲區 | 適用場景 |
|---|---|---|---|---|---|
| 字符陣列 | char name[] = "itcast"; | 陣列 | ✅ 可修改內容 | 棧 (局部) / 數據段 (全域) | 內容需頻繁修改 |
| 字符指針 | char *name = "itcast"; | 指針指向常量 | ❌ 內容不可修改 (UB) | 只讀數據段 (常量區) | 內容固定、頻繁只讀 |
strlen、printf("%s")、strcpy 等所有標準庫函數以 \0 為界"abc" 編譯器自動補 \0,等價於 {'a','b','c','\0'}char name[] = {'i', 't'}; // ❌ 缺 \0,非字符串
printf("%s", name); // 亂碼,繼續讀取直到隨機遇到 0
char name2[] = {'i', 't', '\0'}; // ✅ 正確
char name3[] = {'i', 't', 0}; // ✅ 正確 (0 即 \0)
char name4[8] = {'i', 't'}; // ✅ 餘下自動補 0 (全域/靜態同理)
strlen 關鍵特性strlen("abc") == 3char *names[3] = {"Jack", "Rose", "Jake"}; // 每元素是 char*
// 內存:指針陣列(棧) + 字面量(常量區)
names[0][1] = 'A'; // ❌ UB,修改常量區
char names2[3][10] = {"Jack", "Rose", "Jake"}; // 連續 3×10 字節
names2[0][1] = 'A'; // ✅ 合法,修改棧上數據
#include#include int main() { char name[20]; printf("Enter name: "); scanf("%s", name); // 讀至空白,自動補 \0 printf("Length: %zu\n", strlen(name)); printf("3rd char: %c\n", name[2]); // 0-based // 字符串陣列遍歷 char *fruits[] = {"Apple", "Banana", "Cherry"}; for (int i = 0; i < 3; i++) printf("%s: len=%zu\n", fruits[i], strlen(fruits[i])); return 0; }
char *p = "abc"; p[0] = 'x'; → 段錯誤(修改只讀段)char a[5] = "hello"; → 溢出(需 6 字節含 \0)scanf("%s", buf); 無長度限制 → 緩衝區溢出(用 %19s)strcmp(a, b) == 1 判斷相等 → 應用 == 0malloc + strcpy,用完 free掌握「陣列可改、指針指常量、\0 是命門」三大核心,即可駕馭 C 語言字符串的所有基礎操作。