简体   繁体   中英

Why “scanf” works but fgets doesn't works in C?

Look here, those two programms should be equivalent in my opinion. But obviously they aren't, as the first programm works and the second doesn't. Can someone explain to me, why fgets() doesn't do the job?

// FIRST PROGRAM : WORKS FINE
#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *stream;
    char fileName[67];
    scanf("%s", fileName);
    printf("%s", fileName);
    stream = fopen(fileName, "r");
    char ch;
    if(stream){
        ch = fgetc(stream);
        while(!feof(stream)){
            putchar(ch);
            ch = fgetc(stream);
        }
        fclose(stream);
    }
}


// SECOND PROGRAM: DOES NOT WORK 

#include <stdio.h>
#include <stdlib.h>
int main()
{
    FILE *stream;
    char fileName[67];
    fgets(fileName, 67, stdin);
    printf("%s", fileName);
    stream = fopen(fileName, "r");
    char ch;
    if(stream){
        ch = fgetc(stream);
        while(!feof(stream)){
            putchar(ch);
            ch = fgetc(stream);
        }
        fclose(stream);
    }
}

I enter "test.txt" into the console both times and press enter then. Of course test.txt exists in the right directory

The reason is that fgets() retains the newline entered. You can verify it is there by altering your print statement to

printf("[%s]", filename);

when the ] will appear on the next line. You can remove the trailing newline like this

#include <string.h>

...

filename [ strcspn(filename, "\r\n") ] = 0;

The main problem you experienced is correctly solved by Weather Vane, but I want to point another problem with your code: the loops for reading and writing the contents of the file are incorrect. Testing the end of file with feof(stream) leads to incorrect behaviour most of the time. In your case, a read error from stream will cause your program to loop endlessly, writing 0xFF bytes to stdout .

There is a much simpler and idiomatic way to implement this loop:

if (stream) {
    int ch;

    while ((ch = fgetc(stream)) != EOF) {
        putchar(ch);
    }
    fclose(stream);
}

As you can see, it is simpler and correctly tests for EOF at the right time, when input fails. It stores the return value of fgetc() into an int variable capable of holding all possible return values from fgetc() . Using an int is necessary because comparing a char value to EOF either always fails if the char type is unsigned or potentially gives false positives if char is signed and has value '\\377' .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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