1

I tested lot's of situations with getchar() and putchar() and '\n' and EOF (in Visual Studio) to understand better how buffering and getchar works.

If my code

int c;
printf("Enter character\n");
/* 1 - number for explaining steps */
c = getchar();
putchar(c);

/* 2 */
c = getchar();
putchar(c);

printf("hi");

In this code if I enter the character a and press Enter, it will show

 a
 hi

This means that when I when press enter the '\n' will be saved in the buffer too, and then the first item in the buffer (a) goes to the first c=getchar() and a is printed; then the second item in the buffer (\n) goes to the second c=getchar() and prints the new line.

I conclude that '\n' is saved in the buffer and it's not the result of the command's ability to go to a new line when pressing enter because I tested another code for this:

while ((c = getchar()) != '\n')
    putchar(c);
printf("hi");

In this code when I typed a and press enter it prints ahi and new line doesn't print it means that when a passed to getchar(), putchar() prints it then when getchar() gets the '\n', the loop terminated and putchar() inside the loop doesn't print the new line so the command is not the reason for the new line.

Now I want to test another code:

  int c;
  while ((c = getchar()) != EOF)
    putchar(c);
  printf("hi");
  return 0;

In this one if I pass it abc and the signal of EOF (in my system ^Z (Ctrl+Z)) it will show abc->. If we look at it like the previous code: abc-1(or every thing else shows eof)'\n' should have been saved in the buffer and first a go to the first getchar (first time loop works) the b passes to second getchar then c passes to the third — and then -1should have been passed to c=getchar() and it's against the condition and loop should terminate.

However, instead it prints -> and loop continued and new line (the last item in the buffer) doesn't print. Instead when I just ctr +z when c=getchar() reads the EOF sign from the buffer the loop terminated and new line printed so why it prints the new line? It reads the EOF and it should not read anything else in the buffer in this situation.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Habib Kazemi
  • 2,172
  • 1
  • 24
  • 30
  • That last paragraph is almost entirely one sentence/question; might you re-format it? – Scott Hunter Mar 13 '15 at 22:45
  • In future questions, and passing around code in general, you can put things like step #1 in the code comments. Programmers will know to look in the comments when you talk about step 1, and it keeps our internal C compilers from throwing hissy fits when we read your code. – Philip Mar 13 '15 at 22:58
  • Last example, after the c is processed, the next character is '-' not '-1'. Are you sure the '>" isn't your prompt in the terminal? – Philip Mar 13 '15 at 23:08
  • Note that the first loop example, which only tests for newline, will run into problems if you type Control-Z twice before you hit enter. I don't have a good explanation for the `->` appearing. It could be something the terminal driver does, though it is a little improbable. I don't have a Windows system on which to run the tests. – Jonathan Leffler Mar 14 '15 at 18:45

1 Answers1

2

Your outline of how the input reads first a and then the newline in the first example is basically correct. Newline is a perfectly normal character as far as getchar() is concerned; indeed, there are no abnormal characters. getchar() can return any 8-bit value that fits in char, plus one additional value, known as EOF. That's why its return value must be stored in an int, as you did correctly.

The standard I/O functions return EOF when the underlying read() system calls return 0 bytes available to be read — or when there's an error.

When you type abcControl-Z on Windows (you'd type Control-D instead on Unix), then:

  1. The terminal driver makes the characters currently in its buffer (abc) available to the read() system call.
  2. The read() system call populates the standard I/O buffer with those characters.
  3. The successive getchar() calls return a, b and c.
  4. The next getchar() waits for more input.

This wasn't EOF; it was just flushing the characters on the line to the program. To get the effect of EOF, you'd have to type Control-Z twice in a row after the abc. The first would flush the abc; the second would generate a read() of 0 bytes, indicating EOF.

The terminal driver also makes input available when a newline (Enter) is pressed. If you type Control-Z immediately after typing Enter, all zero of the characters pending input are sent from the terminal to the program, so the read() returns 0, so the standard I/O package reports EOF.

Note that until you hit enter or the EOF indication, you can edit the data in the line with the backspace and other editing options, including deleting all the data. Once you've hit enter or the EOF indication, you can no longer edit the data that was made available to read().

The analogous behaviour occurs on Unix; you type the EOF indication twice to terminate the input mid-line; once to terminate the input at the start of a line.

There are many related questions on Stack Overflow, including these ones:

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Another well presented answer! – chux - Reinstate Monica Mar 14 '15 at 00:31
  • nice answer.but i was asking about windows that we should press enter after ^c and press first time is not flushing the buffer I tested in linux it was obvious how it's work but in windows I don't know why it prints ('->') and why it doesn't print new line ,and why if i had pressed ^c the press enter with out any other characters it prints the new line after terminate the loop i expected not to read rest of the buffer. – Habib Kazemi Mar 14 '15 at 09:10
  • i couldn't edit the last comment change ^c with ^z sorry. and I should mention that it prints '->' when typing 'abc^z'the pressing enter. – Habib Kazemi Mar 14 '15 at 09:19
  • FYI: if I find I've made a mistake in a comment but it is no longer editable, and if there is no response to it yet, then I will make a copy of the comment and add a new, edited version of it, and then delete the old one. If deleting the comment would mess up the flow of other comments, I live with typos. – Jonathan Leffler Mar 14 '15 at 14:24