本系列第三篇聚焦「指標與字串」交互產生的經典錯誤,涵蓋 NULL vs NUL、字串初始化四大陷阱、標準庫函式誤用、函式傳遞/回傳字串的記憶體管理、函式指標應用。
((void*)0),用於指標比較/初始化。'\0' (ASCII 0),字串結束標記。if (str == NUL) 應為 if (str == NULL) 或 if (*str == '\0')。| 方式 | 程式碼 | 儲存區 | 可修改? | 備註 |
|---|---|---|---|---|
| 字面常數 | char *s = "Hello"; | 唯讀資料區 | 否 | 修改導致崩潰 |
| 陣列初始化 | char s[] = "Hello"; | 堆疊/資料區 | 是 | 含結束符,長度 6 |
| 陣列逐字元 | char s[] = {'H','e','l','l','o','\0'}; | 堆疊/資料區 | 是 | 手動加 \0 |
| 動態配置 | char *s = malloc(6); strcpy(s, "Hello"); | 堆積 | 是 | 需 free(),長度含 \0 |

char s[10] = "Hello";
sizeof(s) // 10 (編譯期陣列大小,含未使用空間)
strlen(s) // 5 (執行期字串長度,遇 \0 停止)

strcpy(dest, src):不檢查長度,src 過長導致緩衝區溢位。strncpy(dest, src, n):若 src 長度 ≥ n,不自動補 \0,後續操作風險極大。strcat(dest, src):同樣不檢查 dest 剩餘空間。snprintf、strlcpy (BSD)、或手動檢查長度。

size_t stringLength(char *str) {
size_t len = 0;
while (*(str++)) len++;
return len;
}
實際傳遞的是首字元位址,函式內可修改內容(除非參數為 const char*)。
return "Hello"; (靜態存活,唯讀)return malloc(...); (呼叫端須 free)void getStr(char *buf, size_t n); (最安全)絕對禁止: 回傳區域陣列/字串指標(函式返回後堆疊框架銷毀,指標成懸空)。

void process(const char *str, void (*callback)(const char *)) {
// 處理邏輯...
callback(str); // 回呼
}
void printUpper(const char *s) {
while (*s) putchar(toupper(*s++));
}
// 使用
process("hello", printUpper);
💡 核心原則: 「誰配置,誰釋放」;字串指標傳遞時明確標註
const;永遠假設輸入可能包含嵌入式\0或超長,邊界檢查不可省略。