440
社区成员




统计文件单词数量代码如下:
#include <stdio.h> // 引入标准输入输出头文件
// 定义状态常量:OUT 表示在分隔符中,IN 表示在单词中
#define OUT 0
#define IN 1
#define INIT OUT // 初始状态设为 OUT
// 判断字符是否是分隔符(空格、换行、制表符、引号、加号、逗号、分号、句号)
int split(char c){
if (' ' == c || '\n' == c || '\t' == c || '\"' == c || '\'' == c || '+' == c || ',' == c || ';' == c || '.' ==c)
{
return 1; // 是分隔符,返回1
}else{
return 0; // 不是分隔符,返回0
}
}
// 统计文件中单词的数量
int Count_word(char *filename)
{
int state = INIT; // 当前状态初始化为 OUT
int word = 0; // 单词计数器初始化为 0
FILE *fp = fopen(filename,"r"); // 以只读模式打开文件
if (fp==NULL)
{
return -1; // 打开失败,返回错误码 -1
}
char c;
// 逐字符读取文件内容,直到遇到文件结束符 EOF
while ((c = fgetc(fp)) != EOF)
{
if(split(c)) // 如果是分隔符
{
state = OUT; // 切换为 OUT 状态
}else if (OUT == state){ // 如果当前字符不是分隔符,且之前是 OUT 状态
state = IN; // 状态切换为 IN,表示进入一个新单词
word++; // 单词数加一
}
}
return word; // 返回单词数量
}
// 主函数
int main(int argc, char *argv[])
{
if(argc <2){ // 如果没有提供文件名参数
return -1; // 返回错误码
}
// 调用 Count_word 统计文件中单词数量并打印
printf("word: %d\n", Count_word(argv[1]));
}
编辑好c语言文件之后,在Linux终端输入命令进行运行
gcc -o count count.c # 编译 count.c 为可执行文件 count
./count a.txt # 运行程序,并统计 a.txt 文件中的单词数
-o
是 gcc 的一个选项,意思是 “output”(输出)。count
是你希望编译后生成的可执行文件的名字。会在当前目录下生成一个名为 count
的可执行文件。如果你不加 -o count
,那么 GCC 默认会输出一个叫 a.out
的可执行文件。
一些学到的知识点:
int main(int argc, char *argv[])
argc
表示命令行参数的个数(argument count)
argv
是一个字符串数组(argument vector),里面每个元素是一个参数
argv[0]
是程序本身的名字
argv[1]
开始才是你运行时传的参数(例如你传一个文件名)
写法 | 含义 |
---|---|
char *argv[] | 字符串指针数组 |
char **argv | 指向字符串指针的指针,等价于上面 |
常用格式说明符汇总表:
格式符 | 说明 | 示例输出 |
---|---|---|
%d | 打印 十进制整数(int) | printf("%d", 10); → 10 |
%i | 同 %d ,也用于打印整数 | printf("%i", 10); → 10 |
%u | 打印 无符号整数(unsigned int) | printf("%u", 10); → 10 |
%f | 打印 浮点数(float, double),默认 6 位小数 | printf("%f", 3.14159); → 3.141590 |
%.2f | 打印浮点数,保留两位小数 | printf("%.2f", 3.14159); → 3.14 |
%c | 打印单个字符 | printf("%c", 'A'); → A |
%s | 打印字符串(char 数组) | printf("%s", "hello"); → hello |
%x | 打印整数的 十六进制(小写) | printf("%x", 255); → ff |
%X | 打印整数的 十六进制(大写) | printf("%X", 255); → FF |
%o | 打印整数的 八进制表示 | printf("%o", 10); → 12 |
%p | 打印 指针地址 | printf("%p", ptr); → 0x7ffee3a4e1c8 |
%% | 打印 % 本身 | printf("100%%"); → 100% |
FILE
是 C 语言标准库中定义的一个 结构体类型,用于表示一个打开的文件。
FILE *fp = fopen("hello.txt", "r");
如果当前目录下有一个文件叫 hello.txt
,就会成功打开,fp
就是这个文件的句柄,以后你就可以用 fgetc(fp)
、fgets(fp)
等函数读取里面的内容了。
打开模式还有很多种:
"r" | 只读 |
"w" | 只写(文件不存在就创建,存在就清空) |
"r+" | 读写 |
"w+" | 写读(会清空原内容) |
"a" | 追加 |
"a+" | 追加读写 |
fgetc
是 C 语言中用来从文件中按字符读取数据的函数。
int fgetc(FILE *stream);
作用:从文件指针 stream
所指向的文件中读取一个字符。
返回值:
成功:返回读取的字符(类型是 int
,虽然一般用 char
接收)。因为要能区分“正常字符”和特殊值 EOF
,而 char
是 8 位(0~255),不能表示 EOF
(通常是 -1),所以用 int
。
失败或到达文件结尾:返回 EOF
(End Of File)。这是 C 标准库里定义的一个常量,表示“文件的结尾”。
int fgetc(FILE *stream);
作用:从 stream
所指向的文件中读取一个字符。
HELLO WORLD
模拟程序一步步怎么读出两个单词
步骤 | 字符 c | 是否分隔符 | 当前状态 state | 操作 | 单词数 word |
---|---|---|---|---|---|
1 | 'H' | 否 | OUT | state → IN ,word++ | 1 |
2 | 'E' | 否 | IN | 无操作 | 1 |
3 | 'L' | 否 | IN | 无操作 | 1 |
4 | 'L' | 否 | IN | 无操作 | 1 |
5 | 'O' | 否 | IN | 无操作 | 1 |
6 | ' ' | 是 | IN | state → OUT | 1 |
7 | 'W' | 否 | OUT | state → IN ,word++ | 2 |
8 | 'O' | 否 | IN | 无操作 | 2 |
9 | 'R' | 否 | IN | 无操作 | 2 |
10 | 'L' | 否 | IN | 无操作 | 2 |
11 | 'D' | 否 | IN | 无操作 | 2 |
12 | EOF | - | - | 结束循环 | 2 |
统计单词及其出现的次数
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX_WORD_NUM 1000 // 最多能记录的单词数量
#define MAX_WORD_LEN 100 // 每个单词最大长度
// 定义结构体,用于保存一个单词和它的出现次数
struct CountWord {
char word[MAX_WORD_LEN]; // 单词内容
int count; // 出现次数
};
// 判断一个字符是否为分隔符(用于切分单词)
int is_split(char c) {
return c == ' ' || c == '\n' || c == '\t' ||
c == ',' || c == '.' || c == ';' || c == ':' || c == '!' || c == '?';
}
// 将字符串转换为全小写,避免大小写影响比较
void to_lower(char *s) {
for (int i = 0; s[i]; i++) {
s[i] = tolower(s[i]); // tolower 是将字符转换成小写
}
}
int main(int argc, char *argv[]) {
int word_nums = 0; // 当前记录的单词数量
struct CountWord word_list[MAX_WORD_NUM]; // 存储所有单词及其计数的数组
int idx = 0; // 当前正在拼接的单词长度
char buffer[MAX_WORD_LEN]; // 暂存当前正在读取的单词
// 如果命令行参数不足(没有给出文件名),返回错误
if (argc < 2) {
return -1;
}
// 打开指定文件
FILE *fp = fopen(argv[1], "r");
// 如果文件打开失败,返回错误
if (fp == NULL) {
return -1;
}
char c;
// 持续读取文件中的字符,直到文件结尾
while ((c = fgetc(fp)) != EOF) {
if (!is_split(c)) {
// 如果当前字符不是分隔符,就加到 buffer 中
if (idx < MAX_WORD_LEN - 1) {
buffer[idx++] = c;
}
} else {
// 如果遇到分隔符,且 buffer 中有内容,说明一个单词读完了
if (idx > 0) {
buffer[idx] = '\0'; // 补上字符串结束符
to_lower(buffer); // 转成小写,便于统一统计
int found = 0;
// 遍历已有的单词列表,看看是否已经记录过这个单词
for (int i = 0; i < word_nums; i++) {
if (strcmp(buffer, word_list[i].word) == 0) {
word_list[i].count++; // 找到就让计数加一
found = 1;
break; // 找到了就跳出循环,避免重复判断
}
}
// 如果没有找到这个单词,是新词
if (!found) {
if (word_nums < MAX_WORD_NUM) {
strcpy(word_list[word_nums].word, buffer); // 把新词加入数组
word_list[word_nums].count = 1; // 初始计数为1
word_nums++; // 单词总数加一
}
}
idx = 0; // 清空 buffer,准备读取下一个单词
}
}
}
// 输出所有统计到的单词及其出现次数
for (int i = 0; i < word_nums; i++) {
printf("%s: %d\n", word_list[i].word, word_list[i].count);
}
return 0;
}
break
是 跳出最近的一层循环
在 C 语言中,!
是逻辑“非”运算符,意思是“取反”:
如果 found == 0
,那 !found == 1
(即 true)
如果 found != 0
,那 !found == 0
(即 false)
strcmp
:字符串比较
int strcmp(const char *s1, const char *s2);
作用: 比较两个字符串 s1
和 s2
的内容。
返回值:
0
:如果两个字符串内容相同(注意:区分大小写);
< 0
:如果 s1
小于 s2
(按 ASCII 值逐字符比较);
> 0
:如果 s1
大于 s2
。
strcpy
:字符串拷贝
char *strcpy(char *dest, const char *src);
作用: 把 src
(源字符串)复制到 dest
(目标空间),包括 \0
结尾符。
函数 | 用途 | 示例 |
---|---|---|
strcmp | 比较两个字符串 | strcmp("a", "b") → -1 |
strcpy | 拷贝字符串内容 | strcpy(dest, "hello") |