首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

從零手寫 strcpy:字串複製的底層邏輯與防禦性程式設計

     編輯:關於C語言

為什麼要手寫 strcpy?

  • 理解指標運算、字串結束符機制
  • 面試經典考題:考察 C 基礎與邊界條件處理
  • 嵌入式/核心開發:無標準庫環境下的自給自足
  • 安全強化:標準 strcpy 不檢查緩衝區大小,易導致溢位

標準庫 strcpy 簽名與語義

char *strcpy(char *restrict dest, const char *restrict src);
  • 將 src 指向的字串(含 '\0')複製到 dest
  • 回傳 dest(鏈式呼叫用)
  • 行為未定義:dest 空間不足、記憶體重疊

手寫版本演進:從朴素到健壯

版本 1:最小可行實現(教學用)

char *my_strcpy_v1(char *dest, const char *src) {
    char *ret = dest;
    while ((*dest++ = *src++) != '\0');
    return ret;
}

缺陷:無空指標檢查、無緩衝區長度檢查、dest 必須可寫。

版本 2:防禦性實現(生產級)

char *my_strcpy_v2(char *dest, const char *src) {
    if (!dest || !src) return NULL;           // 空指標防護
    
    char *ret = dest;
    while ((*dest++ = *src++) != '\0');       // 複製含結束符
    return ret;
}

版本 3:安全版 strcpy_s 風格(指定緩衝區大小)

/* 回傳 0 成功,非 0 失敗(ERANGE/EINVAL) */
int my_strcpy_s(char *dest, size_t destsz, const char *src) {
    if (!dest || !src || destsz == 0) return EINVAL;
    
    size_t i = 0;
    for (; i < destsz - 1 && src[i] != '\0'; ++i)
        dest[i] = src[i];
    
    if (i == destsz - 1 && src[i] != '\0') {  // 空間不足
        dest[0] = '\0';
        return ERANGE;
    }
    dest[i] = '\0';
    return 0;
}

核心邏輯解析:while ((*dest++ = *src++) != '\0')

  1. *src++:取得當前字元,src 後移
  2. *dest++ = ...:寫入當前位置,dest 後移
  3. != '\0':判斷剛寫入的字元是否為結束符
  4. 若非 '\0' → 繼續迴圈;若是 → 結束符已寫入,迴圈結束

關鍵洞察:賦值運算式的值是被賦予的值,因此迴圈條件天然包含「複製並檢查結束符」的雙重語意。

測試驗證程式

#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest1[20], dest2[20], dest3[10];  // 最後一個故意太小
    
    // 版本 2 測試
    my_strcpy_v2(dest1, src);
    printf("v2: %s\n", dest1);
    
    // 安全版測試
    int r = my_strcpy_s(dest2, sizeof(dest2), src);
    printf("v3 (normal): %s, ret=%d\n", dest2, r);
    
    r = my_strcpy_s(dest3, sizeof(dest3), src);  // 空間不足
    printf("v3 (overflow): '%s', ret=%d (ERANGE=%d)\n", dest3, r, ERANGE);
    
    return 0;
}

進階話題:效能優化與標準庫實現

  • 字對齊複製:現代 libc 使用 memcpy + 向量化指令(SSE/AVX/NEON)按 16/32/64 位元組塊複製
  • strlen + memcpy 兩階段:先算長度再大塊複製,利用 CPU 預取器
  • restrict 關鍵字:告訴編譯器 src 與 dest 不重疊,啟用積極優化

避坑檢查清單

  1. ✅ 空指標檢查
  2. ✅ 目的緩衝區大小驗證(安全版)
  3. ✅ 正確處理 '\0' 複製
  4. ✅ 回傳值語意清晰(指標 vs 錯誤碼)
  5. ⚠️ 記憶體重疊情況(memmove 語意)未處理
  6. ⚠️ 多執行緒環境下 src 可能被並發修改
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved