Windows C编程中文本文件字符串覆写异常原因咨询
文件覆写时字符丢失的原因解析
问题场景
初始file.txt内容(行号非实际内容):
1 |My name is Yugal Bishram Don 2 |
实际内容为:My name is Yugal Bishram Don\n
以"r+"模式打开文件后执行以下代码:
FILE *fp=fopen("file.txt", "r+"); fscanf(fp,"%[^\n]",buffer1); // 对buffer1进行操作 rewind(fp); fprintf(fp,"My name is Aswin Don\n"); fclose(fp);
执行后文件内容变为:
1 |My name is Aswin Don 2 |am Don 3 |
疑问:写入的字符串共21个字符,按预期应覆写前21个字符,剩余ram Don\n应保留,但实际剩余am Don,原字符串中的'r'为何消失?
核心原因
1. fscanf的缓冲区溢出问题
你使用的fscanf(fp, "%[^\n]", buffer1)存在严重安全隐患:这个格式说明符不会检查目标缓冲区的大小,会一直读取直到换行符的所有字符。如果buffer1的长度小于原行内容的长度(原行"My name is Yugal Bishram Don"共28个字符),就会发生缓冲区溢出——超出buffer1的字符会覆盖相邻内存区域的数据。
而FILE *fp结构体的内存可能就在buffer1附近,溢出的内容会破坏fp内部记录的文件指针位置、缓冲区状态等关键信息,导致后续的rewind操作没有真正将文件指针重置到文件开头,而是偏移了1个字节的位置。
这种情况下,后续的fprintf会从偏移1的位置开始写入21个字符:
- 原文件偏移0的'M'被保留,偏移1-21被写入的内容覆盖,最终第一行呈现为"My name is Aswin Don";
- 原文件偏移21的'r'被写入的最后一个字符(换行符
\n)覆盖,后续的'a'开始的内容保留,于是第二行变成了'am Don'。
2. 读写切换的流同步问题
在C标准中,当文件流从读操作切换到写操作时(反之亦然),如果中间没有调用定位函数(fseek、rewind)或刷新函数(fflush),会导致未定义行为。虽然你调用了rewind,但如果之前的读操作导致输入缓冲区残留了未读取的字符(比如换行符\n),部分C库实现仍可能出现异常的指针定位行为,进一步加剧问题。
解决方法
- 避免缓冲区溢出:使用
fscanf时必须限制读取的字符数,比如fscanf(fp, "%27[^\n]", buffer1)(假设buffer1大小为28,留1个字节给终止符\0);或者更安全的做法是使用fgets读取整行,它会自动限制读取的字符数并保留换行符。 - 确保流同步:在读写切换前,调用
fflush(fp)刷新缓冲区,再执行rewind或fseek定位。示例代码:
FILE *fp=fopen("file.txt", "r+"); // 使用fgets更安全 fgets(buffer1, sizeof(buffer1), fp); // 对buffer1进行操作 fflush(fp); // 刷新缓冲区,同步流状态 rewind(fp); fprintf(fp,"My name is Aswin Don\n"); fclose(fp);
内容的提问来源于stack exchange,提问作者Mildred Gallagher
相关产品推荐
相关产品推荐

