Alon
Alon

Reputation: 464

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

Upvotes: 0

Views: 237

Answers (2)

chqrlie
chqrlie

Reputation: 145297

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'.

Upvotes: 1

Weather Vane
Weather Vane

Reputation: 34583

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;

Upvotes: 4

Related Questions