应用——统计文件字符数、单词数、行数

一、程序概述

1.1 功能描述

实现类似Linux wc命令的文件统计工具,能够统计:

  • 字符数(包括所有字符)

  • 单词数(基于空白字符分隔)

  • 行数(基于换行符\n计数)

1.2 程序结构

主函数 main()

处理命令行参数

调用 file_statistics()

打开文件 → 失败 → 错误处理

循环读取字符

统计行数、字符数、单词数

关闭文件

输出结果

1.3代码

cpp 复制代码
#include <stdio.h>
#include <string.h>

// 统计文件行数、字符数、单词数
int file_statistics(const char *filename)
{
    FILE *fp = fopen(filename, "r");
    if (!fp) {
        perror("打开文件失败");
        return -1;
    }
    
    int lines = 0, chars = 0, words = 0;
    int ch, prev_ch = ' ';
    
    while ((ch = fgetc(fp)) != EOF) {
        chars++;
        
        if (ch == '\n') {
            lines++;
        }
        
        // 简单的单词计数:当前字符是空格/换行,前一个字符不是空格/换行
        if ((ch == ' ' || ch == '\n' || ch == '\t') && 
            (prev_ch != ' ' && prev_ch != '\n' && prev_ch != '\t')) {
            words++;
        }
        
        prev_ch = ch;
    }
    
    // 处理最后一个单词
    if (prev_ch != ' ' && prev_ch != '\n' && prev_ch != '\t' && chars > 0) {
        words++;
    }
    
    printf("文件统计信息:\n");
    printf("  行数: %d\n", lines + (chars > 0 ? 1 : 0));
    printf("  字符数: %d\n", chars);
    printf("  单词数: %d\n", words);
    
    fclose(fp);
    return 0;
}

int main(int argc, char *argv[])
{
    if (argc != 2) {
        printf("用法: %s <文件名>\n", argv[0]);
        return -1;
    }
    
    return file_statistics(argv[1]);
}

二、核心算法分析

2.1 行数统计

// 简单直接的方法

if (ch == '\n') {

lines++;

}

特殊情况处理:

  • 最后一行没有换行符时,需要额外+1

  • 空文件应该显示0行

2.2 原始单词统计算法

// 边界检测算法

if ((ch == ' ' || ch == '\n' || ch == '\t') &&

(prev_ch != ' ' && prev_ch != '\n' && prev_ch != '\t')) {

words++;

}
算法原理:

文本: "Hello World!\n"

流程:

  • 当前字符 ' ',前一个字符 'o' → 检测到单词边界 → words=1

  • 当前字符 '\n',前一个字符 '!' → 检测到单词边界 → words=2

2.3 改进的单词统计算法

#include <ctype.h>

// 状态机算法

int in_word = 0;

while ((ch = fgetc(fp)) != EOF) {

if (isalnum(ch) || ch == '_' || ch == '-') {

in_word = 1; // 进入单词状态

} else if (isspace(ch) || ispunct(ch)) {

if (in_word) {

words++; // 离开单词状态

in_word = 0;

}

}

}

if (in_word) words++; // 处理最后一个单词

单词定义:

  • 字母、数字、下划线、连字符视为单词字符

  • 空白字符和标点符号作为单词分隔符

三、关键代码实现细节

3.1 文件打开与错误处理

FILE *fp = fopen(filename, "r");

if (!fp) {

perror("打开文件失败"); // 自动输出错误信息

return -1;

}

3.2 字符读取循环

int ch; // 必须用int,不能用char!

while ((ch = fgetc(fp)) != EOF) {

// 处理字符

}
为什么用int不用char?

  • fgetc()返回int类型,范围是0-255和EOF(-1)

  • 如果使用char,无法区分EOF和某些字符

3.3 处理最后一行

// 调整行数计数

printf("行数: %d\n", lines + (chars > 0 ? 1 : 0));
逻辑解释:

  • 情况1: "Hello\nWorld" → lines=1, chars>0 → 显示2行 ✓

  • 情况2: "" → lines=0, chars=0 → 显示0行 ✓

  • 情况3: "Hello" → lines=0, chars>0 → 显示1行 ✓

四、程序扩展功能

4.1 多文件支持实现

int total_lines = 0, total_chars = 0, total_words = 0;

for (int i = 1; i < argc; i++) {

int lines, chars, words;

if (process_file(argvi, &lines, &chars, &words) == 0) {

// 累加统计

total_lines += lines;

total_chars += chars;

total_words += words;

}

}

4.2 性能优化与计时

#include <time.h>

clock_t start = clock();

// ... 文件处理代码 ...

clock_t end = clock();

double time_used = ((double)(end - start)) / CLOCKS_PER_SEC;

printf("处理时间: %.3f秒\n", time_used);

4.3 格式化输出

// 对齐输出格式

printf("%-20s 行数: %6d 单词数: %6d 字符数: %6d\n",

filename, lines, words, chars);

// 输出示例:

// test.txt 行数: 3 单词数: 9 字符数: 48

五、学习要点总结

  • 文件操作基础:fopen、fgetc、fclose的正确使用

  • 错误处理:检查返回值,使用perror输出错误

  • 状态机思想:单词统计中的状态转换

  • 命令行参数:argc/argv的使用

  • 性能考虑:缓冲区、计时、大文件处理

  • 可扩展性:设计支持功能扩展的程序结构

相关推荐
一隅论数智19 小时前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
倒头就睡的小比特19 小时前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!19 小时前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
虎头金猫19 小时前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
猎头南楼20 小时前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
深圳老胡21 小时前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
旖旎夜光21 小时前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark21 小时前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her121 小时前
并查集-听课笔记
笔记·算法·并查集
码流子21 小时前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构