0

I have recently started learning C from the K&R book. Now I am stuck on example 1.5.2. The program is like this:

#include <stdio.h>

/* Count the number of characters written in input */
main()
{
    long nc;

    nc = 0;
    while (getchar() != EOF)
        nc++;

    printf("%ld\n", nc);
}

I compile the code directly from notepad++ via the NppExec plugin, but have also tried to run it directly from cmd.

This are different examples

Example 1:

input: dadada^Z

from Notepad++

output: 0

from cmd

while loop doesn't end

Example 2:

input: dadada[enter]^Z

from Notepad++

output: 7

from cmd

while loop doesn't end

Example 3:

input: dadada[enter]^Z[enter]

from Notepad++

output: program end with [enter]^Z, additional [enter] doesn't do anything

from cmd

output: 7

Now what I was wondering is why was the output 0 in example 1.

And could someone please explain the EOF integer. In cmd it is [enter]^Z[enter], in notepad++ it is [enter]^Z and some people have even said its ^Z.

Edit

This is the command I used in NppExec

npp_console 1               //open console
NPP_CONSOLE -               //disable output of commands
npe_console m-              //disable unnecessary output
con_colour bg= 191919 fg= F5F5F5    //set console colors
npp_save                //save the file
cd $(CURRENT_DIRECTORY)         //follow current directory
NPP_CONSOLE +               //enable output
IF $(EXT_PART)==.c GOTO C       //if .c file goto C label
IF $(EXT_PART)==.cpp GOTO CPP       //if .cpp file goto CPP label
IF $(EXT_PART)==.java GOTO JAVA     //if .java file goto JAVA label
IF $(EXT_PART)==.cs GOTO C#     //if .cs file goto C# label
IF $(EXT_PART)==.py GOTO PYTHON     //if .py file goto PYTHON label
echo FILE SAVED
GOTO EXITSCRIPT             // else treat it as a text file and goto  EXITSCRIPT
//C label
:C                                                                  
cmd /C if exist "$(NAME_PART).exe" cmd /c del "$(NAME_PART).exe"//delete   existing executable file if exists
gcc "$(FILE_NAME)" -o $(NAME_PART)              //compile file
IF $(EXITCODE) != 0 GOTO EXITSCRIPT             //if any compilation error   then abort
echo C CODE COMPILED SUCCESSFULLY:              //print message on console
$(NAME_PART)                                            //run file in cmd,  set color to green and pause cmd after output
GOTO EXITSCRIPT                         //finally exits

:CPP
cmd /C if exist "$(NAME_PART).exe" cmd /c del "$(NAME_PART).exe"
g++ "$(FILE_NAME)" -o $(NAME_PART)
IF $(EXITCODE) != 0 GOTO EXITSCRIPT
echo C++ CODE COMPILED SUCCESSFULLY:
$(NAME_PART)
GOTO EXITSCRIPT

:JAVA
cmd /C if exist "$(NAME_PART).class" cmd /c del "$(NAME_PART).class"
javac $(FILE_NAME) -Xlint
IF $(EXITCODE) != 0 GOTO EXITSCRIPT
echo JAVA CODE COMPILED SUCCESSFULLY:
java $(NAME_PART)
GOTO EXITSCRIPT

:C#
cmd /C if exist "$(NAME_PART).exe" cmd /c del "$(NAME_PART).exe"
csc $(FILE_NAME)
IF $(EXITCODE) != 0 GOTO EXITSCRIPT
echo C# CODE COMPILED SUCCESSFULLY:
$(NAME_PART)
GOTO EXITSCRIPT

:PYTHON
echo RUNNING PYTHON SCRIPT IN CMD:              //python is a script so no     need    to compile
python $(NAME_PART).py
GOTO EXITSCRIPT

:EXITSCRIPT
// that's all, folks!
over--00--
  • 19
  • 4
  • 1
    The program [works fine on ideone](http://ideone.com/GSy8jv). The problem has to do with recognition of `EOF` in your environments. – Sergey Kalinichenko Jan 30 '16 at 11:33
  • what operating system are you running? – Angus Comber Jan 30 '16 at 11:38
  • I am running windows 10 – over--00-- Jan 30 '16 at 11:42
  • 1
    Your code works on Windows 7 using Visual Studio 2013 - Ctrl-Z for termination. Maybe your plugin. Visual Studio 2015 is free by the way. – Angus Comber Jan 30 '16 at 11:52
  • @dasblinkenlight so what is `^z` defined as in notepad++ – over--00-- Jan 30 '16 at 11:53
  • @AngusComber yeah I originally wanted to try it out, but after finding out that I can just compile and run a program directly from notepad++ I didnt really feel the need to. – over--00-- Jan 30 '16 at 12:00
  • After installing nppexec in notepad++ I find that it is a generic framework for executing commands: It asks me what I want to do with the source file. I suppose it asked you, too. What did you answer? – Peter - Reinstate Monica Jan 30 '16 at 12:06
  • 2
    In windows, for EOF to be sent, 1)All the data must be already flushed into the `stdin` before pressing CTRL+Z 2) Enter needs to be pressed after CTRL+Z – Spikatrix Jan 30 '16 at 12:07
  • 1
    invalid protoype for `main`, it should be `int main(void)` or `int main(int argc, char *argv[])` – chqrlie Jan 30 '16 at 12:10
  • @chqrlie Ah, that is why it doesn't work. – Peter - Reinstate Monica Jan 30 '16 at 12:13
  • @PeterA.Schneider: No, I'm afraid it is just a comment. – chqrlie Jan 30 '16 at 12:16
  • @chqrlie I know... I just couldn't resist. You are more catholic than the popes, so to speak ;-) (the program is a literal copy from K&R 2nd ed.). When I asked elswhere, nobody could come up with an example where this made a difference (beyond an undefined exit status of the program, which is rather independent of `main`'s declaration). – Peter - Reinstate Monica Jan 30 '16 at 12:18
  • 1
    How do you run the program for cmd? – Karoly Horvath Jan 30 '16 at 12:20
  • @chqrlie The program is exactly the same as in K&R book. Since its writen by the author of the c language I dont think its wrong. – over--00-- Jan 30 '16 at 12:20
  • 1
    @over--00-- The C standard evolved since 1989, and formally requires the declaration for `main()` which @chqrlie mentioned. It doesn't make any difference in practice though if you are not interested in the exit status. – Peter - Reinstate Monica Jan 30 '16 at 12:22
  • @over--00--: It's a ridiculously old book. It's like reading a 500 year old english book. It's grammar and vocabulary isn't correct anymore. – Karoly Horvath Jan 30 '16 at 12:22
  • @KarolyHorvath It's a ridiculously old *language* ;-) – Peter - Reinstate Monica Jan 30 '16 at 12:23
  • 2
    @PeterA.Schneider: OK, I should have seen the K&R reference. It is really too bad Kernighan does not make a third edition. The book is dated, but still much better than many newer ones. Sadly, `gcc` still defaults the `c89` and will not complain about this, but `clang` will. C99 is 17 years old, already replaced by the more recent C11, the popes have long spoken, time to move on... – chqrlie Jan 30 '16 at 12:26
  • @chqrlie I agree but would put more emphasis on the important progress which was made in the language (what may that be? Probably multithreading support, aliasing?) than on irrelevant (I insist) formalisms. – Peter - Reinstate Monica Jan 30 '16 at 12:36
  • @chqrlie sorry, I thought the second edition was up to date. Well thank you for explaining its faults. – over--00-- Jan 30 '16 at 12:43
  • @PeterA.Schneider: while I agree with you that the language did make important steps, formalism is very important too. C makes it so easy for programmers, especially newbie programmers, to make all kinds of mistakes, blatant and subtile ones... Attention to detail, consistent formatting and spacing, systematic use of classic idioms, systematic use of compiler warnings... all these may all seem futile, they help reduce the number of bugs. – chqrlie Jan 30 '16 at 12:44
  • So should I still learn from the K&R book or not. And if I should what should I be wary of – over--00-- Jan 30 '16 at 12:45
  • @over--00--: You can look at http://stackoverflow.com/questions/562303/the-definitive-c-book-guide-and-list for more choices. – chqrlie Jan 30 '16 at 12:46
  • @over--00-- Incidentally, K&R is the top choice. By all means, read it, and then read it again. It's one of the best tech books out there. Declare main's return value any way you want, it didn't matter back then and it doesn't matter today. – Peter - Reinstate Monica Jan 30 '16 at 12:57
  • Pay attention to the *semantics* and language design choices. Why does an array object not carry size information? (Where should it!?) Why does it "decay" to a pointer when it is passed to a function? How do I deal with that? Why is this illegal: `int arr[2][3]; int **p = arr;`, even though `int i = **arr;` is perfectly ok?? -- And if you have really understood it, move on to C++. – Peter - Reinstate Monica Jan 30 '16 at 13:02

1 Answers1

3

Edit: I see now that you use gcc, and I realize that perhaps the compiler (determining the run time library) may not be so important. It will just receive a zero return value on a read() or equivalent from a file descriptor. How user input can trigger that is a matter of the terminal (the input window and driver).

There are good explanations for unix online; one fairly thorough one is here. (As opposed to what I thought before, the shell is not involved in it; input to a foreground program from a terminal is not processed by the shell.) The bottom line is that the terminal program and driver together react to certain user actions (like pressing a special button, or selecting a menu item) and then "communicate things" (close file descriptors, send signals) to the running process [group]. The Windows mechanisms are likely almost but not quite entirely different.


Then, the nppexe plugin is not a real terminal, according to the documentation; under which conditions it closes the file descriptor it sends the data to (the event which would make the reading process detect EOF) I don't know. I must assume it closes the file descriptor when you press ctrl-z without sending the characters typed so far.

The normal Windows console usually recognizes ctrl-z as an end-of-file indicator, with restrictions (cf. Cool Guy's comment). In my attempts on a Windows console with a cygwin-gcc compiled program, ctrl-z immediately closes the communication with the program, discarding any user input on the current input line so far. That's consistent with your 0 result.

A cygwin terminal (I use mintty) and shell (I use bash) will usually recognize ctrl-d. There, too, ctrl-d has to be pressed at the beginning of a line, or more exact when all input so far has been sent. If input is pending when ctrl-d is pressed, e.g. while typing a line, it causes the terminal to send that data to the process, so that no data is waiting any more. A subsequent, second ctrl-d will therefore make the terminal close the connection. (Thanks for Chrono to point that out.)

(Ctrl-z is commonly interpreted by a unix terminal, as well as cygwin's mintty, as a request to suspend the current foreground process. Note that these special keys are configurable with stty: stty eof ^E, where the ctrl-e was produced by pressing ctrld-v ctrl-e, will from then on make the terminal recognize ctrl-e instead of ctrl-d for end of file.)


In general I recommend using prepared files which are redirected to the program's standard input in order to test such programs. That avoids many of the pitfalls which are involved with interactive sessions, and has the advantage that it is perfectly reproducable and can run atomatically, which is important for tests.

Community
  • 1
  • 1
Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
  • If there is data on the line, Ctrl-D should flush the input buffer of the terminal (mintty in your case), which will send that data to the input buffer of your process. Otherwise, the terminal's input buffer is empty. If you press Ctrl-D when the terminal's input buffer is empty, then `EOF` is sent to your process. –  Jan 30 '16 at 13:01
  • (continued) Unfortunately, the Windows console doesn't work anything like that. Ctrl-Z at the start of a line, followed by the Enter key, sends `EOF`. Ctrl-Z on a line with data preceding it sends that data _and_ character code 26 and _**does not**_ send `EOF`. Any data after Ctrl-Z is discarded, including `\n`, regardless of any other input. –  Jan 30 '16 at 13:02
  • @ChronoKitsune Hmmm... confusing. On my Windows8 cmd window, a program compiled with cygwin gcc terminates immediately when pressing ctrl-z, whether in the middle of input or not, and does not receive the preceding characters on that line. mintty/bash work the way you described (flushing the line so far). I wasn't aware of that. windows/cmd also interprets EOF when receiving a ctrl-d on an empty line or two subsequent ones in the middle of a line (in which case the preceding input is sent to the process first), which I find confusing. – Peter - Reinstate Monica Jan 30 '16 at 13:20
  • @ChronoKitsune I added the information about ctrl-d flushing the pending input, thanks--. Regarding ctrl-z: my little program received EOF immediately after I press ctrl-z *anywhere* on a line, no enter required, and pending input (start of that line) was discarded. – Peter - Reinstate Monica Jan 30 '16 at 14:17
  • Hm... When I compile in VS2013, the program behaves the way you describe it, so the run time libs seem to have an effect. When I run that prog in mintty and set susp to something else with `stty susp1`, I can actually input ctrl-z. Then it behaves on the console like you describe (must be at beginning of line, followed by enter). That makes me think that under windows, EOF detection happens late in the processing pipeline (later than the terminal). – Peter - Reinstate Monica Jan 30 '16 at 14:50
  • Cygwin's default environment differs from the Windows console default environment. Ctrl-Z in a Cygwin process is the "Suspend process" key sequence for example, but Ctrl-Z with a (non-Cygwin) Windows console process functions in a manner similar to the way Ctrl-D behaves in Cygwin's bash environment by default, though obviously there are some differences. –  Jan 30 '16 at 17:50