C语言中fgetc()函数失效问题:为何两段代码表现不同
问题分析与解决
你的第一段代码无法正常读取第一个字符的核心原因是:文件指针已经被移动到了文件末尾。
具体问题拆解
文件指针位置耗尽
在第一段代码的do-while循环中,你通过fgetc(fp)不断读取文件内容,直到遇到EOF(文件结束符)。此时文件内部的位置指针已经指向了文件的最后一个字节之后,后续再调用fgetc(fp)只会返回EOF,自然无法读到文件开头的1。char类型存储fgetc返回值的隐患fgetc的返回值是int类型,它会返回读取到的字符(转换为unsigned char后再转为int),或者返回EOF(一个在int范围内的负值)。如果用char存储返回值,当系统中char是有符号类型时,某些字符(比如ASCII值为0x80-0xFF的字符)会被错误识别为EOF,导致循环提前终止或者判断错误。缺少文件打开成功的检查
如果fopen调用失败(比如文件不存在、权限不足),fp会是NULL,后续对fp的操作会导致程序崩溃,必须添加检查:fp = fopen("a.txt", "r"); if (fp == NULL) { perror("Failed to open file"); return 1; }
修复方案
要实现统计数字个数后再读取第一个字符,有两种常见方法:
方法一:统计完成后重置文件指针
在循环结束后,调用rewind(fp)将文件指针重置到文件开头,或者用fseek(fp, 0, SEEK_SET):FILE* fp; char digit_char; int NUM=1; fp = fopen("a.txt", "r"); if (fp == NULL) { perror("Open file failed"); return 1; } int ch; // 改为int类型 do { ch = fgetc(fp); if (ch == ',') { NUM++; } } while (ch != EOF); rewind(fp); // 重置文件指针到开头 int* arr; arr = malloc(sizeof(int) * NUM); // C中无需强制转换malloc返回值 if (arr == NULL) { perror("Malloc failed"); fclose(fp); return 1; } digit_char = fgetc(fp); // 现在可以读到第一个字符'1' free(arr); fclose(fp);方法二:一次遍历完成两个操作
不需要两次遍历文件,第一次读取时同时记录第一个字符和统计逗号数量,效率更高:FILE* fp; char digit_char = 0; int NUM=1; fp = fopen("a.txt", "r"); if (fp == NULL) { perror("Open file failed"); return 1; } int ch; int first_read = 1; while ((ch = fgetc(fp)) != EOF) { if (first_read) { digit_char = ch; first_read = 0; } if (ch == ',') { NUM++; } } int* arr = malloc(sizeof(int) * NUM); if (arr == NULL) { perror("Malloc failed"); fclose(fp); return 1; } // 后续处理数组... free(arr); fclose(fp);
为什么第二段代码正常?
第二段代码没有执行任何移动文件指针的循环,打开文件后直接调用fgetc(fp),此时文件指针默认指向文件开头,自然能读到第一个字符1。
内容的提问来源于stack exchange,提问作者user18790043
相关产品推荐
相关产品推荐

