文件 data.txt 內容如下 (空格/Tab 分隔):
100 Alice 85.5 200 Bob 92.0 300 Charlie 78.5
目標:讀取每行第一個整數 (100, 200, 300)。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE 256
int main() {
FILE *fp = fopen("data.txt", "r");
if (!fp) { perror("開啟失敗"); return 1; }
char line[MAX_LINE];
int first_num;
while (fgets(line, sizeof(line), fp)) {
// 移除末尾換行符 (可選)
line[strcspn(line, "\n")] = '\0';
// 解析第一個整數,%*s 跳過後續字串
if (sscanf(line, "%d", &first_num) == 1) {
printf("第一欄: %d\n", first_num);
} else {
fprintf(stderr, "解析失敗: %s\n", line);
}
}
fclose(fp);
return 0;
}
優點:逐行讀取,緩衝區可控;sscanf 解析靈活,可輕鬆擴展讀取第 2、3 欄;自動處理行尾換行符。
while (fscanf(fp, "%d", &first_num) == 1) {
printf("%d\n", first_num);
// 必須手動跳過行尾剩餘內容,否則下次掃描會卡住
fscanf(fp, "%*[^\n]"); // 跳過非換行字符
fgetc(fp); // 吃掉換行符
}
缺點:格式不匹配易導致無限迴圈;需手動處理換行符;不適合含空行或異常行的文件。
int ch, num = 0, sign = 1, in_num = 0;
while ((ch = fgetc(fp)) != EOF) {
if (ch >= '0' && ch <= '9') {
num = num * 10 + (ch - '0');
in_num = 1;
} else if (in_num) { // 非數字且剛讀完數字
printf("%d\n", sign * num);
num = 0; sign = 1; in_num = 0;
} else if (ch == '-' && !in_num) {
sign = -1;
}
if (ch == '\n') { // 行尾重置
if (in_num) printf("%d\n", sign * num);
num = 0; sign = 1; in_num = 0;
}
}
| 方法 | 健壯性 | 擴展性 | 適用場景 |
|---|---|---|---|
| fgets + sscanf | ★★★★★ | ★★★★★ | 通用文本處理、CSV、日誌分析 |
| fscanf | ★★☆☆☆ | ★★☆☆☆ | 格式極其固定、無異常行的簡單文件 |
| 逐字符 | ★★★★☆ | ★★★☆☆ | 嵌入式無標準庫、極特殊格式、教學 |
// POSIX 專用 getline (Linux/macOS)
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, fp)) != -1) {
// 使用 line...
}
free(line);
**首選 fgets + sscanf**。它清晰分離「讀取行」與「解析行」,邊界檢查完善,易於維護擴展。記得檢查 fopen 回傳值與 sscanf 掃描匹配數。