“fread()”,“fwrite()”和“fseek()”的意外行为

时间:2012-06-02 00:04:25

标签: c stdio

我编写了一个简单的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, "%s\n", buf);   /* trick to replace '\n' with '\0' */

    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;
}

这里有什么问题?

3 个答案:

答案 0 :(得分:2)

你有两个问题:

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

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

答案 1 :(得分:2)

你有一些问题......

检查标准C库函数返回的类型以及返回值的含义。 std C库将EOF定义为整数 -1。由于完整字符集为256个字符且char类型可以容纳0到255(256个diff值),因此必须使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
    }
}

所有这些都说......在现代系统上一次读一个角色是非常低效的。调整代码以一次读取一个缓冲区,并立即写出整个修改过的缓冲区。

答案 2 :(得分:0)

原因:

对于打开更新的文件(包含“+”符号的文件),允许进行输入和输出操作,在读取操作之前,应刷新流(fflush)或重新定位(fseek,fsetpos,rewind)这是在写作操作之后。在读取操作之后的写入操作(每当操作没有到达文件结尾)时,流应重新定位(fseek,fsetpos,rewind)。

解决方案:

你应该添加“fflush(fp);”在fwrite行之后。