標準庫 <string.h> 提供了高優化的版本,但在以下場景手寫實現極有價值:
為避免與標準庫衝突,命名加前綴 my_,並盡量貼近標準語義:
// 返回字符串長度(不含結束符 '\0') size_t my_strlen(const char *str); // 將 src 複製到 dest,返回 dest char *my_strcpy(char *dest, const char *src); // 將 src 追加到 dest 末尾,返回 dest char *my_strcat(char *dest, const char *src); // 比較兩字符串字典序,返回 <0, 0, >0 int my_strcmp(const char *s1, const char *s2);
size_t my_strlen(const char *str) {
const char *p = str;
while (*p != '\0') p++;
return p - str; // 指針相減得元素個數
}
要點:用 const char* 保護輸入;指針遍歷比下標 str[i] 更高效(避免每次加法);返回 size_t 匹配標準庫。
char *my_strcpy(char *dest, const char *src) {
char *ret = dest; // 保存返回值
while ((*dest++ = *src++) != '\0') ; // 賦值+判斷+自增一氣呵成
return ret;
}
要點:*dest++ = *src++ 先賦值後自增;循環條件直接判斷賦值結果是否為 '\0',極其精簡;必須保證 dest 有足夠空間(標準庫行為,不做邊界檢查)。
char *my_strcat(char *dest, const char *src) {
char *ret = dest;
while (*dest != '\0') dest++; // 定位到 dest 末尾的 '\0'
while ((*dest++ = *src++) != '\0') ; // 接上 src
return ret;
}
要點:先找到 dest 結尾,再執行類似 strcpy 的複製;同樣不檢查緩衝區溢出。
int my_strcmp(const char *s1, const char *s2) {
while (*s1 && (*s1 == *s2)) {
s1++; s2++;
}
return (unsigned char)*s1 - (unsigned char)*s2; // 強轉 unsigned char 避免負值溢出
}
要點:同時遍歷,直到字符不同或任一結束;返回兩字符 ASCII 碼差;轉 unsigned char 確保 '\xFF' > '\x00' 邏輯正確(避免有符號 char 溢出導致邏輯反轉)。
// 安全複製:最多複製 n-1 個字符,保證以 '\0' 結尾
char *my_strncpy(char *dest, const char *src, size_t n) {
char *ret = dest;
while (n > 1 && (*dest++ = *src++) != '\0') n--;
if (n > 0) *dest = '\0'; // src 過短時補 '\0'
return ret;
}
// 安全追加:最多追加 n 個字符,保證以 '\0' 結尾
char *my_strncat(char *dest, const char *src, size_t n) {
char *ret = dest;
while (*dest) dest++;
while (n-- > 0 && (*dest++ = *src++) != '\0') ;
*dest = '\0';
return ret;
}
#include <stdio.h>
#include <string.h> // 對比標準庫
// 上述四個函數實現放這裡...
int main() {
char buf1[50] = "Hello";
char buf2[50] = "World";
char buf3[50] = "";
const char *s = "Hello";
printf("strlen: %zu vs %zu\n", my_strlen(s), strlen(s));
printf("strcpy: %s\n", my_strcpy(buf3, s));
printf("strcat: %s\n", my_strcat(buf1, buf2));
printf("strcmp: %d vs %d\n", my_strcmp("abc", "abd"), strcmp("abc", "abd"));
printf("strcmp: %d vs %d\n", my_strcmp("abc", "abc"), strcmp("abc", "abc"));
return 0;
}
| 函數 | 核心邏輯 | 關鍵細節 | 標準庫對應 |
|---|---|---|---|
| strlen | 指針遍歷至 '\0' | const 保護、指針相減、size_t 返回 | strlen |
| strcpy | 逐字符賦值含 '\0' | 返回 dest、無邊界檢查、指釖自增技巧 | strcpy |
| strcat | 定位 dest 末尾再 strcpy | 兩階段:找尾 + 接上 | strcat |
| strcmp | 同步遍歷比較差值 | unsigned char 轉換、字典序語義 | strcmp |
dest(鏈式調用會斷)。strcmp 直接用 *s1 - *s2 導致有符號溢出錯誤。strncpy/strncat/snprintf)。const 修飾只讀參數,啟用編譯器優化(-O2 下指針版常比下標版快)。