C语言基于文本文件实现持久化计数器的代码问题排查
代码问题诊断
你的代码存在几个核心错误,直接导致计数无法持久累加:
- 首要错误是
fopen打开模式选择错误:你使用的"w+"模式会在打开文件时直接将文件截断为0字节的空文件,无论之前文件里存储了什么计数内容,打开的瞬间就被清空了,后续你检查文件大小永远得到0,自然每次都只会写入初始值1,完全读不到历史数据。 - 未给文件名分配合法的存储缓冲区:你直接对
FILENAME执行sprintf写入,如果FILENAME是未初始化的指针、或者缓冲区长度不足,会触发内存溢出,轻则文件名乱码,重则程序直接崩溃。 - 文件流读写切换不符合C标准规范:C语言规定对同一个文件流交替执行读、写操作时,必须插入
fseek/rewind/fflush这类流定位/刷新操作,否则会出现写入位置错位、内容混乱的未定义行为。 - 未校验读取操作的有效性:你直接使用
fscanf的读取结果,但没有判断是否读取成功,如果文件为空、内容不是合法整数,Count会是未初始化的随机值,累加后的结果完全不可控。 - 没有处理旧内容残留:如果你从文件头开始写入新值,但新值的长度比旧值短,旧值多出来的尾部字符会残留在文件中,下次读取会得到错误的数值。
修正实现
核心思路是调整文件打开逻辑:先以不破坏原内容的"r+"模式尝试打开已有文件,读取现有计数累加;如果文件不存在(打开失败),再新建文件写入初始值1。同时补全缓冲区定义、操作校验、残留清理逻辑。
可直接运行的修正代码:
#include <stdio.h> // 类Unix系统使用ftruncate需要引入该头文件,Windows平台可替换为<io.h>并将ftruncate替换为_chsize #include <unistd.h> int main() { int Num; // 修正原代码的拼写问题,Entera补空格为Enter a printf("Enter a number:\t"); scanf("%d", &Num); // 预分配128字节的文件名缓冲区,足够存储任意int范围数字拼接后的文件名 char FILENAME[128]; sprintf(FILENAME, "counter.%d.txt", Num); FILE *counter; int Count, NewCount; // 第一步:尝试打开已存在的计数文件,r+模式不会清空原内容 counter = fopen(FILENAME, "r+"); if (counter != NULL) { // 尝试读取文件中存储的合法整数 int read_res = fscanf(counter, "%d", &Count); if (read_res == 1) { NewCount = Count + 1; } else { // 文件内容损坏/为空,重置为初始值 NewCount = 1; } // 读切换为写前,定位回文件开头 rewind(counter); fprintf(counter, "%d", NewCount); // 刷新流、截断文件到当前写入位置,清除旧内容残留 fflush(counter); ftruncate(fileno(counter), ftell(counter)); fclose(counter); } else { // 文件不存在,新建文件写入初始值1 counter = fopen(FILENAME, "w"); if (counter == NULL) { perror("Failed to create counter file"); return 1; } fprintf(counter, "1"); fclose(counter); } // 验证:读取最终存储的计数值打印 counter = fopen(FILENAME, "r"); if (counter != NULL) { fscanf(counter, "%d", &Count); printf("Current count: %d\n", Count); fclose(counter); } return 0; }
关键注意点
- 牢记C语言文件打开模式的核心差异:带
w的模式打开时都会截断/新建空文件,适合创建新文件、覆盖写入场景;带r的模式要求文件必须存在,不会清空原内容,适合读、修改已有文件的场景;带+代表同时支持读写。 - 所有文件IO操作都要校验返回值,不要默认操作一定成功,否则遇到权限不足、文件损坏、磁盘满等异常场景时程序会出现不可预期的错误。
- 覆盖写入文件内容时,如果新内容长度和旧内容不一致,一定要在写入后截断文件,避免旧内容残留。
内容的提问来源于stack exchange,提问作者Huwee
相关产品推荐
相关产品推荐

