手寫標準庫字串函數是 C 語言指標功力的試金石。本文提供 **生產級實現**,涵蓋參數驗證、const 正確性、返回值設計、重疊處理、效能優化,並對比原始碼的常見缺陷。
#include <assert.h>
#include <string.h>
char *my_strcpy(char *dest, const char *src) {
assert(dest != NULL && src != NULL); // 參數驗證
char *ret = dest; // 保存起始位址,支援鏈式調用
// 核心複製迴圈:包含結束符 \0
while ((*dest++ = *src++) != '\0')
; // 空語句
return ret;
}
char *my_strstr(const char *haystack, const char *needle) {
assert(haystack && needle);
if (*needle == '\0') return (char *)haystack; // 空 needle 返回 haystack
for (const char *h = haystack; *h; h++) {
const char *p1 = h;
const char *p2 = needle;
while (*p1 && *p2 && *p1 == *p2) {
p1++; p2++;
}
if (*p2 == '\0') return (char *)h; // 找到完整匹配
}
return NULL; // 未找到
}
char *my_strcat(char *dest, const char *src) {
assert(dest && src);
char *ret = dest;
// 1. 找到 dest 結束符
while (*dest) dest++;
// 2. 拼接 src (含 \0)
while ((*dest++ = *src++) != '\0')
;
return ret;
}
char buf[20] = "hello"; my_strcat(buf, buf + 2); // 嘗試將 "llo" 拼接到 "hello" 後 // 行為未定義!dest 讀寫位址重疊,可能無限迴圈或記憶體損壞
標準庫保證:`strcat` 行為未定義於重疊。**解決方案**:使用 `memmove` 或手動從後向前複製。
// 現代編譯器會優化為向量化指令 (SSE/AVX/NEON)
char *my_strcpy_opt(char *dest, const char *src) {
return strcpy(dest, src); // 直接呼叫 libc 優化版
}
// 或使用 restrict 關鍵字 (C99) 協助編譯器優化
char *my_strcpy_restrict(char *restrict dest, const char *restrict src) {
// restrict 告訴編譯器 dest/src 不重疊,可積極向量化
return strcpy(dest, src);
}
| 函數 | 常見錯誤 | 正確做法 |
|---|---|---|
| strcpy | 忘記複製 `\0`、返回值錯誤、無 assert | 迴圈含 `\0`、返回原 dest、assert 非空 |
| strstr | 指針回溯邏輯錯、空 needle 未處理 | 雙指針匹配、匹配失敗 h++ 繼續、空 needle 返回 haystack |
| strcat | 未找 dest 末尾、緩衝區溢出風險 | 先找 `\0`、呼叫者保證空間足夠 |
模擬實現核心在於:**指標算術精準控制、const 正確性、邊界條件處理 (空串、NULL)、返回值語義 (支援鏈式)、重疊行為文檔化**。實務開發**直接使用標準庫**,編譯器內建優化 (builtin) 遠超手寫迴圈。面試重點考察:`while (*dest++ = *src++)` 精簡寫法理解、空串處理、重疊未定義行為認知。