C programming — loop - c

I am following the exercises in the C language book. I am in the first chapter where he introduces loops. In this code:
#include <stdio.h>
/* copy input to output; 1st version */
int main() {
int c, n1;
n1 = 0;
while ((c = getchar()) != EOF) {
if (c == '\n') {
++n1;
}
printf("%d\n", n1);
}
}
In here I am counting the number of lines. When I just hit enter without entering anything else I get the right number of lines but when I enter a character then hit enter key the loop runs twice without asking for an input the second time. I get two outputs.
this how the output looks like:
// I only hit enter
1
// I only hit enter
2
// I only hit enter
3
g // I put char 'g' then hit enter
3
4
3 and 4 print at the same time. why is 4 printing after the loop has been iterated already? I thought the loop would restart and ask me for input before printing 4.

The getchar function reads one character at a time. The number of lines will be printed for every character in the input read by getchar, whether that character is newline or not, but the counter will only be incremented when there is a newline character in the input.
When you enter g then the actual input that goes to the standard input is g\n, and getchar will read this input in two iterations and that's the reason it is printing number of lines twice.
If you put the print statement inside the if block then it will print only for newline characters. If you put the print statement outside the loop, then it will only print the count of the number of lines at the end of the input.

To be clear this is the terminal that you are dealing with.
By default, the terminal will not get input from the user \n is entered. Then the whole line is placed in the stdin.
Now as I said earlier here the program is not affected by the buffering of stdin. And then the characters will be taken as input and it is processed as you expect it to be. The only hitch was the terminals buffering - line buffering.
And here from standard you will see how getchar behaves:-
The getchar function returns the next character from the input stream pointed to by stdin. If the stream is at end-of-file, the end-of-file indicator for the stream is set and getchar returns EOF. If a read error occurs, the error indicator for the stream is set and getchar returns EOF.
Now what are those characters - those charaacters include \n - the \n is what you put in the terminal and then to stdin via pressing the ENTER. Here earlier you were entering the characters earlier which were \n. This time you entered two characters. That's why the behavior you saw.

Related

How is the "getchar()" function able to take multiple characters as input?

Here is a basic character counting program in C:
#include <stdio.h>
#include <stdlib.h>
int main(){
long nc = 0;
while(getchar() != EOF)
nc++;
printf("%ld\n" , nc);
}
When I am entering "abcde" as an input, it displays a value of 6(after triggering the EOF test), +1 for the newline character. But my doubt is that getchar(), as its name itself suggests, takes only 1 character into account. But when I am entering "abcde" at one go itself, it still works. Why is this so? What problem am I doing here?
Standard input, by default, is line-buffered with an interactive device. This means that your program won't see any input at all until a complete line is ready, in your case when you hit Enter. One good reason for this is that if the user types her 8 character password, then hits backspace 8 times, and then types her username and hits Enter, then your program only gets her username, and never sees the correction, which is usually what you want when your shell gives the opportunity to edit your input before you send it anywhere.
So what happens is essentially this:
You call getchar(). No input is available, so it waits.
You press a. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press b. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press c. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press d. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press e. It's not the end of a line, so no input is sent to your program, getchar() has nothing to read, so it still waits.
You press Enter. Now it is the end of a line, so the input "abcde\n" is sent to your program.
getchar() now has input to read, so it returns 'a', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns 'b', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns 'c', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns 'd', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns 'e', increments nc, and loops back to wait for input.
Immediately, getchar() has more input to read from the rest of the characters in that line, so it returns '\n', increments nc, and loops back to wait for input.
If you signified end-of-input, perhaps by pressing Control-D, then getchar() has nothing to read and knows there will never be anything to read, so it returns EOF and your loop ends. If it were not end-of-input, then getchar() would just again wait here for you to enter a new line of input.
So what actually happened here is that getchar() did nothing until you hit Enter. Then, probably before you even took your finger off the Enter key, it ran six times and consumed the six characters of input that you typed. But despite getchar() running six times, you were only prompted to enter something once (twice, if you include having to type Control-D), because getchar() will only wait for your input when it doesn't already have input available and waiting.
Back in the days where standalone terminals were common, the actual terminal device might not even transmit any characters to the computer until the end of a line, and could have a small amount of on-board memory to allow for this kind of local line-based editing, so the computer itself might literally never see it until end-of-line. On the kind of modern PC many people use, the operating system, down at the terminal driver level, will more probably be buffering these characters itself, and just presenting them and making them available to your program one line at a time (unless you specifically tell it that you want characters immediately, of course).
When you type in abcde\n (\n generated from Enter), it gets flushed into the standard input stream (stdin).
getchar(), as its name itself suggests, takes only 1 character into account
Yes, that's right. But notice that getchar is used in a loop which loops until getchar returns EOF. Also, recall that getchar reads input from the stdin.
So, in the first iteration, after you type in the data, getchar reads the first character a. In the second iteration, it doesn't wait for input since the stdin still contains bcde\n and hence, reads the next character b and so on.
Finally, the loop breaks when you trigger EOF. Then, the printf gets executed (printing 6 since six characters were read) and the program ends.
getchar reads next characters from standard input's buffer, and returns it, since you feed six characters - "abcde\n" - into the standard input, and you are calling getchar in a while loop, that means the loop body was run for six times, it read the chars one by one. You can test this by:
int c;
while ((c = getchar()) != EOF) {
printf("got %c\n", c);
nc++;
}

how putchar works with while loop?

I am new to c programming, so hope you guys can help me out with such questions.
1. I thought putchar() only print 1 char each time, while when I enter several char like 'hello' it print 'hello' before allow me to enter a next input? I thought that it should print only 'h' and then allow me to enter other input because getchar() only return one character each time.
2. how to make the loop stops? I know EOF has value of -1, but when I enter -1, the loop still runs.
#include <stdio.h>
main()
{
int c = getchar();
while(c != EOF){
putchar(c);
c = getchar();
}
}
After the first getchar() has completed reading one character, the next getchar(); is inside the while() loop, so as per the logic, it will keep reading the input one-by-one, until in encounters EOF.
Following the same logic, putchar(c); is under the while loop, so it will print all the characters [one character per loop basis] read by getchar() and stored in c.
In linux, EOF is produced by pressing CTRL+D. When waiting for input, if you press this key combination, the terminal driver will transform this to EOF and while loop will break.
I'm not very sure about windows, but the key combination should be CTRL+Z.
Note: even if it seems entering -1 should work in accordance with EOF, actually it won't. getchar() cannot read -1 all at a time. It will be read as - and 1, in two consecutive iterations. Also worthy to mention, a character 1 is not equal to an integer 1. A character 1, once read, will be encoded accordingly [mostly ASCII] and the corresponding value will be stored.
getchar() gets the input from the console. In a while loop, it will read all the characters from the input including the return key.
-1 is "-1". It's not a value but just another combination of characters. EOF occurs when there is no more char in the buffer. i.e. when you press Enter (or Ctrl-Z or Ctrl-D depending on your OS)

Understanding getchar() in the character counting program in C

This is a follow-up question of my previous question. There is already a similar question asked(question). But I don't get what I want to know from that answer.
From the previous question I come to know that if I type a lot of characters, then they are not made available to getchar(), until I press Enter. So at the very point when I press Enter, all the characters will be made available to getchar()s. Now consider the following program for character counting:
#include<stdio.h>
main()
{
long nc;
nc=0;
while(getchar()!=EOF)
++nc;
printf(" Number of chars are %ld ",nc);
}
If I input characters from the command line in the following sequence: {1,2,3,^Z,4,5,Enter}, then in the next line {^Z,Enter}. The output that I expect is: Number of chars are 6. But the output that I am getting is Number of chars are 4.
This answer explains that when we input1,2,3,^Z, then ^Z acts like Enter and 1,2,3 are sent to getchar()s. The while loop of the above written code runs three times. ^Z is not given to getchar(), so the program doesn't terminate yet. My input was {1,2,3,^Z,4,5,Enter}. After ^Z I had pressed 4,5 and then Enter. Now when I press Enter the characters 4,5 and Enter, should be given to getchar()s and the while loop should execute three times more. Then in the last line I input {^Z,Enter}, since there is no text behind ^Z, it is consider as a character and when I press Enter, this ^Z is given as the input to getchar() and the while loop terminates. In all this, the while loop has executed 6 times, so the variable nc should become 6.
Why am I getting 4 as the value of nc, rather than 6.
Adding some output will help you:
#include <stdio.h>
int
main (void)
{
int c, nc = 0;
while ((c = getchar ()) != EOF)
{
++nc;
printf ("Character read: %02x\n", (unsigned) c);
}
printf ("Number of chars: %d\n", nc);
}
The Windows console views the ^Z input as "send input before ^Z to stdin, discard remaining input on the line (including the end-of-line delimiter), and send ^Z" unless it is at the beginning of a line, in which case it sends EOF instead of ^Z:
123^Z45
Character read: 31
Character read: 32
Character read: 33
Character read: 1a
^Z12345
Number of chars: 4
Also, Windows always waits for the Enter/Return key, with the exception of very few key sequences like ^C or ^{Break}.
^Z, or Ctrl-Z, means end-of file for text files (old MS-DOS). getchar() is equivalent to fgetc(stdin) and is often a macro. "fgetc returns the character read as an int or returns EOF to indicate an error or end of file."
See also _set_fmode, however, I am not sure if that changes the behaviour right away or whether you have to close/reopen the file. Not sure either if you can close/reopen stdin (don't do much console programming anymore).

It seems I must first press enter before getchar() gets EOF

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?
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.
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.
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;

`getchar()` gives the same output as the input string

I am confused by a program mentioned in K&R that uses getchar(). It gives the same output as the input string:
#include <stdio.h>
main(){
int c;
c = getchar();
while(c != EOF){
putchar(c);
c = getchar();
}
}
Why does it print the whole string? I would expect it to read a character and ask again for the input.
And, are all strings we enter terminated by an EOF?
In the simple setup you are likely using, getchar works with buffered input, so you have to press enter before getchar gets anything to read. Strings are not terminated by EOF; in fact, EOF is not really a character, but a magic value that indicates the end of the file. But EOF is not part of the string read. It's what getchar returns when there is nothing left to read.
There is an underlying buffer/stream that getchar() and friends read from. When you enter text, the text is stored in a buffer somewhere. getchar() can stream through it one character at a time. Each read returns the next character until it reaches the end of the buffer. The reason it's not asking you for subsequent characters is that it can fetch the next one from the buffer.
If you run your script and type directly into it, it will continue to prompt you for input until you press CTRL+D (end of file). If you call it like ./program < myInput where myInput is a text file with some data, it will get the EOF when it reaches the end of the input. EOF isn't a character that exists in the stream, but a sentinel value to indicate when the end of the input has been reached.
As an extra warning, I believe getchar() will also return EOF if it encounters an error, so you'll want to check ferror(). Example below (not tested, but you get the idea).
main() {
int c;
do {
c = getchar();
if (c == EOF && ferror()) {
perror("getchar");
}
else {
putchar(c);
}
}
while(c != EOF);
}
Strings, by C definition, are terminated by '\0'. You have no "C strings" in your program.
Your program reads characters (buffered till ENTER) from the standard input (the keyboard) and writes them back to the standard output (the screen). It does this no matter how many characters you type or for how long you do this.
To stop the program you have to indicate that the standard input has no more data (huh?? how can a keyboard have no more data?).
You simply press Ctrl+D (Unix) or Ctrl+Z (Windows) to pretend the file has reached its end.
Ctrl+D (or Ctrl+Z) are not really characters in the C sense of the word.
If you run your program with input redirection, the EOF is the actual end of file, not a make belief one
./a.out < source.c
getchar() reads a single character of input and returns that character as the value of the function. If there is an error reading the character, or if the end of input is reached, getchar() returns a special value, represented by EOF.
According to the definition of getchar(), it reads a character from the standard input. Unfortunately stdin is mistaken for keyboard which might not be the case for getchar. getchar uses a buffer as stdin and reads a single character at a time. In your case since there is no EOF, the getchar and putchar are running multiple times and it looks to you as it the whole string is being printed out at a time. Make a small change and you will understand:
putchar(c);
printf("\n");
c = getchar();
Now look at the output compared to the original code.
Another example that will explain you the concept of getchar and buffered stdin :
void main(){
int c;
printf("Enter character");
c = getchar();
putchar();
c = getchar();
putchar();
}
Enter two characters in the first case. The second time when getchar is running are you entering any character? NO but still putchar works.
This ultimately means there is a buffer and when ever you are typing something and click enter this goes and settles in the buffer. getchar uses this buffer as stdin.

Resources