文件字符计数函数异常及fscanf使用问题咨询
一、countchars函数统计字符数异常的原因:文件被提前关闭
你提到在main函数中已经打开了文件,调用countchars前文件处于打开状态,但在countchars末尾关闭了文件——这就是核心问题!
文件指针FILE *p是按值传递给countchars函数的,但它指向的是同一个底层文件资源。当你在countchars里调用fclose(p)后,这个文件资源就被系统释放了,main函数里原来的文件指针会直接变成无效的悬空指针。如果后续main还要对这个文件做操作(比如再次读取、写入),会触发未定义行为,甚至直接崩溃;更关键的是,如果countchars被多次调用,第二次传入的已经是关闭的指针,自然无法正确统计字符数。
修复方案:
把文件的打开和关闭逻辑统一放在调用方(也就是main函数里),countchars只负责读取统计,不要处理文件的关闭:
void countchars(FILE *p){ char ch; int countc=0; for(;(fscanf(p,"%c",&ch)!=EOF);countc++); printf("%d",countc); // 移除这里的fclose(p); } // main函数示例 int main(){ FILE *fp = fopen("test.txt", "r"); if(fp == NULL){ perror("Failed to open file"); exit(EXIT_FAILURE); } countchars(fp); fclose(fp); // 在这里统一关闭文件 return 0; }
二、为什么不带!=EOF的fscanf仅读取最后一个单词/字符?
要搞懂这个问题,得先明确fscanf的返回值规则:
fscanf会返回成功读取并赋值的项数;- 当到达文件末尾(EOF)或者发生读取错误时,返回
EOF。
如果你的代码里没有用!=EOF作为循环判断条件,会出现两种典型情况:
1. 无循环,仅单次调用fscanf
比如:
char ch; fscanf(p,"%c",&ch);
这时候fscanf只会执行一次,读取文件中的第一个字符(如果用%s则读取第一个单词)。你感觉是“最后一个”,大概率是之前已经读取过文件,文件指针已经移动到末尾了。
2. 有循环但不判断返回值
比如错误写法:
char ch; while(1){ fscanf(p,"%c",&ch); // 处理ch }
当文件指针到达EOF后,fscanf会返回EOF,但循环不会停止。此时ch的值会保持最后一次成功读取的字符,后续每次循环都不会更新ch,看起来就像是一直在读取“最后一个字符”。
而你代码里的写法(把fscanf的返回值和EOF比较)是正确的:当读取失败(到达末尾)时终止循环,这样就能正确遍历所有字符。
另外补充一点:用fscanf("%c", &ch)统计字符时,会读取包括换行符、空格在内的所有字符,如果你只想统计可见字符,可能需要额外添加判断逻辑,但这是另一个范畴的问题了。
内容的提问来源于stack exchange,提问作者Tyler

