char* strcpy(char* dest, const char* src);
// 複製 src 至 dest,包含結束符 '\0'
// 返回 dest 原始值
// 行為未定義:dest 空間不足、src/dest 重疊、src 非以 \0 結尾
char* my_strcpy(char* dest, const char* src) {
// 1. 參數驗證
if (dest == NULL || src == NULL) return NULL;
// 2. 保存 dest 起始位址 (返回值)
char* ret = dest;
// 3. 核心複製迴圈:複製字元並檢查結束符
// 先賦值再判斷,確保 '\0' 也被複製
while ((*dest++ = *src++) != '\0') {
// 本體為空,所有工作在條件表達式完成
}
// 4. 返回原始 dest
return ret;
}
if (dest==NULL || src==NULL):防禦性程式設計,避免空指標解引用崩潰char* ret = dest:儲存起始位址,因 `dest` 會在迴圈中遞增while ((*dest++ = *src++) != '\0'):經典單行複製
return ret:返回原始 dest,符合標準庫慣例,支援鏈式呼叫#include
char* my_strcpy(char* dest, const char* src) {
if (!dest || !src) return NULL;
char* ret = dest;
while ((*dest++ = *src++) != '\0');
return ret;
}
int main() {
char src[] = "Hello, World!";
char dest[50];
printf("複製前: dest = \"%s\"\n", dest);
my_strcpy(dest, src);
printf("複製後: dest = \"%s\"\n", dest);
printf("返回值指向: %s\n", my_strcpy(dest, "New String"));
// 測試空字串
char empty[] = "";
my_strcpy(dest, empty);
printf("空字串複製: '%s' (長度 %zu)\n", dest, strlen(dest));
return 0;
}
char* my_strncpy(char* dest, const char* src, size_t n) {
if (!dest || !src) return NULL;
char* ret = dest;
while (n-- && (*dest++ = *src++) != '\0');
// 若 src 結束而 n>0,需補 \0 (標準 strncpy 行為)
while (n--) *dest++ = '\0';
return ret;
}
| 錯誤寫法 | 問題 | 修正 |
|---|---|---|
| while (*src) *dest++ = *src++; | 未複製結束符 '\0' | 改為 do-while 或條件包含賦值 |
| char* dest = "literal"; strcpy(dest, src); | 字串常數不可修改 | 用陣列 `char dest[100]` 或 malloc |
| 未檢查 dest 空間大小 | 緩衝區溢位 | 使用 strncpy 或確保足夠大 |
| src 與 dest 重疊 | 行為未定義 | 用 memmove 或保證不重疊 |
| 返回 dest 而非原始值 | 破壞鏈式呼叫慣例 | 保存並返回起始位址 |
// 針對長字串,按 word (4/8 bytes) 複製
char* fast_strcpy(char* dest, const char* src) {
char* ret = dest;
// 對齊到 word 邊界
while ((uintptr_t)dest % sizeof(long) && (*dest++ = *src++));
// 批量複製
long* d = (long*)dest;
const long* s = (const long*)src;
while (!has_zero_byte(*s)) *d++ = *s++;
// 剩餘位元組
dest = (char*)d; src = (char*)s;
while ((*dest++ = *src++) != '\0');
return ret;
}
// 檢測 64-bit word 中是否包含 0 byte
int has_zero_byte(unsigned long x) {
return (x - 0x0101010101010101UL) & ~x & 0x8080808080808080UL;
}
手寫 strcpy 是理解指標運算、字串結構、函數介面設計的基礎訓練。掌握單行複製慣用語 `while (*d++ = *s++)` 是 C 程式設計師的必修課。