← C 语言 学习路线(共 8 章)

第 8 章 文件、命令行参数与综合实战

red wenzi · 2026-09-15 · 编程语言 · C 语言 · 📖 预计阅读 11 分钟 · 共 2 道练习
🎯 本章你会学到:把输入输出从屏幕扩展到文件和命令行,并完成一个统计小项目。建议边读边敲,每节练习先自己做,再展开答案对照。

程序真正的用武之地是处理文件和数据。这一章把前面所有内容串起来:函数、数组、指针、结构体,最后落到读写文件与命令行参数。

命令行参数

把命令行参数当数字相加
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {     /* argc 是参数个数,argv 是参数字符串数组 */
    long long sum = 0;
    for (int i = 1; i < argc; ++i) {   /* argv[0] 是程序名,从 1 开始 */
        sum += strtoll(argv[i], NULL, 10);
    }
    printf("argc=%d sum=%lld\n", argc, sum);
    return 0;
}
运行结果
argc=4 sum=6
运行示例
./add 1 2 3        # 输出 argc=4 sum=6

读写文件

写文件再读回来
#include <stdio.h>

int main(void) {
    const char *path = "numbers.txt";

    FILE *out = fopen(path, "w");      /* "w" 写模式,会清空原文件 */
    if (out == NULL) {
        return 1;
    }
    for (int i = 1; i <= 3; ++i) {
        fprintf(out, "%d\n", i * 10);
    }
    fclose(out);                       /* 必须关,否则内容可能还没落盘 */

    FILE *in = fopen(path, "r");
    if (in == NULL) {
        return 1;
    }
    int value = 0;
    long long sum = 0;
    while (fscanf(in, "%d", &value) == 1) {   /* 读到读不动为止 */
        sum += value;
    }
    fclose(in);

    printf("sum=%lld\n", sum);
    return 0;
}
运行结果
sum=60

运行后输出 sum=60(10+20+30)。文件的打开模式:r 只读、w 覆盖写、a 追加、rb/wb 二进制。

函数用途注意
fopen / fclose打开 / 关闭文件打开失败返回 NULL,一定要判断
fprintf / fscanf格式化读写用法跟 printf/scanf 一样,多一个 FILE*
fgets读一行保留换行符,适合逐行处理文本
fread / fwrite二进制读写需要给出元素大小与个数
feof是否到文件末尾要在读失败之后判断,不要用它当循环条件
⚠️ 易错点 fopen 之后忘了 fclose:写文件时数据可能还在缓冲区,程序非正常结束时内容会丢。
⚠️ 易错点 不要用 while (!feof(f)) 当循环条件——它会在读到末尾后再多循环一次,导致最后一条数据被重复处理。用 fscanf(...) == 1fgets(...) != NULL 作条件。

✍️ 本节练习

8.1必做统计行数与单词数

从标准输入读到文件结束,统计总行数和单词数(单词以空格、制表符或换行分隔)。

输入 若干行文字,读完会自动结束(Windows 下 Ctrl+Z 回车)。

输出 两行:lines=行数words=单词数

样例输入
hello world
foo
样例输出
lines=2
words=3

💡 提示 用 getchar() 一个字符一个字符读,遇到空白就把 in_word 置 0。

✅ 查看参考答案与解析
#include <stdio.h>

int main(void) {
    int lines = 0, words = 0;
    int c = 0, in_word = 0;
    while ((c = getchar()) != EOF) {
        if (c == '\n') {
            ++lines;
        }
        if (c == ' ' || c == '\n' || c == '\t' || c == '\r') {
            in_word = 0;
        } else if (!in_word) {
            ++words;
            in_word = 1;
        }
    }
    printf("lines=%d\n", lines);
    printf("words=%d\n", words);
    return 0;
}

解析 getchar 返回 int 而不是 char:这样才能同时容纳 0-255 的字符和 EOF(-1)。这是 C 里一个经典细节。

8.2挑战成绩汇总(综合练习)

读入若干行「名字 分数」,直到输入结束。输出人数、平均分(2 位小数)和最高分学生的名字。

输入 若干行「名字 分数」,读到输入结束。

输出 三行:count=avg=top=

样例输入
Ann 90
Bob 95
Cid 88
样例输出
count=3
avg=91.00
top=Bob

💡 提示 先读名字、再读分数(scanf("%31s %d", ...) == 2),读到读不动为止。

✅ 查看参考答案与解析
#include <stdio.h>
#include <string.h>

int main(void) {
    char name[32];
    char best_name[32] = "";
    int score = 0;
    int best = -1;
    int count = 0;
    long long sum = 0;

    while (scanf("%31s %d", name, &score) == 2) {
        ++count;
        sum += score;
        if (score > best) {
            best = score;
            strcpy(best_name, name);
        }
    }

    if (count == 0) {
        return 0;
    }
    printf("count=%d\n", count);
    printf("avg=%.2f\n", (double)sum / count);
    printf("top=%s\n", best_name);
    return 0;
}

解析 这道题把整条 C 线串起来了:字符串数组、循环、函数、strcpy、格式化输出。写完它,C 的基础部分就算过关。

📚 本文概念都在知识大全:

C 语言 · GCC 编译器 · 指针 · 动态内存 malloc/free · C 字符串 · 结构体 · 预处理 · 编译与链接