文件内容ASCII码偏移修改异常:无限循环与未定义行为问题排查
解决文件字符偏移操作的无限循环与未定义行为问题
咱们来一步步拆解你遇到的问题,以及对应的解决方案:
问题1:初始代码的无限循环
你的第一版代码有两个致命问题:
- 未初始化变量:
char c;没有被赋值就直接传入fputc,这会写入随机的垃圾字符,属于未定义行为。 "a+"模式的行为+循环逻辑错误:"a+"模式下所有写操作都会强制追加到文件末尾,而你的while ((fgetc(fp)) != EOF)循环每次读一个字符后,就追加一个字符,导致文件持续变长。更糟的是,你没有把读到的字符存入变量,循环只是不断读取新追加的垃圾字符,永远碰不到EOF,直接陷入无限循环。
问题2:修改后代码的未定义行为
你把char c改成int c并赋值是正确的(因为fgetc返回int类型,包含EOF的-1,用char存储可能导致EOF判断失效),但还是触发了UB,原因有两个:
- 运算符优先级错误:
(c+5%127)会被C编译器解析为c + (5%127),也就是等价于c+5,完全没执行你想要的取模127操作。正确写法是(c + 5) % 127。 - 读写切换未定位:C标准明确规定,对同一个文件流进行读和写操作时,如果中间没有调用
fseek、fsetpos或rewind,行为是未定义的。你读完字符直接写,没有修正指针位置,导致写入位置混乱。
解决方案1:修改原文件的每个字符(替换模式)
如果你想把原文件的每个字符都替换成偏移后的结果,应该用"r+"模式(读写模式,文件必须存在),并在每次读写之间手动定位指针:
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { char filename[100]; printf("Provide name of file:\n"); scanf("%s", filename); FILE *fp = fopen(filename, "r+"); if (fp == NULL) { fprintf(stderr, "Error opening %s file!\n", filename); exit(EXIT_FAILURE); } int c; long current_pos; while ((c = fgetc(fp)) != EOF) { // 记录读完当前字符后的指针位置 current_pos = ftell(fp); // 移回当前字符的起始位置,准备覆盖写入 fseek(fp, current_pos - 1, SEEK_SET); // 计算正确的偏移值:先加5再取模127 int modified_char = (c + 5) % 127; // 写入修改后的字符 fputc(modified_char, fp); // 刷新缓冲区,确保写入生效,再移到下一个字符位置 fflush(fp); fseek(fp, current_pos, SEEK_SET); } fclose(fp); return EXIT_SUCCESS; }
解决方案2:测试"a+"的追加效果(追加模式)
如果你只是想验证"a+"的追加行为,即读取原文件内容,把每个字符偏移后追加到文件末尾,不需要修改原内容,代码可以这样写:
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { char filename[100]; printf("Provide name of file:\n"); scanf("%s", filename); FILE *fp = fopen(filename, "a+"); if (fp == NULL) { fprintf(stderr, "Error opening %s file!\n", filename); exit(EXIT_FAILURE); } // 先将指针移到文件开头,读取原内容 fseek(fp, 0, SEEK_SET); int c; while ((c = fgetc(fp)) != EOF) { int modified_char = (c + 5) % 127; // "a+"模式下写操作会自动跳到文件末尾,直接写入即可 fputc(modified_char, fp); } fclose(fp); return EXIT_SUCCESS; }
这个版本不会无限循环,因为读完原文件的所有内容后,fgetc会返回EOF,循环正常退出,不会读取刚追加的内容。
内容的提问来源于stack exchange,提问作者helpme_1
相关产品推荐
相关产品推荐

