c语言 - "fread()"、'fwrite()'和'fseek()'的意外行为



我写了一个简单的C程序,它接受一个.txt文件并用连字符替换所有空格。但是,程序进入无限循环,结果是无穷无尽的连字符数组。

这是输入文件:

a b c d e f

这是进程崩溃后的文件:

a----------------------------------------------------------------------------
----------------------------------------... (continues thousands of times)... 

我猜fread()fwrite()fseek()的意外行为的原因,或者我对这些功能的误解。这是我的代码:

#include <stdlib.h>
#include <stdio.h>
#define MAXBUF 1024
int main(void) {
    char buf[MAXBUF];
    FILE *fp;
    char c;
    char hyph = '-';
    printf("Enter file name:n");
    fgets(buf, MAXBUF, stdin);
    sscanf(buf, "%sn", buf);   /* trick to replace 'n' with '' */
    if ((fp = fopen(buf, "r+")) == NULL) {
        perror("Error");
        return EXIT_FAILURE;
    }
    fread(&c, 1, 1, fp);
    while (c != EOF) {
        if (c == ' ') {
            fseek(fp, -1, SEEK_CUR); /* rewind file position indicator to the position of the ' ' */
            fwrite(&hyph, 1, 1, fp); /* write '-' instead */
        }
        fread(&c, 1, 1, fp); /* read next character */
    }
    fclose(fp);
    return EXIT_SUCCESS;
}

这里有什么问题?

您有两个问题:

1

)你应该检查fread是否返回你请求的项目数量,例如你得到一个1。

2)然后你应该检查feof(fp),而不是将你读到的字符与EOF进行比较。 这将告诉您读取是否由于EOF或其他原因返回较少/没有项目。

你有几个问题...

检查标准 C 库函数返回哪些类型以及该返回值的含义。std C 库将EOF定义为整数 -1。 由于完整字符集为 256 个字符,并且 char 类型可以容纳 0 到 255(256 个差异值),因此有必要将EOF设为整数。

撇开所有的咆哮不谈... 您也错误地检查了EOF

问题,详细说明:

您应该从fread中检查返回值

if( fread(&c, 1, 1, fp) != 1 )
{
    // Handle the error
}
// `EOF` is the integer -1.  It will not fit in a char.  So, your while loop becomes endless unless you get a -1 in the data stream
// The "correct" way to do what you want to do is using the stdlib function feof(fp)
while( !feof( fp ) )
{
    if (c == ' ')
    {
        // You should check the value returned by fseek for errors
        fseek(fp, -1, SEEK_CUR); /* rewind file position indicator to the position of the ' ' */
        // You should check the value returned by fwrite for errors
        fwrite(&hyph, 1, 1, fp); /* write '-' instead */
    }
    if( fread(&c, 1, 1, fp) != 1 )
    {
        // Handle the error
    }
}

都说了... 在现代系统上一次读取一个字符的效率非常低。 调整代码以一次读取一个已满的缓冲区,并一次写出整个修改后的缓冲区。

原因:

对于打开进行更新的文件(包含"+"号的文件),允许输入和输出操作,在写入操作之后的读取操作之前,应刷新(fflush)或重新定位流(fseek,fsetpos,rewind)。流应在读取操作之后的写入操作之前重新定位(fseek、fsetpos、rewind)(只要该操作未到达文件末尾)。

解决方案:

您应该在 fwrite 行后添加 "fflush(fp);"。

最新更新