43

I am stumped by the 1.5.2 question in K&R. I googled for sometime and found out that I have to supply the EOF input after entering the characters.

long nc = 0;

while (getchar() != EOF)
    ++nc;
printf("%ld\n", nc);

return 0;

I tried both command-D and control-D as EOF inputs but nothing worked. Any idea how to supply the EOF for Mac OS X?

Henry Ecker
  • 34,399
  • 18
  • 41
  • 57
Morpheus
  • 3,285
  • 4
  • 27
  • 57

4 Answers4

82

By default, macOS (formerly OS X and Mac OS X) software recognizes EOF when Control-D is pressed at the beginning of a line. (I believe this behavior is similar for other versions of Unix as well.)

In detail, the actual operation is that, when Control-D is pressed, all bytes in the terminal’s input buffer are sent to the attached/foreground process using the terminal. At the start of a line, no bytes are in the buffer, so the process is told there are zero bytes available, and this acts as an EOF indicator.

This procedure doubles as a method of delivering input to the process before the end of a line: The user may type some characters and press Control-D, and the characters will be sent to the process immediately, without the usual wait for enter/return to be pressed. After this “send all buffered bytes immediately” operation is performed, no bytes are left in the buffer. So, when Control-D is pressed a second time, it is the same as the beginning of a line (no bytes are sent, and the process is given zero bytes), and it acts like an EOF.

You can learn more about terminal behavior by using the command man 4 tty in Terminal. The default line discipline is termios. You can learn more about the termios line discipline by using the command man termios.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • 1
    Could you help me understand how `getchar()` works? I thought get char can only hold one character at a time. When I am entering a string like `hdjshj` into the terminal, and enter the end of file, will `getchar` store the whole sting of the characters at once? Or does it store the character as soon as it is entered into the terminal and stop storing it when the EOF is encountered? – Morpheus Jan 27 '14 at 13:42
  • 3
    @Morpheus: The processing of characters I discuss in my answer is below/before `getchar` sees the characters. `getchar` is part of software in your program (linked in from software libraries) that manages files and buffers. That software calls something like a `read` system call to get bytes. Separately, there is software that operates the “terminal” window you see, and software that reads characters from the keyboard. The terminal software receives characters from the keyboard (through additional layers of system software) and processes them.… – Eric Postpischil Jan 27 '14 at 14:49
  • 2
    @Morpheus: … Typically, the terminal software remembers ordinary characters in a buffer it maintains and processes special characters in various ways. E.g., when it sees a control-C, it may send a signal to the running process to interrupt it. When it sees a return/enter, it sends the buffered characters, and the return/enter, to the running process. When characters are sent to the running process in this way, the `read` system call returns them to the caller. The caller is part of that software that manages files and buffers in your program.… – Eric Postpischil Jan 27 '14 at 14:51
  • 2
    @Morpheus: … That software has its own buffer. When you call `getchar`, it pulls a character out of that buffer, if there is one there. (If there is not, it requests the buffer be filled, which results in another `read` call being executed.) `getchar` has only one guaranteed spot where `ungetchar` can put back a character, but there may be multiple characters in the internal buffer. (There are various ways to turn some of this buffering off so that you can read characters more directly from the terminal, but most programs do not need to do this.) – Eric Postpischil Jan 27 '14 at 14:53
15

If you want to see what EOF is set as in your terminal, you can type

stty all

on my mac, this gives the output -

speed 9600 baud; 24 rows; 80 columns;
lflags: icanon isig iexten echo echoe -echok echoke -echonl echoctl
    -echoprt -altwerase -noflsh -tostop -flusho pendin -nokerninfo
-extproc
iflags: -istrip icrnl -inlcr -igncr ixon -ixoff ixany imaxbel iutf8
-ignbrk brkint -inpck -ignpar -parmrk
oflags: opost onlcr -oxtabs -onocr -onlret
cflags: cread cs8 -parenb -parodd hupcl -clocal -cstopb -crtscts -dsrflow
-dtrflow -mdmbuf
discard dsusp   eof     eol     eol2    erase   intr    kill    lnext   
^O      ^Y      ^D      <undef> <undef> ^?      ^C      ^U      ^V      
min     quit    reprint start   status  stop    susp    time    werase  
 1       ^\      ^R      ^Q      ^T      ^S      ^Z      0       ^W     

You can see four lines up from the bottom, three cells in eof is ^D.

There's a fuller description here which is where I found the information.

dan
  • 1,030
  • 1
  • 9
  • 24
10

I just figured it out. You have to press Ctrl+D+D. Hold the control down and press D twice. I have to say what a weird key sequence.

vahid abdi
  • 9,636
  • 4
  • 29
  • 35
Morpheus
  • 3,285
  • 4
  • 27
  • 57
  • 1
    this does not answer the question: "Any Idea how to supply the EOF for mac osx?" – user3629249 Sep 26 '15 at 03:00
  • 1
    You should get the same behaviour by doing Ctrl-D twice (i.e. the continuous holding of Ctrl is not relevant) – M.M Jul 07 '19 at 03:27
0

In macOS Monterey, ctrl + D is all I need to fire an EOF.

Here is what I did:

  1. use gcc to compile the source
  2. run the executable
  3. press ctrl + D to send an EOF at the very start of a new line

I added two extra print at the beginning and the end of the program to verify ctrl + D actually works.