strcpy 與 strcat 是 C 字串操作最基礎也最危險的兩個函數。本文解析標準庫實現邏輯,揭示緩衝區溢位根源,提供安全替代方案。
char* strcpy(char* dest, const char* src);
char* strcpy(char* dest, const char* src) {
char* ret = dest;
assert(dest != NULL && src != NULL);
while ((*dest++ = *src++) != '\0'); // 複製含結尾 \0
return ret;
}
dest 容量,src 過長必導致緩衝區溢位src 與 dest 重疊行為未定義char* strcat(char* dest, const char* src);
char* strcat(char* dest, const char* src) {
char* ret = dest;
assert(dest && src);
while (*dest) dest++; // 找到 dest 結尾 \0
while ((*dest++ = *src++)); // 接上 src 含 \0
return ret;
}
dest 有足夠空間容納原字串 + src + \0| 函數 | 標準 | 特性 |
|---|---|---|
strncpy | C89 | 指定最大複製字元數,但不保證以 \0 結尾 |
strncat | C89 | 指定最大拼接字元數,保證 \0 結尾 |
snprintf | C99 | 推薦:snprintf(dest, size, "%s", src) 複製;snprintf(dest, size, "%s%s", dest, src) 拼接,自動處理 \0 與截斷 |
strcpy_s / strcat_s | C11 Annex K | Microsoft 推廣,帶邊界檢查,回傳錯誤碼 |
snprintf 或 strncat + 手動保證 \0sizeof(buffer) 傳遞大小,避免硬編碼size_t len 變數,避免重複 strlenstd::string,彈性且安全char buf[10];
strcpy(buf, "Hello World"); // 溢位!需 12 字元含 \0
strcat(buf, "!"); // 疊加溢位
// 正確
snprintf(buf, sizeof(buf), "%s", "Hello"); // 複製
snprintf(buf, sizeof(buf), "%s!", buf); // 拼接