1

I'm starting to learn about EOF and I've written the following simple program :

#include<stdio.h>
#include<stdlib.h>
#include<string.h>   

void main()
{    
    int i=0;
    while(getchar()!=EOF)
    {
        i++;    
    }       
    printf("number of characters : %d \n",i);       
}

The thing is, when I write a string, press enter and then press Ctrl+Z the output is the number of the characters I wrote plus 1 (for the EOF). However, if I write a string and, without changing line, press Ctrl+Z the while loop does not terminate. Why is that?

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
Grabenfly
  • 13
  • 5
  • Added Windows because I take it from your using `Ctrl+Z` for EOF that that's your platform. Btw., `main` should return `int`, not `void`, if you care about portable code. – Fred Foo Sep 27 '14 at 10:09
  • @larsmans First of all I think I have to know how this works and then I'll start worrying about portable code..! – Grabenfly Sep 27 '14 at 10:11
  • 1
    see this http://stackoverflow.com/questions/1793616/why-doesnt-getchar-recognise-return-as-eof-in-windows-console – ibrahim Sep 27 '14 at 10:13
  • Yeah paxdiablo says that if I press anywhere Ctrl+Z and newline after, I'll do my job but I've done that and the program continues,the "while" does not stop. – Grabenfly Sep 27 '14 at 10:21

3 Answers3

1

First things first, EOF is signalled only when Ctrl + Z is at the very beginning of a line. With that on mind:

On your first try with your input (10 characters) and then Enter, you actually push your input\n to the input stream, which gets read character by character through getchar, and there are 11 characters now with the addition of that new line at the end thanks to your Enter.

On the new line, you then use the Ctrl + Z combination to signal the EOF, and you indeed do that properly there; signal the EOF and get 11 as the result.

It's strange that you were expecting to see 10 here. What if you were to have an input of multiple lines? Would you like it to not count for new lines? Then you could use something like:

int onechar;
while ((onechar = getchar( )) != EOF)
{
    if (onechar != '\n')
        i++;
}

Or even more further, are you always expecting a single line of input? Then you might want to consider changing your loop condition into following:

while(getchar( ) != '\n')
{
    i++;
}

Oooor, would you like it to be capable of getting multi-line input, as well as it to count the \n characters, and on top of all that, just want it to be able to stop at Ctrl + Z combinations that are not necessarily at the beginning of a line? Well then, here have this:

// 26 is the ASCII value of the Substitute character
for (int onechar = getchar( ); onechar != EOF && onechar != 26; onechar = getchar( ))
{
    i++;
}

26, as commented, is the Substitute character, which, at least on my machine, is what the programme gets when I use Ctrl + Z inappropriately. Using this, if you were to input:

// loop terminated by the result of (onechar != 26) comparison
your input^Z

You would get 10 as the result and if you were to input:

// loop terminated by the result of (onechar != EOF) comparison
your input
^Z

You would get 11, counting that new-line which you did input along with all the other 10 characters before that. Here, ^Z has been used to display the Ctrl + Z key combination as an input.

Utkan Gezer
  • 3,009
  • 2
  • 16
  • 29
0

Input uses buffers. The first getchar requests a system-level read. When you press enter or ctrl-z the read returns the buffer to the program. When you press enter the system also adds a newline character to the buffer before returning it. Eof is not an actual character but results from reading an empty buffer.

After the control is returned to the program, getchar sequentially reads each character in the returned buffer and when it's finished it requests another read.

In the first case, getchar reads the buffer including the newline character. Then since the buffer is empty getchar requests another read which is interrupt by pressing ctrl-z, returning an empty buffer and resulting in EOF.

In the second case, pressing ctrl-z simply returns the buffer and after getchar is finished reading it, it requests another read which isn't finished since you never press ctrl-z or enter again.

It's not your while loop that never finishes but merely the read call. Try to press ctrl-z twice in the second case.

Veritas
  • 2,150
  • 3
  • 16
  • 40
-1

I saw here topic related to this. What you need to do is to set pts/tty into non-cannonical mode and do it with somekind of TCSANOW(do attr changes immediately). You do it using functions from termios.h , operating on struct termios;

guest
  • 1