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

strcpy 與 memcpy 手寫實現深度解析

     編輯:關於C語言

strcpy 與 memcpy 手寫實現深度解析

面試高頻考點:手寫 strcpy、memcpy。看似簡單,實則包含空指針檢查、自拷貝處理、內存重疊安全拷貝、const 正確性、返回值約定等工業級細節。本文給出健壯、標準庫級的實現,並對比兩者核心差異。

一、strcpy 實現(含重疊安全)

char* my_strcpy(char* dest, const char* src) {
    // 1. 參數合法性
    if (!dest || !src) return NULL;  // 或 assert
    
    // 2. 自拷貝直接返回
    if (dest == src) return dest;
    
    // 3. 計算長度(含 '\0')
    size_t len = strlen(src) + 1;
    
    // 4. 判斷重疊並選擇拷貝方向
    // dest 在 src 之前,或 dest 在 src+len 之後:無重疊或安全區域,前向拷貝
    // 否則:重疊且 dest 在 src 之後,必須後向拷貝避免覆蓋未讀數據
    if (dest < src || dest >= src + len) {
        // 前向拷貝
        char* d = dest;
        const char* s = src;
        while (len--) *d++ = *s++;
    } else {
        // 後向拷貝
        char* d = dest + len - 1;
        const char* s = src + len - 1;
        while (len--) *d-- = *s--;
    }
    return dest;
}

二、memcpy 實現(標準庫級)

void* my_memcpy(void* dest, const void* src, size_t n) {
    if (!dest || !src) return NULL;
    if (dest == src) return dest;
    
    char* d = (char*)dest;
    const char* s = (const char*)src;
    
    // 重疊判斷邏輯同 strcpy
    if (d < s || d >= s + n) {
        // 前向
        while (n--) *d++ = *s++;
    } else {
        // 後向
        d += n - 1;
        s += n - 1;
        while (n--) *d-- = *s--;
    }
    return dest;
}

三、strcpy vs memcpy 核心差異

維度strcpymemcpy
拷貝內容僅字符串(以 '\0' 結束)任意二進制數據(結構體、數組、整數等)
長度確定遇到 '\0' 停止,隱式長度顯式指定 n 字節
安全性易溢出,不推薦,用 strncpy/strlcpy長度可控,相對安全
返回值返回 dest返回 dest
適用場景字符串複製內存塊移動、結構體賦值、網絡包組裝

四、常見簡化版實現(教學/面試速寫)

// strcpy 極簡版(無重疊保護,無空檢查)
char* strcpy_simple(char* dest, const char* src) {
    char* ret = dest;
    while ((*dest++ = *src++));
    return ret;
}

// memcpy 極簡版
void* memcpy_simple(void* dest, const void* src, size_t n) {
    char* d = dest;
    const char* s = src;
    while (n--) *d++ = *s++;
    return dest;
}

五、擴展:strcat、strcmp、strlen、strlwr 手寫

// strcat: 追加 src 到 dest 末尾
char* my_strcat(char* dest, const char* src) {
    char* d = dest;
    while (*d) ++d;      // 找到 '\0'
    while ((*d++ = *src++)); // 拷貝含 '\0'
    return dest;
}

// strcmp: 字典序比較
int my_strcmp(const char* s1, const char* s2) {
    while (*s1 && *s1 == *s2) { ++s1; ++s2; }
    return (unsigned char)*s1 - (unsigned char)*s2;
}

// strlen: 計算長度
size_t my_strlen(const char* s) {
    const char* p = s;
    while (*p) ++p;
    return p - s;
}

// strlwr: 轉小寫(非標準,Windows 有)
char* my_strlwr(char* s) {
    for (char* p = s; *p; ++p) *p = tolower(*p);
    return s;
}

六、避坑指南

  1. const 正確性:src 必須 const,防止誤修改源數據。
  2. 重疊處理:memmove 標準庫函數保證處理重疊,memcpy 標準不保證(實現多為前向),手寫時建議加重疊保護。
  3. 返回 dest:鏈式調用慣例,如 printf("%s", strcpy(buf, "hello"));。
  4. 字符類型轉換:strcmp 中轉 unsigned char 防止負字符值比較錯誤。

熟練掌握這些底層內存操作的邊界條件與實現細節,不僅能應付面試,更能在系統編程、嵌入式開發、庫開發中寫出零成本、高可靠的代碼。

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