简体   繁体   English

'fread()','fwrite()'和'fseek()'的异常行为

[英]Unexpected behavior of 'fread()', 'fwrite()' and 'fseek()'

I wrote a simple C program, which takes a .txt file and replaces all spaces with hyphens. 我编写了一个简单的C程序,该程序使用.txt文件并将所有空格替换为连字符。 However, the program enters an infinite loop and the result is endless array of hyphens. 但是,程序进入无限循环,结果是连字符的数组无穷。

This is the input file: 这是输入文件:

a b c d e f

This is the file after the process crashes: 进程崩溃后的文件是:

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

I guess the reason in unexpected behavior of fread() , fwrite() and fseek() , or my misunderstanding of these functions. 我猜想fread()fwrite()fseek()意外行为的原因,或者是我对这些函数的误解。 This is my code: 这是我的代码:

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

What is the problem here? 这里有什么问题?

You have two problems: 您有两个问题:

1) You should be checking that fread returns the number of items you requested, eg that you get a 1 back. 1)您应该检查fread是否返回了您请求的项目数,例如您得到了1。

2) You should then be checking feof(fp), not comparing the character you read to EOF. 2)然后,您应该检查feof(fp),而不是将读取的字符与EOF进行比较。 This will tell you if your read returned less/no items because of EOF or some other reason. 这将告诉您您的阅读是否由于EOF或其他原因退回的物品少/少。

You have a few problems... 你有一些问题...

Check what types the standard C library functions return and what that return value means. 检查标准C库函数返回的类型以及该返回值的含义。 The std C library defines EOF as the integer -1. std C库将EOF定义为整数 -1。 Since the full character set is 256 characters and the type char can hold from 0 to 255 (256 diff values) it was necessary to make EOF an integer. 由于完整字符集为256个字符,并且char类型可以容纳0到255(256个diff值),因此必须使EOF为整数。

With all that bluster aside... You're also checking for EOF incorrectly. 抛开所有这些怒气...您还正在错误地检查EOF

The problems, spelled out: 问题阐明:

You should check the return value from fread 您应该检查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
    }
}

All of that said... It is very inefficient to read a character at a time on modern systems. 所有这些都说明了...在现代系统上一次读取一个字符效率很低。 Adapt your code to read a buffer full at a time and write the entire modified buffer out at once. 修改您的代码以一次读取一个完整的缓冲区,然后一次写出整个修改后的缓冲区。

The reason: 原因:

For files open for update (those which include a "+" sign), on which both input and output operations are allowed, the stream shall be flushed (fflush) or repositioned (fseek, fsetpos, rewind) before a reading operation that follows a writing operation. 对于允许进行输入和输出操作的要更新的打开文件(带有“ +”号的文件),应在进行后续的读取操作之前对流进行刷新(fflush)或重新定位(fseek,fsetpos,rewind)。写作操作。 The stream shall be repositioned (fseek, fsetpos, rewind) before a writing operation that follows a reading operation (whenever that operation did not reach the end-of-file). 在读取操作之后的写入操作之前(无论该操作未到达文件末尾),都应在重定位流之前(fseek,fsetpos,rewind)。

The solution: 解决方案:

You should add "fflush(fp);" 您应该添加“ fflush(fp);” after the fwrite line. 在fwrite行之后。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM