英文:
Why does this program fail to write the character in the file properly and instead get stuck in an infinite loop?
问题
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
char ch;
fp = fopen("sample.txt", "r+");
if (fp == NULL) {
printf("无法访问文件!");
exit(1);
}
while ((ch = fgetc(fp)) != EOF) {
if (ch == ' ') {
fseek(fp, -1l, SEEK_CUR);
fputc('_', fp);
fseek(fp, 0, SEEK_CUR);
}
}
fclose(fp);
return 0;
}
英文:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *fp;
char ch;
fp = fopen("sample.txt", "r+");
if (fp == NULL) {
printf("Problem accessing the file!");
exit(1);
}
while ((ch = fgetc(fp)) != EOF) {
if (ch == ' ') {
fseek(fp, -1l, SEEK_CUR);
fputc('_', fp);
}
}
fclose(fp);
return 0;
}
In this program, I wanted the all the white-space characters in the opened file to be replaced with underscore characters. But this program is behaving in a very unexpected manner and getting stuck in an infinite loop. How do I make it work properly?
I tried to flush the stream fp
on each iteration of the while loop but still it doesn't give the intended output.
答案1
得分: 5
ch
必须定义为类型 int
,以容纳由 fgetc()
读取的所有字节值和 EOF
宏的特殊负值。
使用 char
使得在您的平台上无法测试 EOF
,因为 char
类型似乎是无符号的,因此当存储到 ch
中时,EOF
的值被转换为正值 255
,与测试中的 EOF
不同。
此外,在从流中读取切换到写入之前,您必须发出对 fseek()
或 rewind()
的调用,这一点您已经做到了,但在切换回读取之前也需要这样做,但您没有这样做。
最后,您应该以二进制方式打开文件,以便 fseek
能够正确地处理诸如 -1
之类的绝对数字。
以下是修改后的版本:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
int ch;
fp = fopen("sample.txt", "rb+");
if (fp == NULL) {
printf("Problem accessing the file!");
exit(1);
}
while ((ch = fgetc(fp)) != EOF) {
if (ch == ' ') {
fseek(fp, -1L, SEEK_CUR);
fputc('_', fp);
fseek(fp, 0L, SEEK_CUR);
}
}
fclose(fp);
return 0;
}
英文:
ch
must be defined with type int
to accommodate all byte values read by fgetc()
and the special negative value of the EOF
macro.
Using char
makes it impossible to test EOF
on your platform because type char
seems to be unsigned, hence the value EOF
is converted to a positive value 255
when stored into ch
, which compares different from EOF
in the test.
Furthermore, you must issue a call to fseek()
or rewind()
before switching from reading from the stream to writing to it, which you do, but also to switch back to reading, which you don't.
Finally, you should open the file as binary for fseek
to operate correctly with absolute numbers such as -1
.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
int ch;
fp = fopen("sample.txt", "rw+");
if (fp == NULL) {
printf("Problem accessing the file!");
exit(1);
}
while ((ch = fgetc(fp)) != EOF) {
if (ch == ' ') {
fseek(fp, -1l, SEEK_CUR);
fputc('_', fp);
fseek(fp, 0L, SEEK_CUR);
}
}
fclose(fp);
return 0;
}
答案2
得分: 0
有几个错误,但它们都与这个声明有关:
...
char ch;
...
while ((ch = fgetc(fp)) != EOF) {
...
函数 fgetc()
必须 使用一个 int
变量,因为它将输入字节作为介于 0 到 255 之间的数字返回(全部为正数),并返回一个额外的值(EOF
,通常定义为 -1),这不能由 char
处理。
第二件事是,在您的计算机中,char
可能被定义为 unsigned
,因此您在 ch
中得到一个介于 0 到 255 之间的数字(通过未定义行为将 -1 转换为其中一个值,这是您在声明中发生的错误)。
第三件事是,将在范围 (0..255) 内的数字与 -1 进行比较,会导致左操作数被转换为介于 0 到 255 之间的整数,这将使得 while
测试始终为真,从而使 while
循环永远运行下去。
fgetc()
是一个返回 257 个值的函数,而不是 256 个。 其中一个用于表示所有可能的字节值,另外一个用于指示 EOF
(这实际上不是一个字符,而是表示文件中发生了什么的指示器,这是一个常见的错误,认为有一个文件结束字符,实际上并没有。)。
英文:
There are several errors, but all of them are related to this declaration:
...
char ch;
...
while ((ch = fgetc(fp)) != EOF) {
...
the function fgetc()
requires to use an int
variable, as it returns the input byte as a number between 0 and 255 (all of them positive) and an extra value (EOF
, normally defined as -1) this cannot be handled by a char
.
The second thing is that, char
in your computer, is probably defined as unsigned
so you get in ch
a number between 0 and 255 (with -1 converted into one of these values by an Undefined Behavior you have incurred in your declaration)
The third thing is that comparing a number in the range (0..255) against -1 makes the left operand to be converted into an integer between 0 and 255, with results in the while
test to be true always, this makes the while
loop to run forever.
fgetc()
is a function that returns 257 values, not 256. The ones used for all the possible byte values, plus one extra for indicating EOF
(and this is not a charater, indeed, it is an indicator of what happened in the file, it is a common mistake considering that there's an end of file character, which there's not.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论