在嵌入式開發或面試手寫代碼時,經常需要在不使用標準庫 string.h 的情況下實現字串操作。本文提供一個純 C 實現的 del_substr 函數,用於從原字串中刪除首次出現的指定子字串,並附帶完整註解與邏輯解析。
my_strlen 獲取子字串長度。\0。#include <stdio.h>
int del_substr(char *str, char const *substr);
int my_strlen(char const *str);
int main(void) {
char str[] = "abcdefgh";
char *substr1 = "efg";
char *substr2 = "fgr";
printf("%d\t%s\n", del_substr(str, substr1), str); // 找到並刪除,輸出 1 和 "abcdh"
printf("%d\t%s\n", del_substr(str, substr2), str); // 未找到,輸出 0 和 "abcdh"
return 0;
}
/**
* 刪除 str 中首次出現的 substr
* 成功返回 1,失敗返回 0
*/
int del_substr(char *str, char const *substr) {
int i = 0;
char *temp_str = str;
char const *temp_substr = substr;
int sub_len = my_strlen(substr);
// 1. 尋找子字串起始位置
while (1) {
if (*temp_str == *temp_substr) {
temp_substr++;
if (*temp_substr == '\0') break; // 完整匹配
} else {
temp_substr = substr; // 重置子字串指針
}
if (*temp_str == '\0') return 0; // 遍歷完主字串未找到
temp_str++;
}
// 2. 計算刪除起始位址
char *preDel = temp_str - (sub_len - 1);
// 3. 記憶體前移覆蓋
while (*(preDel + (i + sub_len)) != '\0') {
*(preDel + i) = *(preDel + (i + sub_len));
i++;
}
*(preDel + i) = '\0'; // 結尾補零
return 1;
}
// 簡易 strlen 實現
int my_strlen(char const *str) {
int len = 0;
while (*str++ != '\0') len++;
return len;
}
使用兩個指針 temp_str(遍歷主字串)和 temp_substr(遍歷子字串)。
temp_substr 後移繼續比對。temp_substr 重置指向子字串開頭,temp_str 繼續後移。temp_substr 走到 \0,表示完整匹配,跳出循環;此時 temp_str 指向匹配區間的最後一個字元。preDel = temp_str - (sub_len - 1) 將指針回退到匹配區間的第一個字元,這就是要被覆蓋的起始位置。
將 preDel + sub_len 之後的所有字元(含結尾 \0)依次向前搬移 sub_len 個位置,時間複雜度 O(n),空間複雜度 O(1)。
1 abcdh // "efg" 被刪除
0 abcdh // "fgr" 不存在,字串不變
strstr + memmove,標準庫經過優化且經過充分測試。這個練習不僅考驗指針操作功力,更能幫助理解字串在記憶體中的連續佈局與就地修改技巧,是 C 語言進階的必修課。