代碼上下文
char s[81], *t, *f;
gets(s); // 讀入字符串 (注意: gets 不安全, 建議用 fgets)
t = f = s; // t, f 都指向字符串首地址
while (*t) t++; // 循環結束時, t 指向字符串結束符 '\0'
t--; // t 回退一步, 指向字符串最後一個有效字符
while (*t == '*') t--; // 從後向前跳過連續的 '*'
while (*f == '*') f++; // 從前向後跳過連續的 '*'
fun(s, f, t); // 處理去除首尾 '*' 後的子串
逐句解析
`while (*t) t++;`
- `*t` 解引用獲取當前字符。
- 在 C 中,字符 `'\\0'` (值 0) 為假,非零字符為真。
- 循環將 `t` 遞增,直到指向字符串結尾的 `'\0'` 為止。**循環結束後 `t` 指向 `'\0'`**。
`t--;`
- 將 `t` 向前移動一位,使其指向**字符串最後一個有效字符** (即 `'\0'` 之前的那個字符)。
`while (*t == '*') t--;`
- **從字符串末尾向前掃描**,只要當前字符是 `'*'`,就繼續向前移動 `t`。
- 循環結束時,`t` 指向**末尾連續 `'*'` 之前的第一個非 `'*'` 字符**,或者如果整串都是 `'*'`,會越界指向 `s[-1]` (邏輯漏洞,需加邊界判斷 `t >= s`)。
- 目的:定位 **有效內容的末尾邊界** (去除尾部 `*`)。
`while (*f == '*') f++;`
- **從字符串開頭向後掃描**,只要當前字符是 `'*'`,就繼續向後移動 `f`。
- 循環結束時,`f` 指向**開頭連續 `'*'` 之後的第一個非 `'*'` 字符**,或者指向 `'\0'` (全是 `*`)。
- 目的:定位 **有效內容的起始邊界** (去除頭部 `*`)。
整體功能
**去除字符串首尾連續的 `'*'` 字符**,將剩餘中間部分 (從 `f` 到 `t`,包含 `t`) 傳遞給 `fun` 處理。
例如:`s = "***hello**world***"` → `f` 指向 `h`,`t` 指向 `d` → `fun` 處理 `"hello**world"`。
潛在風險與改進
- `gets` 不安全:無緩衝區長度檢查,易導致棧溢出。**必須改用 `fgets(s, sizeof(s), stdin)` 並手動去除換行符**。
- 越界風險:若字符串全為 `'*'` 或空串,`t--` 和 `while` 會導致指針越過 `s[0]` 訪問非法內存。
修正:`while (t >= s && *t == '*') t--;` 及 `while (f <= t && *f == '*') f++;` (假設 `f` 初始 `= s`)。
- 參數傳遞:`fun(s, f, t)` 傳遞的是指針值,`fun` 內部可直接修改原數組內容。
修正版核心邏輯
fgets(s, sizeof(s), stdin);
s[strcspn(s, "\n")] = 0; // 去除 fgets 讀入的換行符
char *t = s, *f = s;
// 找尾部
while (*t) t++;
if (t > s) t--; // 非空串才回退
while (t >= f && *t == '*') t--; // 含邊界檢查
// 找頭部
while (f <= t && *f == '*') f++; // 含邊界檢查
if (f <= t) {
fun(s, f, t); // 有有效內容
} else {
// 全是 * 或空串
}