7

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);
}
Deduplicator
  • 44,692
  • 7
  • 66
  • 118

6 Answers6

12

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.

Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
  • 1
    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 Dec 05 '08 at 02:30
  • Oh, I've always assumed that EOF was one of the control characters... thanks for the info. – Paige Ruten Dec 05 '08 at 02:36
  • 1
    Actually now I realize an EOF character wouldn't make sense because binary files would often contain the character code. – Paige Ruten Dec 05 '08 at 02:42
  • 1
    CTRL-D actually is the EOT (end of transmission) character, which causes an EOF condition when sent from the terminal. – tvanfosson Dec 05 '08 at 03:19
  • ctrl Z was an eof character in some of the early retro machines. – EvilTeach Dec 05 '08 at 22:47
7

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
  • 106,424
  • 25
  • 145
  • 137
6

Your 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;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
EvilTeach
  • 28,120
  • 21
  • 85
  • 141
  • Though slightly wrong, %f is for doubles. It can also be used for floats due to promotion on variable argument functions. – Chris Young Dec 05 '08 at 02:26
  • Thanks but I'll stick with %lf, like the good book says #include 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 Dec 05 '08 at 02:47
  • 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 Dec 05 '08 at 03:01
  • 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 Dec 05 '08 at 03:07
  • @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 Dec 05 '08 at 04:31
  • Also, there is no such this as a long float, regardless of whether it works on your compiler. – Robert Gamble Dec 05 '08 at 04:31
  • The question context is K&R, not C89/C90 or ANSI. long float is valid in that context. double is a synonym for it, %f is for float. %lf is for long float. It's in the book. – EvilTeach Jan 22 '10 at 11:24
5

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
  • 15,627
  • 7
  • 36
  • 42
  • 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 Dec 05 '08 at 03:35
  • 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 Dec 05 '08 at 03:44
  • Apologies, on doing my own research it appears you're right about 4 also. Thanks. – Chris Young Dec 05 '08 at 04:00
  • 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 Dec 05 '08 at 04:03
  • Here is an example program for #4: #include int main (void) { while (getchar() != EOF); puts("first EOF"); while (getchar() != EOF); puts("second EOF"); return 0; } – Robert Gamble Dec 05 '08 at 04:04
  • 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 Dec 05 '08 at 04:06
  • 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 Dec 05 '08 at 04:09
  • ie, if I put clearerr(stdin) before your second while, I get the behaviour I was looking for. – Chris Young Dec 05 '08 at 04:12
  • Yes, some systems need the clearerr first, I should have put that in there. – Robert Gamble Dec 05 '08 at 04:21
1

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
  • 20,457
  • 3
  • 51
  • 87
  • 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? –  Dec 05 '08 at 01:26
  • 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 Dec 05 '08 at 01:28
  • 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 Dec 05 '08 at 01:28
  • 1
    K&R "The C Programming Language" was the first book to teach C. It is very old. – Chris Dec 05 '08 at 01:30
  • Second edition is from 1988, still considered one of the best C books, just misses a few things out from the C99 standard. –  Dec 05 '08 at 01:50
  • 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 Dec 05 '08 at 03:24
  • @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 Dec 05 '08 at 05:01
0

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
  • 347
  • 2
  • 4