tags:

views:

1333

answers:

6

Any idea why the following code doesn't print the amount of characters in the input? I've taken this straight from the K&R book. Learning C at the moment and this is really confusing, looks to me like I'm never reaching EOF. If that's the case then why would this be used as an example?

#include <stdio.h>

main()
{
    double nc;

    for (nc = 0; getchar() != EOF; ++nc)
        ;
    printf("%d\n", nc);
}
+1  A: 

This code reads characters from the standard input. When you run this program normally, standard input comes from the user. In this case, there is no way to send EOF to the program.

This code will work if you redirect a file to the standard in (./myprogram < tempfile.txt).

SoapBox
Why is it being used as ane example in it's current form when there is no way (in it's current intended form) to get to the printf function?
Are you sure they don't want you to use redirection? Also if you typed it exactly as the example appears, then it looks like this book is pretty old, maybe it used to work, or works on a specific platform (that might not be around anymore, like DOS).
SoapBox
Particularly the definition of main(), where it isn't given a return type, and the use of double for the for loop make me question the age and usefulness of this book.
SoapBox
Chris
Second edition is from 1988, still considered one of the best C books, just misses a few things out from the C99 standard.
main has no return type because it isn't returning anything. This is allowed in C. It's using double for the loop because the code is for an exercise where the number of characters exceeds an int. This exercise takes characters from a file, the user isn't expected to press millions of keystrokes.
Dour High Arch
@Dour: main has return type of int, this is implied when none is specified in C89. A value is returned from main in the example but since no return statement is present the value returned is undefined (in C99, if main ends without returning a value the effect is equivalent to return 0;).
Robert Gamble
+7  A: 

The program keeps reading data from stdin until EOF is received, this is done by pressing Ctrl-D at the beginning of a line on a Unix console or Ctrl-Z at the beginning of a line in a Windows console. After you signal EOF in this way, the printf function will be executed displaying the number of characters read.

Robert Gamble
+10  A: 

The program looks correct, your problem is that you have to send EOF (end-of-file) to the command line after your input since the standard input is treated as a file. I think in a linux terminal you can press Ctrl+D to send EOF... I'm not sure how to do it in other OS's. To test this program you might want to change EOF to '\n' which will cause it to stop when you press enter.

yjerem
CTRL Z in dos land
EvilTeach
Why did I get two downvotes?
yjerem
FWIW, I didn't downvote you. However, there is no such thing as an EOF character, so that might be why. When a user presses ^D (or whatever) on a terminal, it causes an EOF condition on the process' stdin (it's closed by the shell), there is no character involved.
Chris Young
Oh, I've always assumed that EOF was one of the control characters... thanks for the info.
yjerem
Actually now I realize an EOF character wouldn't make sense because binary files would often contain the character code.
yjerem
CTRL-D actually is the EOT (end of transmission) character, which causes an EOF condition when sent from the terminal.
tvanfosson
ctrl Z was an eof character in some of the early retro machines.
EvilTeach
+5  A: 

nc is a double.

use printf("%lf", nc) to print doubles

Try this one instead

#include <stdio.h>

int main(void)
{
    int nc;

    for (nc = 0; getchar() != EOF; ++nc)
        ;
    printf("%d\n", nc);

    return 0;
}
EvilTeach
Ooh, good pickup.
Charlie Martin
Though slightly wrong, %f is for doubles. It can also be used for floats due to promotion on variable argument functions.
Chris Young
Thanks but I'll stick with %lf, like the good book says#include <stdio.h>int main(void){ long float x = 3.14159265358979; float y = 3.14159265358979f; printf("%15.10f\n", y); /* 3.1415927410 */ printf("%15.10lf\n", x); /* 3.1415926536 */ return 0;}
EvilTeach
You may stick with %lf if you wish, but it's still wrong. %f is for doubles. As an aside, ISO/IEC 9899:1999 (colloquially C99, not supported by many implementations) treats %lf as %f, but in ISO/IEC 9899:1990 (colloquially ANSI C or C89 or C90) %lf is undefined behavior.
Chris Young
Also, your comment example is wrong, there's no such thing as a long float. You use %f for both floats and doubles, because a float is promoted to a double when passed to a variable argument function.
Chris Young
works on my compiler. thanks anyway.
EvilTeach
@EvilTeach, please don't advocate using %lf, this was made legal in C99 to harmonize with the scanf but is not legal in prior versions. Since it is not possible to pass a float to printf (or any variadic function), %f is used to represent doubles (whether promoted from float or not).
Robert Gamble
Also, there is no such this as a long float, regardless of whether it works on your compiler.
Robert Gamble
EvilTeach
+5  A: 

I'd like to clarify the answers given so far because they seem to use phrases like "send EOF", "received EOF", "EOF character", etc. As per comments (thanks) to this answer, "send EOF" and "received EOF" are legitimate terms, but please don't think that it's a character.

EOF is not a character at all. It is the value that getchar() (or fgetc/getc) returns if the stream is at "end-of-file" or a read error occurs. It is merely a special value outside the range of character values that getchar() will return that indicates the condition of error or end-of-file.

It is defined by the C standard as being negative, whereas getchar returns characters as an unsigned char converted to int.

Edit: On doing some research which I should've done before the paragraph I wrote that used to be here, I've realised some of my assumptions were completely wrong. Thanks to the commenter for pointing this out.

Once a stream (such as stdin) is in end-of-file condition, this condition can be cleared again with clearerr() and getchar() may read more data from stdin.

Chris Young
Wow, there is a lot to correct here: 1) nobody called EOF a character, 2) "send/receive EOF" are perfectly legitimate phrases, 3) the controlling terminal doesn't close your files, 4) stdin is not closed when EOF is returned from getchar, you can continue to read from stdin after receiving EOF ...
Robert Gamble
1) Actually Jeremy Ruten did, and I corrected him and he edited his answer; see the revision history. 2) Okay 3) I should've said the shell 4) Sure, you can continue to read from stdin but you'll just keep getting EOF. If you disagree please provide an illustration.
Chris Young
Apologies, on doing my own research it appears you're right about 4 also. Thanks.
Chris Young
1) Okay, I didn't see this, I'll concede that point. 3) this is still wrong, the shell doesn't close your files, this isn't even possible after the child process starts. 4) stdin is not closed, if it was you couldn't read from it anymore, you can read more data after EOF if more data is added.
Robert Gamble
Here is an example program for #4:#include <stdio.h>int main (void) { while (getchar() != EOF); puts("first EOF"); while (getchar() != EOF); puts("second EOF"); return 0;}
Robert Gamble
@Chris, downvote retracted, thanks for fixing.
Robert Gamble
Thanks, but what input do you give that example program? As soon as I hit ^D, first EOF and second EOF are outputted straight away. ie, subsequent calls to getchar() return EOF.
Chris Young
I think I've found the gap in my understanding. end-of-file condition can be reversed with clearerr(), this would allow me to read more characters from stdin after an EOF, thanks.
Chris Young
ie, if I put clearerr(stdin) before your second while, I get the behaviour I was looking for.
Chris Young
Yes, some systems need the clearerr first, I should have put that in there.
Robert Gamble
Thanks, this has been very informative.
Chris Young
A: 

First, as mentioned previously you need %lf instead of %d to display the double, otherwise it will just display zero all the time (d is for a signed integer). Then if you want to test this manually on a windows based OS type in some characters press Enter and then pressl CtrlZ on the next line all by itself (this will simulate the EOF). The printed result will be one more than the number of characters (it includes the CtrlZ). Also as SoapBox indicated when looking for an EOF typically the thinking back then was Unix where you pipe a file into the program via standard input, this would also work.

daduffer