經典 C 語言面試題:將字串 ******ab***cdf**rty******* 中間的 * 移除,保留首尾星號,結果為 ******abcdfrty*******。本文逐行解析指針操作邏輯,釐清 q、h、p、a[i] 的具體含義。
f 指向首個非星號字元,t 指向尾部最後一個非星號字元[a, f):完整複製(含前導星號)[f, t]:跳過星號,只複製非星號字元(t, 末尾]:完整複製(含尾隨星號)a 上操作,最後補 \0| 變量 | 含義 | 初始化/移動 |
|---|---|---|
a | 原字串陣列(也是輸出緩衝區) | 主函數傳入 s |
f | 首個非 * 字元位址 | while(*f=='*') f++; |
t | 尾部最後一個非 * 字元位址 | while(*t) t++; t--; while(*t=='*') t--; |
q | 遍歷游標 | 初始 q=a,逐步後移 |
h | 中段起始邊界 | 主函數傳入 f |
p | 中段結束邊界 | 主函數傳入 t |
i | 寫入索引 | 從 0 遞增 |
[a, h)char *q = a; // q 指向字串開頭
int i = 0;
while (q < h) { // 直到 q 達到第一個非星號字元
a[i] = *q; // 逐字元複製
i++; q++;
}
效果:******ab***cdf**rty******* → 前 6 個 * + ab 被複製到 a[0..7],i=8,q 指向第一個中間 *。
[h, p]
while (q < p) { // 遍歷中段
if (*q != '*') { // 非星號才複製
a[i] = *q;
i++;
}
q++; // q 無條件後移
}
效果:跳過所有中間 *,只保留 cdfrty,i 遞增至 14,q 指向尾部星號區起始。
(p, 末尾]
while (*q) { // *q 非 '\0' 繼續
a[i] = *q;
i++; q++;
}
a[i] = '\0'; // 結束字串
關鍵點:q 當前指向尾部第一個 *,*q 為字元值而非位址。迴圈複製直到遇到 \0。
char *a 怎麼能用 a[i]?a[i] 等價 *(a+i)。while(*q) 何時結束?q 指向字串結束符 \0,*q == 0 為假,迴圈結束。h、p 是怎麼傳進來的?f、t 計算好邊界後呼叫 fun(s, f, t),對應形參 a, h, p。
void remove_middle_stars(char *str) {
char *left = str;
while (*left == '*') left++; // 首非星號
char *right = str + strlen(str) - 1;
while (right > left && *right == '*') right--; // 尾非星號
char *read = left, *write = left;
while (read <= right) {
if (*read != '*') *write++ = *read; // 只寫非星號
read++;
}
// 複製尾部星號
while (*read) *write++ = *read++;
*write = '\0';
}
此題核心考察指針邊界計算與原地修改技巧。理解 f/t 如何框定「中間區域」,以及三段式複製的指針推進邏輯,即可掌握 C 字串處理的精髓。