原始碼**錯誤地貼上了 memmove 實現**,完全偏離 `strcmp` 主題。本文提供正確的 `strcmp` 模擬實現、語義分析、邊界測試、與 `strncmp` 差異對比。
#includeint my_strcmp(const char *s1, const char *s2) { assert(s1 && s2); while (*s1 && *s1 == *s2) { s1++; s2++; } // 關鍵:轉為 unsigned char 比較,避免有號字元負值導致錯誤排序 return (unsigned char)*s1 - (unsigned char)*s2; }
int main() {
struct { const char *s1; const char *s2; int expected; } tests[] = {
{"abc", "abc", 0},
{"abc", "abd", -1}, // 'c' < 'd'
{"abd", "abc", 1}, // 'd' > 'c'
{"abc", "abcd", -1}, // 前綴較短
{"", "", 0},
{"a", "", 1},
{"\x80", "\x00", 1}, // 有號字元陷阱:\x80=-128 < \x00,但 unsigned \x80=128 > 0
};
for (size_t i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
int r = my_strcmp(tests[i].s1, tests[i].s2);
int sign = (r > 0) - (r < 0); // 正規化為 -1/0/1
printf("strcmp(\"%s\", \"%s\") = %d (expected %d) %s\n",
tests[i].s1, tests[i].s2, sign, tests[i].expected,
sign == tests[i].expected ? "✓" : "✗");
}
return 0;
}
strcmp("abc", "abc") = 0 (expected 0) ✓
strcmp("abc", "abd") = -1 (expected -1) ✓
strcmp("abd", "abc") = 1 (expected 1) ✓
strcmp("abc", "abcd") = -1 (expected -1) ✓
strcmp("", "") = 0 (expected 0) ✓
strcmp("a", "") = 1 (expected 1) ✓
strcmp("\x80", "\x00") = 1 (expected 1) ✓ // unsigned char 關鍵
// 錯誤:直接相減 (有號字元平台) return *s1 - *s2; // '\x80'(-128) - '\x00'(0) = -128 → 誤判 \x80 < \x00 // 正確:轉為 unsigned char return (unsigned char)*s1 - (unsigned char)*s2; // 128 - 0 = 128 → 正確 \x80 > \x00
C 標準要求 `strcmp` 按 **`unsigned char`** 比較,這在 `char` 預設為有號的平台 (x86, ARM) 極其關鍵。
| 特性 | strcmp | strncmp |
|---|---|---|
| 參數 | (s1, s2) | (s1, s2, n) |
| 比較長度 | 直到 \0 | 最多 n 字元 |
| 提前結束 | 遇到不同字元 | 遇到不同字元或達 n |
| 用途 | 完整字串比較 | 前綴比較、固定長度比較 |
int my_strncmp(const char *s1, const char *s2, size_t n) {
assert(s1 && s2);
while (n-- && *s1 && *s1 == *s2) {
s1++; s2++;
}
if (n == (size_t)-1) return 0; // n 原為 0,循環未執行
return (unsigned char)*s1 - (unsigned char)*s2;
}
`strcmp` 核心:**`unsigned char` 逐字元比較、遇差異或雙\0停止、返回差值**。原始碼貼錯 `memmove` 代碼屬於嚴重編輯錯誤。實務開發直接使用標準庫,編譯器內建優化 (向量化比較) 遠超手寫。面試必會:`unsigned char` 轉換必要性、返回值語義 (負/零/正)、與 `strncmp`/`memcmp` 差異。