`strcpy` 看似簡單,實則考察三大核心能力:
char *strcpy(char *dest, const char *src); // 複製 src 字串(含結束符 \0)到 dest // 回傳 dest 指標,支援鏈式呼叫 // 行為未定義:dest 空間不足、src/dest 重疊
#includechar *my_strcpy(char *dest, const char *src) { // 1. 斷言檢查(Debug 版攔截,Release 版零開銷) assert(dest != NULL && src != NULL); // 2. 保存原始 dest 以便回傳(鏈式呼叫關鍵) char *ret = dest; // 3. 經典單行複製迴圈:賦值與判斷合併 // *dest++ = *src++ 先解參考賦值,再遞增指標 // 結果為賦值後的字元值,\0 為 0 (false) 結束迴圈 while ((*dest++ = *src++)) ; // 4. 回傳原始目的地址 return ret; }
| 程式碼 | 解析 |
|---|---|
| `assert(dest && src)` | 防禦性程式設計,捕捉空指標傳入。生產碼可改為 `if (!dest || !src) return NULL;` |
| `char *ret = dest;` | 因 `dest` 會在迴圈中遞增至末尾,必須保存起始位址供回傳。 |
| `while ((*dest++ = *src++)) ;` | C 語言經典慣用語:賦值運算式的值為賦值結果。複製 `\0` 時值為 0,迴圈結束。分號代表空迴圈體。 |
| `return ret;` | 支援 `printf("%s", my_strcpy(buf, "hello"));` 等鏈式呼叫。 |
// 回傳 0 成功,非 0 失敗
errno_t strcpy_s(char *dest, size_t destsz, const char *src) {
if (!dest || !src || destsz == 0) return EINVAL;
char *d = dest;
const char *s = src;
while (destsz-- && (*d++ = *s++)) ;
if (destsz == 0) { *dest = '\0'; return ERANGE; } // 空間不足
return 0;
}
size_t my_strlen(const char *s) {
assert(s);
const char *p = s;
while (*p) p++;
return p - s; // 指標相減得元素個數
}
手寫 `strcpy` 不只是背誦程式碼,而是展現對 C 語言指標算術、運算式求值順序、標準庫契約、防禦性程式設計的綜合掌握。面試時寫出上述版本並能娓娓道來每一行設計理由,即為通關關鍵。