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

C語言字串複製:strcpy 模擬實現與安全增強版 strcpy_s/strlcpy

     編輯:關於C語言

C語言字串複製:strcpy 模擬實現與安全增強版 strcpy_s/strlcpy

`strcpy` 是最基礎也最危險的字串函數:**無長度檢查、極易緩衝區溢出**。本文提供標準實現、C11 `strcpy_s`、BSD `strlcpy` 安全替代方案,並修正原始碼註釋中的邏輯混淆。

標準 strcpy 實現

#include 

char *my_strcpy(char *dest, const char *src) {
    assert(dest && src);
    
    char *ret = dest;
    
    // 核心:複製含 \0,賦值表達式結果為賦予的值
    while ((*dest++ = *src++) != '\0')
        ;
    
    return ret;
}

原始碼註釋邏輯混淆分析

// 原始碼註釋:
while ((*dest++ = *src++)) ;  // 正確:含 \0 複製
/*while (*src) {               // 替代寫法:漏複製 \0
    *dest = *src;
    dest++; src++;
}*/
// 原串為 \0 時跳出,並未拷貝 \0, 要賦值 *dest = '\0'
// 原註釋邏輯混淆:第一種寫法已含 \0,第二種才需手動補 \0

安全替代方案對比

函數標準簽名行為返回值
strcpyC89(dest, src)無檢查,高危dest
strncpyC89(dest, src, n)固定寫 n 字元,不保證 \0dest
strcpy_sC11 (Annex K)(dest, destsz, src)檢查邊界,失敗返回錯誤碼errno_t (0成功)
strlcpyBSD/常見擴展(dest, src, destsz)保證 \0,返回 src 長度size_t (嘗試長度)

strcpy_s 實現 (C11 Annex K)

#define __STDC_WANT_LIB_EXT1__ 1
#include 
#include 

errno_t my_strcpy_s(char *dest, rsize_t destsz, const char *src) {
    if (dest == NULL || src == NULL || destsz == 0 || destsz > RSIZE_MAX) {
        if (dest && destsz) *dest = '\0';
        return EINVAL;
    }
    
    rsize_t i = 0;
    while (i < destsz && src[i]) {
        dest[i] = src[i];
        i++;
    }
    
    if (i == destsz) {  // src 過長,未遇 \0
        dest[0] = '\0';
        return ERANGE;
    }
    
    dest[i] = '\0';
    return 0;
}

strlcpy 實現 (BSD 風格,推薦)

size_t my_strlcpy(char *dest, const char *src, size_t destsz) {
    const char *s = src;
    size_t n = destsz;
    
    if (n) {
        while (--n && *s) *dest++ = *s++;
        *dest = '\0';
    }
    
    // 計算 src 剩餘長度 (含已複製部分)
    while (*s++) ;
    return (s - src - 1);
}

使用示範與風險對比

int main() {
    char buf[10];
    const char *src = "hello world!";  // 12 字元 + \0 = 13
    
    // 危險:strcpy 溢出
    // strcpy(buf, src);  // 寫入 13 字元到 10 位元組緩衝區 → UB
    
    // 不安全:strncpy 不保證 \0
    // strncpy(buf, src, sizeof(buf));  // buf 可能無 \0!
    
    // 安全:strlcpy (推薦)
    size_t len = strlcpy(buf, src, sizeof(buf));
    printf("strlcpy: buf=\"%s\", 返回長度=%zu (截斷=%s)\n", 
           buf, len, len >= sizeof(buf) ? "是" : "否");
    // 輸出: buf="hello wo", 返回長度=12 (截斷=是)
    
    // 安全:strcpy_s (C11)
    #ifdef __STDC_LIB_EXT1__
    errno_t err = strcpy_s(buf, sizeof(buf), src);
    printf("strcpy_s: buf=\"%s\", 錯誤碼=%d\n", buf, err);
    #endif
    
    return 0;
}

總結

`strcpy` = **棄用、高危**。`strncpy` = **陷阱、不保證 \0、固定寫入**。**現代代碼強制使用 `strlcpy` (返回長度、保證 \0) 或 `strcpy_s` (C11、錯誤碼)**。原始碼實現正確但註釋邏輯混淆:第一種 `while(*d++=*s++)` 已含 `\0`,第二種 `while(*s)` 才需手動補 `\0`。面試必會:四者差異、緩衝區溢出風險、返回值語義、標準歸屬。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved