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

C 語言字符串比較基礎教程:strcmp 用法、大小寫不敏感比較與常見陷阱

     編輯:關於C語言

C 語言無內建字符串類型,字符串以 **空字符 `\0` 結尾的 `char` 陣列** 表示。比較兩字符串是否相等,**不可用 `==` 比較指針地址**,必須使用 `` 提供的 `strcmp()` / `strncmp()` / `strcasecmp()`。本文系統講解標準用法、大小寫不敏感比較、安全長度限制與避坑指南。

核心 API 對比

函數簽名行為返回值適用場景
`strcmp``int strcmp(const char* s1, const char* s2)`逐字節比較,直到 `\0` 或差異0=相等, <0=s10=s1>s2標準精確比較
`strncmp``int strncmp(const char* s1, const char* s2, size_t n)`最多比較 n 字節同上防緩衝區溢出、比較前綴
`strcasecmp` (POSIX)`int strcasecmp(const char* s1, const char* s2)`忽略大小寫比較同上用戶輸入、配置項、不區分大小寫
`strncasecmp` (POSIX)`int strncasecmp(const char* s1, const char* s2, size_t n)`忽略大小寫 + 長度限制同上安全 + 不敏感

標準比較範例:年齡驗證邏輯


#include 
#include 
#include  // for toupper/tolower

int main() {
    int age;
    printf("請輸入用戶年齡: ");
    scanf("%d", &age);
    
    if (age >= 18) {
        printf("成年用戶,可繼續瀏覽\n");
    } else if (age >= 10) {
        char input[10];
        printf("青少年用戶,確認繼續? (Y/N): ");
        scanf("%9s", input); // 限制寬度防溢出
        
        // 方法 1: 標準 strcmp (區分大小寫)
        if (strcmp(input, "Y") == 0 || strcmp(input, "y") == 0) {
            printf("確認繼續\n");
        } else {
            printf("取消瀏覽\n");
        }
        
        // 方法 2: strcasecmp (POSIX,忽略大小寫,推薦)
        // if (strcasecmp(input, "Y") == 0) { ... }
    } else {
        printf("兒童用戶,不適合瀏覽\n");
    }
    return 0;
}

strcmp 返回值語義深度解析

  • **返回 0**:兩字符串**完全相等** (長度相同、每字節相同)
  • **返回 < 0**:`s1` 在字典序**小於** `s2` (第一個不同字節的 ASCII 值較小)
  • **返回 > 0**:`s1` 在字典序**大於** `s2`
  • **判斷相等唯一正確寫法**:`strcmp(s1, s2) == 0`

strcmp("abc", "abc")  == 0   // 相等
strcmp("abc", "abd")  < 0    // 'c' (99) < 'd' (100)
strcmp("abd", "abc")  > 0
strcmp("abc", "abcd") < 0    // '\0' (0) < 'd' (100)
strcmp("ABC", "abc")  < 0    // 'A' (65) < 'a' (97) — 區分大小寫!

大小寫不敏感比較:跨平台方案

方案一:POSIX `strcasecmp` (Linux/macOS/Unix)


#include  // 注意:非 string.h
if (strcasecmp(input, "YES") == 0) { /* ... */ }

方案二:Windows `_stricmp` / `strcmpi`


#ifdef _WIN32
#include 
#define strcasecmp _stricmp
#else
#include 
#endif
// 統一使用 strcasecmp

方案三:手寫通用版 (無依賴、教學用)


int my_strcasecmp(const char* s1, const char* s2) {
    while (*s1 && *s2) {
        char c1 = toupper((unsigned char)*s1);
        char c2 = toupper((unsigned char)*s2);
        if (c1 != c2) return c1 - c2;
        s1++; s2++;
    }
    return toupper((unsigned char)*s1) - toupper((unsigned char)*s2);
}

關鍵細節: `touper((unsigned char)c)` 避免負值 `char` 導致未定義行為。

安全編程:strncmp 防緩衝區溢出

若輸入來源不可信 (網絡、文件、用戶),**必須限制比較長度**:


// 只比較前 3 字符,防止異常長輸入導致越界讀取
if (strncmp(input, "CMD", 3) == 0) {
    // 處理命令...
}

// 配合 strnlen 確保字符串合法結尾
if (strnlen(input, MAX_LEN) < MAX_LEN && strncmp(input, "EXIT", 4) == 0) {
    // 安全比較
}

常見陷阱與避坑指南

錯誤代碼問題修正
`if (str1 == str2)`比較指針地址,非字符串內容`strcmp(str1, str2) == 0`
`if (strcmp(str1, str2))`相等返回 0 (假),不等返回非 0 (真) — 邏輯反轉`if (strcmp(str1, str2) == 0)` 相等分支
`scanf("%s", buf)` 無寬度限制緩衝區溢出漏洞`scanf("%99s", buf)` (留 1 位給 `\0`)
比較未以 `\0` 結尾的字符陣列越界讀取,未定義行為確保字符串正確結尾,或用 `strncmp` 限制長度
`strcmp` 用於二進制數據比較遇 `\0` 提前停止用 `memcmp(buf1, buf2, len)` 比較二進制塊
假設 `strcasecmp` 標準 C 庫函數Windows 無此函數,移植失敗宏映射 `_stricmp` 或手寫通用版

進階:字符串比較在排序中的應用 (qsort)


int cmp_str(const void* a, const void* b) {
    const char* s1 = *(const char**)a;
    const char* s2 = *(const char**)b;
    return strcmp(s1, s2); // 字典序排序
}

int cmp_str_case(const void* a, const void* b) {
    return strcasecmp(*(const char**)a, *(const char**)b); // 忽略大小寫排序
}

char* names[] = {"Bob", "alice", "Charlie", "ALICE"};
qsort(names, 4, sizeof(char*), cmp_str_case);
// 結果: alice, ALICE, Bob, Charlie

總結

  1. **永遠用 `strcmp` 系列比較字符串內容**,切勿用 `==` 比較指針
  2. **判斷相等寫 `== 0`**,非零即不等
  3. **用戶輸入/配置比較優先用大小寫不敏感版本** (`strcasecmp` / 宏映射 / 手寫)
  4. **不可信輸入必須用 `strncmp` 限制長度**,防越界
  5. **二進制數據用 `memcmp`**,非 `strcmp`

字符串比較是 C 語言基礎中**最易錯、漏洞最多**的環節之一。建立「指針≠字符串、相等==0、輸入必限長、大小寫按需」的肌肉記憶,能消除 90% 的字符串處理 Bug。

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