这个程序为什么无法正确地将字符写入文件,并且会陷入无限循环?

huangapple go评论70阅读模式
英文:

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 &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

int main(void) {
    FILE *fp;
    int ch;

    fp = fopen(&quot;sample.txt&quot;, &quot;rw+&quot;);
    if (fp == NULL) {
        printf(&quot;Problem accessing the file!&quot;);
        exit(1);
    }

    while ((ch = fgetc(fp)) != EOF) {
        if (ch == &#39; &#39;) {
            fseek(fp, -1l, SEEK_CUR);
            fputc(&#39;_&#39;, 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.

huangapple
  • 本文由 发表于 2023年7月3日 16:09:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76602914.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定