C語言標準輸入處理:多行讀取、strstr 過濾包含「ould」的行
從 `stdin` 逐行讀取,使用 `strstr` 過濾包含指定子串的行,是文本處理的基礎模式。本文提供健壯的 `getline` 實現、標準庫 `getline`/`fgets` 對比、緩衝區管理最佳實踐。
自定義 getline 實現 (教學用)
#define MAX_LINE 1000
// 讀取一行到 line,最多 limit 字元,返回讀取長度 (含 \n),EOF 返回 0
int my_getline(char *line, int limit) {
assert(line);
int i = 0;
int ch;
while (limit > 1 && (ch = getchar()) != EOF && ch != '\n') {
line[i++] = ch;
limit--;
}
if (ch == '\n') {
line[i++] = '\n';
}
line[i] = '\0';
return i;
}
主程式:過濾包含 "ould" 的行
int main() {
char line[MAX_LINE];
const char *target = "ould";
while (my_getline(line, MAX_LINE) > 0) {
if (my_strstr(line, target)) {
printf("%s", line); // line 已含 \n
}
}
return 0;
}
標準庫方案對比 (推薦實務使用)
| 函數 | 簽名 | 特點 | 適用場景 |
| fgets | `char *fgets(char *s, int n, FILE *stream)` | 固定緩衝區、保留 \n、標準 C | 行長度可預期、嵌入式 |
| getline | `ssize_t getline(char **lineptr, size_t *n, FILE *stream)` | **動態分配緩衝區**、自動擴容、POSIX | 行長度未知、現代 Linux/BSD |
| fgetln | `char *fgetln(FILE *stream, size_t *len)` | 返回內部緩衝區指標、無 \0 終止、BSD | 高性能、零拷貝、只讀 |
標準 getline 使用範例 (POSIX)
#define _GNU_SOURCE // 或 _POSIX_C_SOURCE 200809L
#include
#include
#include
int main() {
char *line = NULL;
size_t len = 0;
ssize_t read;
const char *target = "ould";
while ((read = getline(&line, &len, stdin)) != -1) {
if (strstr(line, target)) {
fwrite(line, 1, read, stdout); // 精確寫入 read 位元組
}
}
free(line); // getline 分配,需手動釋放
return 0;
}
關鍵細節:輸入結束判斷
- `getchar()` 返回 `EOF` (通常 -1) 表示檔案結束或錯誤
- `fgets` 返回 `NULL` 表示 EOF 或錯誤
- `getline` 返回 `-1` 表示 EOF 或錯誤
- **交互式終端**:`Ctrl+D` (Unix) / `Ctrl+Z` (Windows) 發送 EOF
進階:帶行號、大小寫不敏感過濾
// strcasestr: 大小寫不敏感版 (BSD/GNU 擴展)
// 手寫版:
char *my_strcasestr(const char *h, const char *n) {
if (!*n) return (char*)h;
for (; *h; h++) {
const char *p1 = h, *p2 = n;
while (*p1 && *p2 && toupper(*p1) == toupper(*p2)) { p1++; p2++; }
if (!*p2) return (char*)h;
}
return NULL;
}
// 帶行號輸出
int main() {
char *line = NULL; size_t len = 0; ssize_t read;
int line_no = 0;
while ((read = getline(&line, &len, stdin)) != -1) {
line_no++;
if (my_strcasestr(line, "ould")) {
printf("%4d: %s", line_no, line);
}
}
free(line);
return 0;
}
總結
**實務首選標準 `getline` (POSIX) 或 `fgets` (標準 C)**,自動處理緩衝區擴容、EOF、行結束符。教學理解 `my_getline` 邏輯:`getchar` 循環、緩衝區邊界保護、`\n` 保留、空終止。`strstr` 過濾模式可擴展為 `grep` 核心邏輯:正則表達式 → 有限自動機 → 高性能文本搜尋。
- 上一篇文章: C語言字串查找:strstr 朴素算法模擬實現與 KMP 優化方向
- 下一篇文章: C語言遞歸經典:字串反轉遞歸實現與棧幀分析
Copyright ©
程式碼之家 All Rights Reserved