C: Why does the "Enter" key trigger output in this code? - c

Here's my code for exercise 1-13 in "The C Programming Language":
#include <stdio.h>
int main()
{
int c, currentIndex, currentLength;
currentLength = currentIndex = 0;
while ((c = getchar()) != EOF){
if (c == '\t' || c == '\n' || c == ' '){
if (currentLength == 0){
continue;
}
printf("Length of word %d: ||", currentIndex);
for (int i = 0; i < currentLength; i++){
putchar('-');
}
putchar('\n');
currentLength = 0;
++currentIndex;
} else {
++currentLength;
}
}
return 0;
}
So I can compile this and run it with ./a.out, but when I press "Enter" to start a new line of input ('\n') it runs the printf() and putchar() functions(and neither ' ' or '\t' trigger the output). The while loop doesn't end (it ends as it should with END-OF-FILE(CTRL-D)) but I'm wondering why these functions are being called when they are. It prevents input of multiple lines at a time. Here's an example of it's output:
how long are these words
Length of word 0: ||---
Length of word 1: ||----
Length of word 2: ||---
Length of word 3: ||-----
Length of word 4: ||-----
Just to be clear, I ONLY get the output from printf() and putchar() when I press "Enter". CTRL-D just ends the loop and the program.

getchar() by default is in buffered mode, so the characters are not given to your program until enter is pressed. Duplicate of this question: How to avoid press enter with any getchar()

The ENTER releases the buffer.
Up until the ENTER the data is not available to your code. Your code gets all the characters at the same time.
The operating system is in charge of maitaining the buffer (you might be able to change this aspect of your OS).

in c, any output (unless specifically set otherwise) is buffered.
Nothing is output until one of the following occurs:
fflush() is called
a '\n' is output
the buffer is filled.
so you could add a call to flush() after the call to printf()
Note: there are other word separators that you should probably be looking for, other than tab, space, newline.
Suggest adding: single quotes, double quotes, period, colon, semicolon, left paren, left brace, right paren, right brace, back tick.

Related

Undefined behaviour of scanf() in a do-while loop

I'm currently learning C by a book "C Programming a modern approach" and encountered this code. When I tried to run it, after typing consecutive characters like 'abc' and hitting Enter (new line), nothing was printed. Please explain what is going on here.
char ch;
do {
scanf("%c" , &ch);
} while (ch != '\n');
printf("%c", ch);
You're asking the user to input a character using scanf. This is happening in a loop until the user inputs a '\n' or newline character (the same as pressing the enter key), which is when the loop will break.
Your print statement will then print the character in the variable ch, which at that point will be '\n' (since this variable just stores one character, the last one you typed).
This newline character will probably be invisible when you run your program so you may not be seeing it. You can add another print statement after the loop and if that print statement starts at a newline, you know that the '\n' was printed on the previous line.
Something like:
#include <stdio.h>
int main()
{
char ch;
do
{
scanf("%c" , &ch);
} while (ch != '\n');
printf("%c", ch);
printf("I should show up on a newline");
return 0;
}
The code you provided reads characters from the input using the scanf() function and stores them in the variable ch until a newline character (\n) is encountered. After that, the program prints the last character that was read, which is the newline character.
The reason you are not seeing any output when you enter characters followed by a newline character is because the printf() statement is only executed after the loop has finished running. So, the program is waiting for you to enter a newline character to terminate the loop and print the last character that was read.
If you want to see the characters you enter, you can add a printf() statement inside the loop, like this:
char ch;
do {
scanf("%c" , &ch);
printf("%c", ch);
} while (ch != '\n');
This will print out each character as it is read from the input, so you can see what you're typing. Happy coding :)
When I tried to run it, after typing consecutive characters like abc and hitting Enter (new line), nothing was printed.
Well with the posted code, if the loop even finishes, the last byte read by scanf("%c", &ch) and stored into ch is the newline character. Hence printf("%c", ch) outputs this newline and it seems nothing is printed but something is, the newline which is invisible on the terminal but does move the cursor to the next line.
You can make this more explicit by changing the printf call to this:
printf("last value: '%c'\n", ch);
Note however that the posted code is not a recommended way to read the contents of the input stream:
scanf("%c", &ch) may fail to read a byte if the stream is at end of file. Failure to test this condition leads to undefined behavior (ch is unmodified, hence stays uninitialized if the input stream is an empty file) or to an infinite loop as ch may never receive a newline.
this code is a typical example of a do / while with a classic bug. It would be much better to write the code using getchar() and a while loop.
Here is a modified version:
#include <stdio.h>
int main(void) {
int c; // must use int to distinguish EOF from all valid byte values
int count = 0; // to tell whether a byte was read at all
char ch = 0; // the last byte read
// read all bytes from the input stream until end of file or a newline
while ((c = getchar()) != EOF && c != '\n') {
ch = (char)c;
count++;
}
if (count == 0) {
printf("no characters entered: ");
if (c == EOF) {
printf("end of file or read error\n");
} else {
printf("empty line\n");
}
} else {
printf("last character on line is '%c'\n", ch);
if (c == EOF) {
printf("end of file or input error encountered\n");
}
}
return 0;
}

How can I stop scanning data on the keyboard when CTRL + D is pressed

I'm a newbie programmer. I have an assignment and I have some troubles about that. First of all my assignment is :
"Assume that you scan the input text in Turkish character by character from the keyboard, which you may think of as a default input device, until a ‘CTRL-D’ is pressed. You are supposed to skip punctuation characters as well as blank character. Your program will display the frequencies of letters and digits whenever the scanning process is done. You need to discuss the data structure as well as flowchart solution and hand in them with your code."
I did some research and found that the CTRL + D command corresponds to EOF. I wrote my code but it doesn't work as I want. Here is my code.
#include <stdio.h>
#include "stdlib.h"
#include <locale.h>
int main()
{
setlocale(LC_ALL, "Turkish");
char message[1000] = { ' ' };
char ch;
int i = 0;
printf("Please enter your message: ");
while (ch = getchar() != EOF )
{
message[i] = ch;
i++;
}
for (i; i >= 0; i--)
{
printf("%c", message[i]);
}
printf("\n\n");
system("PAUSE");
return 0;
}
When I run it, I write something and press ctrl + d, but as you can see in the picture, nothing happens. It just writes ^ D. Thank you for your help.
Ctrl-D corresponds to the integer character literal '\4' in C because A=1, B=2, C=3, D=4.
Your screenshot shows you're programming on Windows, so what you read about Ctrl-D being the same as EOF does not apply (it's a Unix/Linux/Mac thing).
To fix things, you need to read up until '\4' (or just 4; they are equivalent):
while ((ch = getchar()) != '\4')
{
message[i] = ch;
i++;
}
Note that you will still need to press your Enter or Return key for the line of text to be accepted, meaning you could type hello world^D what? i can still type? before hitting Enter to submit the text to your program. However, your program will stop reading at the ^D character, resulting in the message hello world being printed.
In the future, you might use something like printf("%d %c\n", message[i], message[i]); in a loop to print a list of the byte values you read.

Nonsensical output stream during the usage of "getchar()" and "EOF"

I have been experimenting with getchar(), putchar() and have been trying to use EOF. Below is the snippet of code I have been experimenting with.
#include <stdio.h>
int main(void)
{
int c;
c = getchar();
while(c != EOF)
{
putchar(c);
printf("\n");
printf("%d\n", EOF);
c = getchar();
}
return 0;
}
Input: -
a
Expected output: -
a //Due to putchar()
-1 //Value of EOF
//Now the cursor should come in next line and wait for next character.
Output getting in real time: -
a
-1
-1
//Cursor waiting for next character.
I am not able to comprehend the reason why the output is showing -1 two times.
Your code comment says
//Now the cursor should come in next line and wait for next character.
But the second loop doesn't wait. It reads the newline that was already entered, and this is shown by the extra blank line in the output.
After the first input before the loop
c = getchar();
the input buffer contains the new line character '\n' that corresponds to the pressed key Enter.
So in the while loop there are outputted
a
and
-1
due to the statement
printf("%d\n", EOF);
After that this statement in the loop
c = getchar();
reads the new line character that is present in the input buffer. So again this statement
printf("%d\n", EOF);
outputs
-1

Two EOF required to actually end reading from terminal

I have been trying to understand how EOF works. In my code (on Windows) invoking EOF (Ctrl+Z and Enter) doesn't work the first time and I have to provide two EOF for it to actually stop reading input. Also, the first EOF gets read as some garbage character which gets displayed when I print the input. (We can see the garbage characters being display at the end in the output provided).
This is my code:-
#include<stdio.h>
#define Max 1000
int main()
{
char c, text[Max];
int i = 0;
while((c = getchar()) != EOF)
{
text[i] = c;
i++;
}
printf("\nEntered Text: \n");
puts(text);
return 0;
}
My Output:
I have this doubt:-
Why are two EOFs being required? and how do I prevent the first one from being read (as some garbage) and stored as part of my input?
Control-Z is only recognized as EOF when at the start of a new line. Therefore, if you want to detect it in the middle of a line, you'll need to do so yourself.
So change this line:
while((c = getchar()) != EOF)
to this:
while((c = getchar()) != EOF && c != CTRL_Z)
and then add:
#define CTRL_Z ('Z' & 0x1f)
at the top of your program.
You may still need to type a return after the Ctrl-z to get the buffered input to be read by the program, but it should discard everything after the ^Z.
The following solution fixes the Ctrl+Z problem and the garbage output and also blocks a buffer overrun. I have commented the changes:
#include <stdio.h>
#define Max 1000
#define CTRL_Z 26 // Ctrl+Z is ASCII/ANSI 26
int main()
{
int c ; // getchar() returns int
char text[Max + 1] ; // +1 to acommodate terminating nul
int i = 0;
while( i < Max && // Bounds check
(c = getchar()) != EOF &&
c != CTRL_Z ) // Check for ^Z when not start of input buffer
{
text[i] = c;
i++;
}
text[i] = 0 ; // Terminate string after last added character
printf( "\nEntered Text:\n" );
puts( text );
return 0;
}
The reason for this behavior is somewhat arcane, but end-of-file is not the same as Ctrl-Z. The console generates an end-of-file causing getchar() to return EOF (-1) if and only if the console input buffer is empty, otherwise it inserts the ASCII SUB (26) character into the stream. The use of SUB was originally to do with MS-DOS compatibility with the even earlier CP/M operating system. In particular CP/M files were composed of fixed length records, so a ^Z in the middle of a record, was used to indicate the end of valid data for files that were not an exact multiple of the record length. In the console, the SUB is readable rather than generating an EOF if it is not at the start of the input buffer and all characters after the SUB are discarded. It is all a messy hangover from way-back.
Try changing the type of c to int as EOF can be a negative number and commonly it is defined as -1. char might or might not be able to store -1. Also, do not forget to end the string with \0 before passing it to puts.
The logic that Windows terminals follow with regard to ^Z in keyboard input (at least in their default configuration) is as follows:
The Ctrl-Z combination itself does not cause the input line buffer to get pushed to the waiting application. This key combination simply generates ^Z character in the input buffer. You have to press Enter to finish that line buffer and send it to the application.
You can actually keep entering additional characters after ^Z and before pressing Enter.
If the input line does not begin with ^Z, but contains ^Z inside, then the application will receive that line up to and including the first ^Z character (read as \x1A character). The rest of the input is discarded.
E.g. if you type in
Hello^Z World^Z123
and press Enter your C program will actually read Hello\x1A sequence. EOF condition will not arise.
If the input line begins with ^Z, the whole line is discarded and EOF condition is set.
E.g. if you input
^ZHello World
and press Enter your program will read nothing and immediately detect EOF.
This is the behavior you observe in your experiments. Just keep in mind that the result of getchar() should be received into an int variable, not a char variable.

Putchar and Getchar in C

I'm reading K&R's The C Programming Language and have become confused on putchar and getchar. I made a program where you enter 10 chars and the program prints them back out to the screen.
#include <stdio.h>
int main()
{
int i;
int ch;
for(i = 0; i < 10; i++)
{
printf("Enter a single character >> ");
ch = getchar();
putchar(ch);
}
return 0;
}
I expected to get an output like this:
Enter a single character >> a
a
Enter a single character >> b
b
...and so on 10 times but this is the output I got: (I stopped after entering 2 chars)
Enter a single character >> a
aEnter a single character >>
Enter a single character >> b
bEnter a single character >>
Enter a single character >>
not sure why my input character is being combined with the fixed string and being output.
Also, I'm not too sure why ints are used to store characters.
putchar(ch);
just prints single character and the following printf continues within the same line. Simply add:
putchar('\n');
right after putchar(ch);, which will explicitly start the new line before the printf is executed. Additionally you should also take '\n' from the input which stays there after you enter the character:
for(i = 0; i < 10; i++)
{
printf("Enter a single character >> ");
ch = getchar();
getchar(); // <-- "eat" new-line character
putchar(ch);
putchar('\n'); // <-- start new line
}
You are not printing a new line. After putchar(ch); you should use putchar('\n'); to print a new line.
User terminal can operate in canonical and non-canonical modes. By default it operates in canonical mode and this means that standard input is available to a program line-by-line (not symbol-by-symbol). In question user inputs something (let it be letter 'a', 0x61 in hex) and pushes enter (new line character '0x0A' in hex). Ascii table is here. So this action gives a two symbols to a program. As mentioned in man getchar() reads it symbol-by-symbol. So loop iterates twice for one character. To see what is going on use the following program (+loop counter output, +character code output):
#include <stdio.h>
#include <unistd.h>
int main()
{
int i;
char ch;
for(i = 0; i < 10; i++)
{
printf("Enter a single character %d >>", i);
ch = getchar();
printf("Ch=0x%08X\n", ch);
/*putchar(ch);*/
}
return 0;
}
Output:
┌─(02:01:16)─(michael#lorry)─(~/tmp/getchar)
└─► gcc -o main main.c; ./main
Enter a single character 0 >>a
Ch=0x00000061
Enter a single character 1 >>Ch=0x0000000A
Enter a single character 2 >>b
Ch=0x00000062
Enter a single character 3 >>Ch=0x0000000A
Enter a single character 4 >>^C
So program gets two symbols and prints them. And new line symbol is not visible. So in the question user see one strange additional line.
Detailed description on different terminal modes and how to make its adjustments can be found here.
Also stty utility can be useful while working with terminal options ("icanon" tells if terminal use canonical mode or not).
And about storing chars as int in getchar() output - see my answer for similar topic.
The term on which our focus should be on, is "Stream".
A "Stream" is a like a bridge, responsible for flow of data in a sequential way. (The harmony of smooth streaming, both in and out of a program, is managed by libraries/header files, e.g. stdio.h)
Coming back to your question :
When you type input as 'a' and hit 'enter', you supply 2 values to input stream.
- a (ASCII Value : 97)
- enter (ASCII Value : 13)
/*This 'enter' as an input is the devil. To keep it simple, i will keep calling it
as Enter below, and the enter is usually not displayed on screen*/
NOTE/IMPORTANT/CAUTION before proceeding: Till the time your stream doesn't get completely empty, you can't write new characters from the console into the stream. (This scenario only implies for the use of getchar and putchar, as shown below)
HERE IS YOUR CODE:
for(i = 0; i < 10; i++)
{
printf("Enter a single character >> ");
ch = getchar();
putchar(ch);
}
Loop Pass 1 :
a) You ask user to enter a character. // printf statement
b) getchar reads only a single character from stream.
c) putchar renders/displays only a single character from stream.
d) At first pass you provide input as 'a' but you also hit 'Enter'
e) Now, your stream is like a ***QUEUE***, at first pass, and at 1st place of
the queue, you have 'a' and at 2nd place 'enter'.
f) Once you do putchar, the first character , i.e. 'a' from the stream/queue
gets displayed.
e) Loop ends.
g) Output of this pass:
Enter a single character >>a
Loop Pass 2 :
a) You ask user to enter a character. // printf() statement
b) Unfortunately your stream isn't empty. It has an "enter" value from the
previous pass.
c) So, getchar(), reads the next single character, i.e. 'enter' from stream.
(This is where you were expecting to manually enter the next character,
but the system did it for you. Read the NOTE/IMPORTANT/CAUTION section
mentioned above)
d) putchar() displays 'enter' on screen, but since 'enter' is no displayable
thing, nothing gets displayed.
e) Output of this pass:
Enter a single character >>
Loop Pass 3 :
Similar as loop 1, only input this time is 'b'.
Loop Pass 4:
Similar as loop 2
and so on till 10 passes. (So, last character you will be able to enter is 'e'.)
INFERENCE/CONCLUSION:
So, long story short, you were expecting to enter the next character,
so that getchar would pick your entered value, but since from your
previous pass,'enter' value was already waiting in the stream,
it got displayed first, giving you such an illusion.
Thank you.
Let me know if your thoughts are different.
Loop on the even number of time, getchar() is not taking input from keyboard, but it is taken from the previous entered hit, so you would have also noticed that loop is only executed 5 times. So you have to clear the buffer, i.e. pressed entered, so that new character can be entered in the ch.
for (i = 0; i < 5; i++)
{
printf("\nEnter a single character >> "); // new line
ch = getchar();
while (getchar() != '\n'); //Clearung buffer.
putchar(ch);
}
Not sure if ideal, but this worked:
#include <stdio.h>
int main()
{
int i;
int ch;
for(i = 0; i < 10; i++)
{
printf("Enter a single character >> ");
getchar();
ch=getchar();
putchar(ch);
}
return 0;
}
I am a beginner . I tried this version of code and it gave the desired output.
#include <stdio.h>
int main()
{
int i;
int ch;
for(i = 0; i < 10; i++)
{
printf("Enter a single character >> ");
fflush(stdin);
ch = getchar();
putchar(ch);
printf("\n");
}
return 0;
}
Although getchar() gets a single character, control isn’t returned to your program until the user presses Enter. The getchar() function actually instructs C to accept input into a buffer, which is a memory area reserved for input. The buffer isn’t released until the user presses Enter, and then the buffer’s contents are released a character at a time. This means two things. One, the user can press the Backspace key to correct bad character input, as long as he or she hasn’t pressed Enter. Two, the Enter keypress is left on the input buffer if you don’t get rid of it.to Get rid of the Enter keypress insert an extra getchar() that captures the Enter but doesn’t do anything with it.so you just need an extra getchar() after ch = getchar();like this
#include <stdio.h>
#include <stdlib.h>
int main()
{ int i;
int ch;
for(i = 0; i < 10; i++)
{
printf("Enter a single character >> ");
ch = getchar();
getchar();
putchar(ch);
}
return 0;
}
I managed to get the desired result. I added a newline character and getchar() which picks up the extra character.
#include <stdio.h>
int main()
{
int i;
char ch;
for (i = 0; i < 10; i++)
{
printf("Enter a single character >> ");
ch = getchar();
putchar(ch);
putchar('\n');
getchar();
}
return 0;
}

Resources