字串替換(將主串中所有 sub 替換為 rep)是 C 語言指針操作的綜合考驗:動態內存管理、子串匹配、結果構建、邊界條件。本文提供經典實現、逐行註解、測試用例與現代化改進建議。
char *replace(char *source, char *sub, char *rep) {
if (!source || !sub || !rep) return NULL;
if (*sub == '\0') return strdup(source); // 空子串直接複製
size_t len_sub = strlen(sub);
size_t len_rep = strlen(rep);
size_t len_src = strlen(source);
// 預估最大可能長度:全匹配且 rep > sub 時
size_t max_len = (len_rep > len_sub) ? (len_src / len_sub) * len_rep + 1 : len_src + 1;
char *result = malloc(max_len);
if (!result) return NULL;
char *pc1 = result; // 結果寫入指針
char *pc2, *pc3; // 掃描輔助指針
while (*source) {
pc2 = source; // 當前匹配起始
pc3 = sub; // 子串掃描
// 嘗試匹配 sub
while (*pc2 && *pc3 && *pc2 == *pc3) {
++pc2; ++pc3;
}
if (*pc3 == '\0') { // 完全匹配
pc3 = rep;
while (*pc3) *pc1++ = *pc3++; // 複製替換串
source = pc2; // source 跳過匹配區間
} else { // 不匹配
*pc1++ = *source++; // 複製單字元
}
}
*pc1 = '\0';
return result; // 調用者負責 free
}
source: a b b c c d f d c d b b d c d sub: d c d rep: 1 2 3 4 5 掃描到 source[6]='d' 時: pc2=source+6, pc3=sub 匹配 'd','c','d' 成功 → pc3 走到 '\0' → 複製 rep 到 result → source = pc2 (指向匹配後第一個字元 'b') 繼續掃描...
int main() {
char s1[] = "abbccdfdcdbbdcd";
char s2[] = "dcd";
char s3[] = "12345";
char *p = replace(s1, s2, s3);
printf("source=%s\nsub=%s\nreplace=%s\n", s1, s2, p);
free(p); // 必須釋放
return 0;
}
// 輸出: abbccf12345f12345bb12345
| 輸入 | 預期行為 | 代碼處理 |
|---|---|---|
| source=NULL | 返回 NULL | 開頭判空 |
| sub="" | 返回 source 副本 | *sub=='\0' 分支 |
| rep="" | 刪除所有 sub | 正常複製空串 |
| sub 不存在 | 返回 source 副本 | 無匹配分支逐字複製 |
| 重疊匹配 | 非重疊替換(標準行為) | source=pc2 跳過匹配區 |
const char *source, *sub, *rep,僅結果需分配。char* 無法區分「分配失敗」與「正常返回空串」,建議改為 int replace(const char*, const char*, const char*, char** out)。// 返回 0 成功,-1 分配失敗,-2 參數錯誤
int replace_ex(const char *source, const char *sub, const char *rep, char **out) {
if (!source || !sub || !rep || !out) return -2;
if (*sub == '\0') { *out = strdup(source); return *out ? 0 : -1; }
// ... 兩次掃描實現 ...
}
字串替換看似簡單,實則考驗動態內存規劃、指針狀態機、邊界條件覆蓋。掌握「雙指針匹配 + 結果緩衝區構建」模式,可舉一反三解決字串分割、轉義、模板渲染等眾多文本處理問題。生產代碼請採用改進版簽名,嚴格檢查返回碼並及時 free。