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

C 標準庫字符串函數參考實現:strcpy/strlen/strcmp 等核心源碼解析

     編輯:關於C語言
 

學習價值

  • 深化對 C 指針、數組、空終止字符串語義的理解。
  • 面試筆試高頻考點:手寫 strcpy、strlen、strcmp 等。
  • 掌握斷言檢查、空指針防護、返回值約定的工業級編碼風格。

核心函數參考實現 (精簡註釋版)

strcpy — 字符串拷貝

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

關鍵點:返回目的地址鏈式調用;拷貝包含結束符;無長度檢查,調用者保證空間足夠。

strlen — 計算長度

size_t strlen(const char *s) {
    assert(s);
    size_t len = 0;
    while (*s++ != '\0') ++len;
    return len;
}

關鍵點:不包含結束符;返回 size_t 無符號。

strcmp — 字典序比較

int strcmp(const char *s1, const char *s2) {
    assert(s1 && s2);
    while (*s1 && *s2 && *s1 == *s1) { ++s1; ++s2; }
    return (unsigned char)*s1 - (unsigned char)*s2;
}

關鍵點:轉 unsigned char 避免符號擴展導致錯誤;返回 <0, =0, >0。

strcat / strncat — 追加/追加限長

char *strcat(char *dest, const char *src) {
    assert(dest && src);
    char *ret = dest;
    while (*dest) ++dest;           // 定位結束符
    while ((*dest++ = *src++) != '\0');
    return ret;
}

strchr / strrchr — 正/反向查找字符

char *strchr(const char *s, int c) {
    assert(s);
    for (; *s != (char)c; ++s)
        if (*s == '\0') return NULL;
    return (char *)s;
}
char *strrchr(const char *s, int c) {
    assert(s);
    const char *end = s;
    while (*end) ++end;             // 先走到結束符
    for (--end; end >= s; --end)
        if (*end == (char)c) return (char *)end;
    return NULL;
}

strstr — 子串查找 (暴力 O(n*m))

char *strstr(const char *haystack, const char *needle) {
    assert(haystack && needle);
    if (!*needle) return (char *)haystack;
    for (; *haystack; ++haystack) {
        const char *h = haystack, *n = needle;
        while (*n && *h == *n) { ++h; ++n; }
        if (!*n) return (char *)haystack;
    }
    return NULL;
}

註:生產級庫常用 KMP/Two-Way/Sunday 算法優化至 O(n+m)。

strtok — 分詞器 (有狀態、非線程安全)

char *strtok(char *str, const char *delim) {
    static char *next = NULL;
    if (str) next = str;
    if (!next) return NULL;
    // 跳過前導分隔符
    str = next;
    while (*str && strchr(delim, *str)) ++str;
    if (!*str) return next = NULL;
    // 找到下一分隔符
    next = str;
    while (*next && !strchr(delim, *next)) ++next;
    if (*next) *next++ = '\0';
    else next = NULL;
    return str;
}

警示:修改原字符串、內部靜態變量、非重入。多線程請用 strtok_r / strsep。

內存操作族:memcpy/memmove/memset/memcmp

void *memcpy(void *dest, const void *src, size_t n) {
    assert(dest && src);
    char *d = dest; const char *s = src;
    while (n--) *d++ = *s++;
    return dest;
}
void *memmove(void *dest, const void *src, size_t n) {
    assert(dest && src);
    char *d = dest; const char *s = src;
    if (d < s) while (n--) *d++ = *s++;           // 正向不重疊
    else { d += n; s += n; while (n--) *--d = *--s; } // 反向避免覆蓋
    return dest;
}
void *memset(void *s, int c, size_t n) {
    assert(s);
    unsigned char *p = s;
    while (n--) *p++ = (unsigned char)c;
    return s;
}

memmove 處理重疊是關鍵區別;memset 按字節填充,僅適合 0/-1/字符填充,不可用於整型數組初始化非字節值。

常見面試陷阱總結

陷阱正確認知
strcpy 不檢查長度調用者必須保證 dest 空間 ≥ strlen(src)+1
strncpy 不自動補 \0若 src 長度 ≥ n,dest 無結束符,需手動 dest[n]='\0'
strlen 返回 int返回 size_t,打印用 %zu
strcmp 直接減 char必須轉 unsigned char 再減,否則負數字符導致錯誤
memset(arr, 1, n) 初始化 int 數組每字節置 1,整數變 0x01010101 ≠ 1,嚴禁

結語

熟練掌握這些「輪子」的內部原理,不僅應付面試,更能在造新輪子時避開標準庫的歷史包袱與陷阱。建議親手敲一遍,體會指針遞增、空終止判斷、斷言防護的節奏。

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