I have been going through The C Programming Language by Brian W. Kernighan and Dennis M. Ritchie and am at Character Input and Output, specifically on File Copying. The example in the book
#include <stdio.h>
int main(void)
{
int c;
c = getchar();
while (c != EOF)
{
putchar(c);
c = getchar();
}
return 0;
}
works perfectly.
But I decided to put my own spin on things and rewrite it a bit:
#define <stdio.h>
int main(void)
{
int c;
printf("Please enter a digit: ");
c = getchar();
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
printf("Please enter a digit: ");
c = getchar();
}
return 0;
}
After compiling and executing, the result of my code is:
Please enter a digit: 9
The digit entered was: 9Please enter a digit: The digit entered was:
Please enter a digit: *cursor is here*
The input should be:
Please enter a digit: 9
The digit entered was: 9
Please enter a digit: *the cursor should be here*
Also, I have a little problem understanding EOF. It would be great if someone could help me with these issues.
Thank you!
Most 'terminals' do not send keyboard input to the program 'one key at at time'. Rather, the terminal will wait for the enter key, and then send all keys pressed (up to that point) to the target program. Hence, the question code suffers from getting newlines \n as input, as well as digits.
The code below throws away all non-digit values (but also allows for the EOF value):
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int c;
do {
c=0;
/* Get user input */
printf("Please enter a digit: ");
while(!isdigit(c) && EOF != c)
c = getchar();
/* Produce output. */
if(c == EOF)
printf("\n");
else
printf("The digit entered was: %c\n", c);
} while (c != EOF);
return 0;
}
Compile the above (Linux GCC example: gcc -Wall -o test *.c)
Then execute: (Linux example: ./test)
Please enter a digit: 5
The digit entered was: 5
Please enter a digit: 6
The digit entered was: 6
Please enter a digit: <CTRL-D>
<CTRL-D> usually generates an EOF condition.
Because the ENTER value "\n" (ASCII value 10) will be get by
getchar(c);
so it will do second time of
printf("The digit entered was: ");
printf("Please enter a digit: ");
Well, it's the trouble about the new-line character that you feed the standard input with while handing your piece into the console screen.
Let me ask you this:
With the code that you have said to work perfectly, you probably have tried some input like "Hello!" let's say, or maybe just a single character like "9" as in your example. You have typed down 'H' then 'e' then 'l' ... then '!' and then hit the enter-key, or just '9' and then hit the enter-key.
After that, you had the following on your screen:
Hello!
Hello!
_
The last underscore there is for indicating the flashing cursor. My question is: Why is it there? Why is it not right next to the last '!'?
Same story with the 9, this would be the things on your screen:
9
9
_
Well, here's why: It is because your programme has printed one more character that you cannot see directly, a new-line character '\n'. Proof: If it hadn't printed that, the underscore would flash next to the '!' or '9'.
When you hit your enter-key, you feed the standard input with a new-line character '\n' in addition to whatever you had typed down so far in that session. Standard input gets fed with all that and getchar(); consumes them one by one.
In your code which doesn't work as you had expected, you feed the standard input with '9' '\n', getchar(); first gets the '9' and then '\n', and then it looks for more, but there isn't any more. Only then (when there isn't more) it asks from you for more.
And that's the story...
To get what you were expecting, you should do something else, I won't tell you that directly, it's a good exercise. I can hint you that you should be using another while loop within the one you already have with a condition checking for a '\n' encounter.
EOF is just a special character, or rather a value indicating a special case of being at the End Of File. For standard input, I guess it can be issued with the CTRL + D key combination on Linux, it is CTRL + Z on Windows. Using that combination and then hitting enter should get you out of that outer loop.
You're being tripped up by a trailing newline in your input; when you type 9 and hit Enter, the input stream that your code reads from will contain the encodings for two characters, the 9 and a newline (in ASCII, it would be the sequence of values [57,10]) . Here's how it breaks down:
Code prompts you to enter a digit
You type 9 and hit Enter
Input stream now contains the characters {'9', '\n'};
getchar returns the next available character from the input stream, which is '9'
'9' is not equal to EOF, so you print the digit and prompt for the next character
getchar returns the next available character from the input stream, which is '\n'
'\n' is not equal to EOF, so you print the character and prompt for the next character
The input stream is now empty, so getchar blocks until you type something else.
You can fix this relatively easily:
#include <ctype.h>
...
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
printf("Please enter a digit: ");
do
{
c = getchar();
} while ( isspace( c ));
}
That last little do loop will read characters from the input stream until it sees something that isn't a newline or other whitespace character. You can add an additional check to make sure the character entered really was a digit [0-9]:
while (c != EOF)
{
printf("The digit entered was: ");
putchar(c);
do
{
printf("Please enter a digit: ");
do
{
c = getchar();
} while ( isspace( c ));
if ( !isdigit( c ))
printf( "%c is not a digit!\n" );
} while ( !isdigit( c ));
}
Now, something to be aware of; what you're storing in c is not the value 9, but the encoding for the character '9', which in ASCII is the integer value 57. If you want to store the value 9 in c, you'll have to do something different.
Related
While executing the small piece of code below, every time I enter a character, the output is repeated and I don't understand why. Can someone explain to me why is it behaving like this?
ps: Just started my programming journey in c.
If I print a character such as 'a' I'm supposed to have 1 as output then another prompt asking me to enter a character again. But I instead get the 1, a prompt, and a 1 again then another prompt asking me to enter a character.
#include <stdio.h>
int main()
{
int usr_ch;
for ( usr_ch = 0; (usr_ch != 'q');){
printf("Enter a single character: (enter 'q' to stop)\n");
usr_ch = getc(stdin);
printf("%d\n", (usr_ch != 'q') ? 1 : 0));
}
return 0;
}
input: u
output:
Enter a single character: (enter 'q' to stop)
1
Enter a single character: (enter 'q' to stop)
1
Enter a single character: (enter 'q' to stop)
You already have a great answer explaining the additional '\n' character generated when the user presses ENTER. Continuing from the comments below the question and comment by #AllanWard about the use of fgets(), it can provide the ability to take all single characters as input and end the input when ENTER alone is pressed. There are a number of other benefits as well.
When reading a line with fgets() you read the input into a buffer (character array or allocated block of memory). Don't skimp on buffer size... fgets() reads and includes the trailing '\n' in the buffer it fills. This means an entire line of input is consumed, including the trailing '\n' given a sufficiently sized buffer. The '\n' is not left in the input buffer (stdin) unread. This will avoid the problem you are experiencing.
To access the first character in the array, all you need do is derefernce the pointer. (an array is converted to a pointer to its first element on access, C18 Standard - 6.3.2.1(p3)). So if you declare char line[1024]; to hold the input, simply referencing *line provides access to the first character.
Using fgets() avoids all of the pitfalls new C programmers fall into using scanf() and eliminates the '\n' being left unread. These are the primary reasons new C programmers (as well as not so new C programmers) are encouraged to take all user input using fgets() (or POSIX getline() which behaves in the same manner, but can also provide auto-allocation to handle a string of any length)
In addition to taking the input, without much more effort you can ensure the user has only entered one-printable character with a few simple tests. This allows you to handle individual error cases as needed. A short example of the use of fgets() and handling several of the foreseeable error cases can be written as:
#include <stdio.h>
#include <ctype.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void)
{
char line[MAXC]; /* buffer to hold line */
/* prompt and then read input into line */
while (fputs ("Enter a single character: (enter alone to stop): ", stdout) &&
fgets (line, MAXC, stdin)) {
/* if ENTER alone, break */
if (*line == '\n') {
puts ("exiting");
break;
}
/* if not a single-character, handle error */
else if (line[1] != '\n') {
fputs (" error: more than 1 char entered.\n", stderr);
}
/* if printable character, output */
else if (isprint ((unsigned char)*line)) {
printf (" you entered '%c'\n", *line);
}
else { /* otherwise, handle error */
fputs (" error: non-printable character generated.\n", stderr);
}
}
}
(note: these are only a few examples of the classification test you can use. You are free to add or remove as many as you like. You can even provide a lookup-table for non-printable character and output a representation, e.g. '\t', when one is pressed, it's entirely up to you.)
Example Use/Output
The following exercises each of the covered error cases (the '\t' character is used for the non-printable character), e.g.
$ ./bin/fgets-char
Enter a single character: (enter alone to stop): a
you entered 'a'
Enter a single character: (enter alone to stop): b
you entered 'b'
Enter a single character: (enter alone to stop): q
you entered 'q'
Enter a single character: (enter alone to stop): Q
you entered 'Q'
Enter a single character: (enter alone to stop):
error: non-printable character generated.
Enter a single character: (enter alone to stop): foo
error: more than 1 char entered.
Enter a single character: (enter alone to stop):
exiting
There is absolutely nothing wrong with using getc() or fgetc() or getchar() for taking a single-character as input, but you must handle any additional characters that remain unread (including the trailing '\n'). Then what if the user presses ENTER twice in a row, or a cat steps on the keyboard generating 500 keypresses? That's where fgets() can help.
Another approach, unfortunately non-portable between different OS's, is to place the terminal in raw unbuffered (non-cannonical) mode where the input is processed immediately. For Linux you can use tcsetattr(). (you can also use setvbuf, see man 3 setbuf to switch between unbuffered, line-buffered or fully-buffered input) For Windows getch() can be used.
Worth exploring each as you continue your learning in C. Let me know if you have further questions.
stdin, by default, is line oriented when you enter "u\n" so getc() will first return u and in the next call \n.
In this case it is more natural to use a do-while-loop (or a for(;;) with a break at the end of the loop body). Then read a letter in a loop till you find one you like (i.e. not a \n). It's a good idea to handle EOF.
#include <stdio.h>
int main() {
int usr_ch;
do {
printf("Enter a single character: (enter 'q' to stop)\n");
while((usr_ch = getc(stdin)) && usr_ch == '\n');
printf("%d\n", usr_ch != 'q'));
} while(usr_ch != 'q' && usr_ch != EOF);
}
and here is example runs:
Enter a single character: (enter 'q' to stop)
a
1
Enter a single character: (enter 'q' to stop)
q
0
AYou can also just fgets() a line or use scanf(" %c", &usr_ch) to ignore leading white space.
I have this little program:
#include <stdio.h>
int main(){
int c;
while(c != EOF){
printf("Enter character\n");
c = getchar();
printf("Character: %c\n", c);
}
printf("FIN\n");
return 0;
}
The output of the terminal seems odd, because the while loop gets executed twice after a character was entered:
Enter character
a
Character: a //This should be the last output after a char was entered, but the loop gets executed a second time without waiting for a keyboard-input:
Enter character
Character:
Enter character
In the terminal I'm compiling and running the code like this:
gcc main.c
./a.out
What am I doing wrong?
Thanks for the answers, It's the lf entered by enter .... It's so obvious :D
You are entering 2 characters, the 'a' and a LF.
The while test is not made until both have been processed.
As soon as you press enter, a newline character gets added to the input stream. So your program actually reads two characters: a and \n. This newline character is read by getchar() and assigned to c in the second iteration and you can actually see it being printed as an empty line. Before printing c, you could use a break statement to get out of the loop: if (c == '\n') break;
If you enter abc, you will see the empty line is printed after c.
For starters your program has undefined behavior because you are using uninitialized variable c in the condition of the while loop
int c;
while(c != EOF){
//...
The function getchar also reads white space characters as for example the new line character '\n' that is placed in the buffer after pressing the Enter key.
Another problem is that you are checking the variable c after reading and outputting it
while(c != EOF){
printf("Enter character\n");
c = getchar();
printf("Character: %c\n", c);
}
Instead of getchar you should use scanf as for example
char c;
while ( scanf( " %c", &c ) == 1 )
{
//...
}
Pay attention to the blank before the conversion specifier %c. This blank means that white space characters will be skipped.
int main (int argc, char *argv [])
{
char a = 'v';
for (int i = 0; a != 'x'; )
{
printf("Enter 'a' : ");
scanf("%c",&a);
}
return 0;
}
I ran it and gave input k. When I hit enter after this , why my printf runs 2 times when loop runs second times?
To understand this behaviour, we can simulate step-by-step the execution.
printf("Enter 'a' : ");
scanf("%c",&a); // User type in example 'a' and presses enter.
scanf "bufferize" a\n and places in a the value 'a'
The loop condition isn't satisfied, since 'a' == 'x' is false
printf("Enter 'a' : ");
scanf("%c",&a); // The buffer still contains `'\n'`
Since the buffer still contains unconsumed data, the next character ('\n') is placed in a and the loop continues.
The loop condition isn't satisfied, since '\n' == 'x' is false
printf("Enter 'a' : ");
scanf("%c",&a); // The buffer is empty now.
This gives you the illusion that the loop displays twice the printf, but in fact, the scanf kept reading the buffer without the need of user input.
If you enter more characters, in example qwerty, "Enter 'a' : " will be displayed 7 times, because "qwerty" contains 6 characters + '\n'
Note that using while (a != 'x') would suit better your needs than for (int i = 0; a != 'x'; )
When you use scanf and %c, it reads any character -- including the newline character you get when you press the ENTER key.
So if you run the program and type
a <Return>
you take two trips through the loop: one to read the 'a' and one to read the '\n'. If you type
<Space> <Space> a <Return>
it makes four trips through the loop. And if you type
x <Return>
it only makes one trip through the loop, because it notices you typed the 'x', and exits.
Things will become a little more clear if you print out each character you receive:
for (int i = 0; a != 'x'; )
{
printf("Enter 'a' : ");
scanf("%c",&a);
printf("you typed %d = %c\n", a, a);
}
When you see it printing
you typed 10 =
that's one of the newlines. (The value of '\n' is 10 in ASCII.)
I said that %c reads any character -- but that's somewhat unusual. Most of scanf's other format specifiers -- %d, %f, %s, etc. -- skip over "whitespace" -- that is, spaces, tabs, newlines, and a few others. But %c does not skip over those, because its job is to read exactly one character, and someone thought you might want to use it to read whitespace characters, too.
For starters this loop
for (int i = 0; a != 'x'; )
does not make sense at least because the variable i is not used within the loop.
Also this prompt
printf("Enter 'a' : ");
only confuses users. You are asking the user to enter the character 'a' while the loop stops when the character 'x' is entered.
This call of scanf
scanf("%c",&a);
reads all characters including white-space characters. It is the reason why the loop iterates one more. You have to write
scanf( " %c", &c );
^^^
In this case white spaces will be skipped.
From the C Standard (7.21.6.2 The fscanf function)
5 A directive composed of white-space character(s) is executed by
reading input up to the first non-white-space character (which remains
unread), or until no more characters can be read
The program can look the following way
#include <stdio.h>
int main(void)
{
char c;
do
{
printf( "Enter a character ('x' - exit): " );
} while ( scanf( " %c", &c ) == 1 && c != 'x' );
return 0;
}
getchar() is not working in the below program, can anyone help me to solve this out. I tried scanf() function in place of getchar() then also it is not working.
I am not able to figure out the root cause of the issue, can anyone please help me.
#include<stdio.h>
int main()
{
int x, n=0, p=0,z=0,i=0;
char ch;
do
{
printf("\nEnter a number : ");
scanf("%d",&x);
if (x<0)
n++;
else if (x>0)
p++;
else
z++;
printf("\nAny more number want to enter : Y , N ? ");
ch = getchar();
i++;
}while(ch=='y'||ch=='Y');
printf("\nTotal numbers entered : %d\n",i);
printf("Total Negative Number : %d\n",n);
printf("Total Positive number : %d\n",p);
printf("Total Zero : %d\n",z);
return 0 ;
}
The code has been copied from the book of "Yashvant Kanetkar"
I think, in your code, the problem is with the leftover \n from
scanf("%d",&x);
You can change that scanning statement to
scanf("%d%*c",&x);
to eat up the newline. Then the next getchar() will wait for the user input, as expected.
That said, the return type of getchar() is int. You can check the man page for details. So, the returned value may not fit into a char always. Suggest changing ch to int from char.
Finally, the recommended signature of main() is int main(void).
That's because scanf() left the trailing newline in input.
I suggest replacing this:
ch = getchar();
With:
scanf(" %c", &ch);
Note the leading space in the format string. It is needed to force scanf() to ignore every whitespace character until a non-whitespace is read. This is generally more robust than consuming a single char in the previous scanf() because it ignores any number of blanks.
When the user inputs x and presses enter,the new line character is left in the input stream after scanf() operation.Then when try you to read a char using getchar() it reads the same new line character.In short ch gets the value of newline character.You can use a loop to ignore newline character.
ch=getchar();
while(ch=='\n')
ch=getchar();
When you using scanf getchar etc. everything you entered stored as a string (char sequence) in stdin (standard input), then the program uses what is needed and leaves the remains in stdin.
For example: 456 is {'4','5','6','\0'}, 4tf is {'4','t','f','\0'} with scanf("%d",&x); you ask the program to read an integer in the first case will read 456 and leave {'\0'} in stdin and in the second will read 4 and leave {''t','f',\0'}.
After the scanf you should use the fflush(stdin) in order to clear the input stream.
Replacing ch = getchar(); with scanf(" %c", &ch); worked just fine for me!
But using fflush(stdin) after scanf didn't work.
My suggestion for you is to define a Macro like:
#define __GETCHAR__ if (getchar()=='\n') getchar();
Then you can use it like:
printf("\nAny more number want to enter : Y , N ? ");
__GETCHAR__;
I agree that it is not the best option, but it is a little bit more elegant.
Add one more line ch = getchar();
between scanf("%d",&x); and ch = getchar();
then your code work correctly.
Because when you take input from user, in this time you press a new line \n after the integer value then the variable ch store this new line by this line of code ch = getchar(); and that's why you program crash because condition can not work correctly.
Because we know that a new line \n is also a char that's why you code crash.
So, for skip this new line \n add one more time ch = getchar();
like,
ch = getchar(); // this line of code skip your new line when you press enter key after taking input.
ch = getchar(); // this line store your char input
or
scanf("%d",&x);
ch = getchar(); // this line of code skip your new line when you press enter key after taking input.
pieces of code work correctly.
Currently im trying to learn simple C Programs. But, i came into this situation :
#include<conio.h>
#include<stdio.h>
void main()
{
char c;
int tryagain=1;
while(tryagain>0){
printf("Enter the Character : ");
scanf("%c",&c);
printf("You entered the character \"%c\" and the ascii value is %d",c,c);
getch();
clrscr();
tryagain=0;
printf("You want to Trry again Press 1 : ");
scanf("%d",&tryagain);
clrscr();
}
}
The program is fine when user first enter a character. And, when it ask to continue. And, user enter 1 then it is behaving weired. It automatically input blank character and prints the ascii and goto the same place.
How can i resolve this? And, specially, Why is the reason for this?
And, Im sorry about my poor english!
Thank you in Advance.
When you use
scanf("%d",&tryagain);
the number is read into tryagain but the newline character, '\n', is still left on the input stream. The next time you use:
scanf("%c",&c);
the newline character is read into the c.
By using
scanf("%d%*c",&tryagain);
the newline is read from the input stream but it is not stored anywhere. It is simply discarded.
The issue is that you are reading a single number in the second scanf, but user inputs more than a single number there, the user also input a new line character by pressing .
User enters "1\n". Your scanf reads "1", leaving out "\n" in the input stream. Then the next scanf that reads a character reads "\n" from the stream.
Here is the corrected code. I use getc to discard the extra new line character that is there.
#include <stdio.h>
void main()
{
char c;
int tryagain = 1;
while (tryagain > 0) {
printf("Enter a character: ");
scanf("%c", &c);
printf("You entered the character \"%c\" and the ascii value is %d\n", c, c);
tryagain = 0;
printf("If you want to try again, enter 1: ");
scanf("%d", &tryagain);
// get rid of the extra new line character
getc(stdin);
}
}
Also, as a side note, you use conio.h which is not part of standard C, it's MS-DOS header file, thus it's not portable C you are writing. I have removed it from my code, but you might wish to keep it.