tags:

views:

261

answers:

7

hi I am new to C. I am just trying to read each character of the file and print it out but when the file finishes reading, but I am getting a bunch of ? after it finishes reading. How do I fix it?

#include <stdio.h>

int main(void){
    FILE *fr;            /* declare the file pointer */

    fr = fopen ("some.txt", "r");  /* open the file for reading */
        /* elapsed.dta is the name of the file */
        /* "rt" means open the file for reading text */
    char c;
    while((c = getc(fr)) != NULL)
    {
        printf("%c", c);
    }
    fclose(fr);  /* close the file prior to exiting the routine */
    /*of main*/ 


    return 0;
}
A: 

fgetc() returns EOF on end-of-file, not NULL.

Ignacio Vazquez-Abrams
A: 

Replace "NULL" with "EOF".

shinkou
+2  A: 

If unsuccessful, fgetc() returns EOF.

int c;
while ((c = getc(fr)) != EOF) 
{ 
    printf("%c", c); 
}
Mitch Wheat
c needs to be declared as an int as well.
Emerick Rogul
@Emerick Rogul: do you want that comment under the original question?
Mitch Wheat
+1  A: 

Change this

char c;
while((c = getc(fr)) != NULL)
{
    printf("%c", c);
}

to

char c;
int charAsInt;
while((charAsInt = getc(fr)) != EOF)
{
     c = (char) charAsInt;
     printf("%c", c);
}

In other words: You need to compare against EOF, not NULL. You also need to use an int variable to receive the return value from fgetc. If you use a char, the comparison with EOF may fail, and you'll be back where you started.

Dan Breslau
Many other functions expect type `int` even though they typically only operate within the range of `char`. `putchar`, `isdigit`, `strchr` etc.
dreamlax
+1  A: 

Others have already addressed the issue you're having, but rather than using printf("%c", c); it is probably much more efficient to use putchar(c);. There is quite a bit of overhead involved when you ask printf to print just one character.

dreamlax
True, but the same holds for using `fgetc` instead of `fgets` or `fscanf`.
Dan Breslau
Also, SuperString is trying to learn C. The infinitesimal amount of overhead is not important at this point, and learning how to use printf is more useful in general than putchar. Since this isn't an answer to the question, you should have left a comment.
benzado
Using `getc` with `putchar` makes more sense since one is intended to read one character from `stdin`, and the other is intended to output one character to `stdout`.
dreamlax
Even if efficiency were a concern (which it's not), this program would definitely be I/O-bound, not CPU-bound, so the difference between `printf` and `putchar` is negligibl.
Adam Rosenfield
Sorry, before I mentioned `getc` gets a character from `stdin`, but I meant to say it gets a character from a from a stream.
dreamlax
Yes you're quite right. However, I still think `putchar` is a better choice of function given the situation.
dreamlax
+1  A: 

getc returns an int.

change char c, to int c.

also getc returns EOF, change your test against NULL to a test against EOF

EvilTeach
+5  A: 

In spite of its name, getc returns an int, not a char, so that it can represent all of the possible char values and, in addition, EOF (end of file). If getc returned a char, there would be no way to indicate the end of file without using one of the values that could possibly be in the file.

So, to fix your code, you must first change the declaration char c; to int c; so that it can hold the EOF marker when it is returned. Then, you must also change the while loop condition to check for EOF instead of NULL.

You could also call feof(fr) to test end of file separately from reading the character. If you did that, you could leave c as a char, but you would have to call feof() after you read the character but before you printed it out, and use a break to get out of the loop.

benzado
Just be careful when using `feof`: http://c-faq.com/stdio/feof.html
jamesdlin
@jamesdlin: Thanks for the warning.
benzado
Nit: in C, plain `char` can be signed or unsigned. Your statement above is true when `char` is unsigned, but if `char` is signed, it *may* be able to represent `EOF`. Typically, `EOF` is a small negative constant (-1 for example), and that's easily represented in a `signed char`.
Alok
Exactly. The only way to reliably and portably test for EOF is by using `feof`.
ephemient
@Alok: I don't see what it has to do with `char` itself being signed or not; `getc` returns the character as an `unsigned char` converted to `int`. You indeed would have the `EOF` collision if `sizeof(int) == 1`, however.
jamesdlin
@jamesdlin: If a char is unsigned, it can never be equal to `-1`, but if it is signed, then it *can* be equal to `-1`, and therefore be equal to `EOF`.
dreamlax
@myself: this of course assumes that EOF is -1, but the same would hold true if EOF was any negative integer greater than -129.
dreamlax
@dreamlax: Yes, a signed char can equal `EOF`, but we're talking about the value returned by `getc`, aren't we? `getc` does not sign-extend the `char` it stuffs into the returned `int`.
jamesdlin
@jamesdlin: No, we're talking about `benzado`'s statement regarding the use of `int` to represent all `char` values and in addition representing `EOF`.
dreamlax
@jamesdlin: if `getc` detects the end-of-file condition, it returns -1 *without* interpreting it as an `unsigned char`. It doesn't make sense for `getc` to do an `unsigned char` conversion at the end of file. From the standard: *If the end-of-file indicator for the input stream pointed to by stream is not set and a next character is present, the `fgetc` function obtains that character as an `unsigned char` converted to an `int` ...* (n1336, 7.19.7.1). In any case, my point was that `EOF` may be in the range [`CHAR_MIN`, `CHAR_MAX`].
Alok
We're all in agreement. Sorry. I simply misunderstood what "Your statement above" was referring to.
jamesdlin