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.
Related
Input
There will be several lines in the input terminated with a line containing a single *. This last line
should not be processed. Each of the lines will contain either Hajj or Umrah.
Output
For each line of the input, output either Hajj-e-Akbar or Hajj-e-Asghar in separate lines without
quotations. For the exact format refer to the sample.
Here's my code for this problem.
#include <stdio.h>
int main()
{
char str[100];
int i = 1;
while (scanf("%s", &str))
{
if (str[0] == '*')
break;
else if (str[0] == 'H')
printf("Case %d: Hajj-e-Akbar\n", i);
else
printf("Case %d: Hajj-e-Asghar\n", i);
i++;
}
}
For the input
Hajj
Umrah
*
When I gave this input at a time, the program provides the expected output by printing
Hajj
Case 1: Hajj-e-Akbar
Umrah
Case 2: Hajj-e-Asghar
*
But after getting * as input, the program is waiting for an Enter. After hitting Enter, the program terminates. But I want my program to terminate, whenever it gets * as input, not by pressing Enter. Please help me here. But this is not my question. My question is for the same input-
Hajj
Umrah
*
When I take input by scanf("%s\n", &str). The program does not print the output Case 1: Hajj-e-Akbar after the first input Hajj but it prints the output for first input after taking the second input Umrah. Then the program is waiting for an Enter for the input *.
The output is like this
Hajj
Umrah
Case 1: Hajj-e-Akbar
*
Then I press Enter, it prints the output Case 2: Hajj-e-Asghar for the second input Umrah
and then waits for another input. This the output looks like after pressing Enter.
Hajj
Umrah
Case 1: Hajj-e-Akbar
*
Case 2: Hajj-e-Asghar
I don't understand how \n is making a difference in scanf.
Thank you.
I'm sorry if I can't explain my question correctly. I am new to programming.
scanf reads formated input, so when you use %s\n”, &str the string will consumed and stored in str as will the newline character , which will be present in the buffer when you press enter, the string will be stored and the newline character will be discarded.
Note that the correct usage is “%s\n”, str, str is already a pointer you shouldn't use &.
When you use “%s”, &str the newline character will be left in the buffer and will be consumed in the next loop, so str will be stored in the first iteration, and "\n" will be stored in str in the next iteration, only then you will be asked for input again, in the third iteration.
For completion, as stated in the comments bellow, as per the definition of scanf:
...any single whitespace character in the format string consumes all available consecutive whitespace characters from the input (determined as if by calling isspace in a loop). Note that there is no difference between "\n", " ", "\t\t", or other whitespace in the format string.
I would also advise you to limit the size of the string expected by scanf to avoid container overflow, something like %99s for a 100 charaters container like you have, and also check scanf return, in this case, it must be = 1 for each cycle.
To do what you want, which I gather is to get a character from stdin without pressing return you will need a SO specific method, here is a small example for Windows using <conio.h> library, and getch():
#include <stdio.h>
#include <conio.h>
int main()
{
int i = 1, c;
while (1)
{
if ((c = getch()) == '*')
return 0;
else if (c == 'H')
printf("Case %d: Hajj-e-Akbar\n", i);
else
printf("Case %d: Hajj-e-Asghar\n", i);
i++;
}
}
For Linux one option is to use also getch() from <ncurses.h> library, which you might need to install.
PS: Don't worry, your question is well built, specially being only the second in the site.
The trailing \n in the scanf is a bad idea: any whitespace character in the format string causes any sequence of whitespace characters to be discarded from the input stream. If reading from a file, you will not necessary have a problem but if you read from the terminal, scanf() will not return until you have typed the next item, and this will create major confusion as you experience, because the program's output will correspond to the previous item, not the one that was just typed... Never add trailing spaces or newlines in a scanf() format string.
You should test if scanf() returns 1 to avoid an infinite loop when it returns EOF at the end of file.
Note also that it is incorrect to pass &str: str is an array, passing it as str will effectively pass a pointer to its first element, which is correct.
Furthermore, you should tell scanf() the maximum number of characters that can be stored into the destination array to avoid undefined behavior on overlong input. Since the array is defined with a size of 100, the format string should be "%99s" to leave space for the null terminator.
Finally, you need to hit Enter after the final * for 3 combined reasons, each of which would force this behavior:
the terminal device driver is line buffered by default, so the input is not made available to the program until you type Enter.
the standard input stream (stdin) is line buffered by default, so it will read data from the system handle until it gets a newline, and only then does scanf() get a chance to see the first character of the entered line.
scanf("%s", str) will keep its input stream until it gets the end of the word, a whitespace character or the end of file, so it does not return when you type just *.
Here is a modified version:
#include <stdio.h>
int main() {
char str[100];
int i = 1;
while (scanf("%99s", str) == 1 && str[0] != '*') {
if (str[0] == 'H') {
printf("Case %d: Hajj-e-Akbar\n", i);
} else {
printf("Case %d: Hajj-e-Asghar\n", i);
}
i++;
}
return 0;
}
I know that adding a space in front of %c in scanf() will scan my second character; however, if two letters were inputted in the first character, it will input the second letter into the second character. How do I scan a single character only?
#include <stdio.h>
int main(void)
{
char firstch, secondch;
printf("Enter your first character: ");
scanf("%c", &firstch);
printf("Enter your second character: ");
scanf(" %c", &secondch);
printf("\n Fisrt character : %c \n Second character : %c \n", firstch, secondch);
return 0;
}
This is my result after running:
Enter your first character: ab
Enter your second character:
First character : a
Second character : b
I only want to read the first character 'a', but the second letter 'b' was inputted right away before I enter my second character.
When you are reading a line of user-input, use a line-oriented input function like fgets() or POSIX getline(). That way the entire line of input is read at once and you can simply take the first character from the line. Say you read a line into the array used as buffer called buf, e.g.
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[MAXC]; /* buffer to read each line into */
You can simply access the first character as buf[0], or since buf[0] is equivalent to *(but + 0) in pointer notation, you can simply use *buf to get the first character.
As a benefit, since all line-oriented functions read and include the '\n' generated by the user pressing Enter after the input, you can simply check if the first character is '\n' as a way of indicating end-of-input. The user simply presses Enter alone as input to indicate they are done.
Using a line-oriented approach is the recommended way to take user input because it consumes and entire line of input each time and what remains in stdin unread doesn't depend on the scanf conversion specifier or whether a matching failure occurs.
Using " %c%*[^\n]" is not a fix-all. It leaves the '\n' in stdin unread. That's why you need the space before " %c". Where it is insidious is if your next input uses a line-oriented function after your code reading characters is done. Unless you manually empty the '\n' from stdin, before your next attempted line-oriented input, that input will fail because it will see the '\n' as the first character remaining in stdin.
A short example using fgets() for a line-oriented approach would be:
#include <stdio.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[MAXC]; /* buffer to read each line into */
for (;;) { /* loop continually */
fputs ("enter char: ", stdout); /* prompt for input */
/* read/validate line, break on EOF or [Enter] alone */
if (!fgets (buf, sizeof buf, stdin) || *buf == '\n')
break;
printf (" got: %c\n\n", *buf); /* output character read */
}
}
Where you simply take input continually isolating the first character as the value you want until the user presses Enter alone to break the read-loop.
Example Use/Output
$ ./bin/fgetschar
enter char: a
got: a
enter char: ab
got: a
enter char: a whole lot of stuff you don't have to deal with using fgets()
got: a
enter char: banannas
got: b
enter char: cantelopes
got: c
enter char:
Look things over and let me know if you have further questions.
Using a space before the %c will skip whitespace before scanning the next non-whitespace character. %c itself just scans a single character -- the next character in the input after whatever else was scanned or skipped previously.
So the question is, what do you want to do? Do you want to skip over all extraneous input on the line after the first character (up to newline?) fgets or scanf("%*[^\n]"); scanf("%c"); will do that (but be careful -- if firstch was itself a newline, this will skip the next line.) Do you want to check the input and make sure it is exactly one character on a line? If so, use fgets (not scanf) and check that the line read is exactly two characters (a character and a newline). Or perhaps you really want to read keystrokes without having the user hit Enter after esch one? That requires changing the input source setup, which is OS dependent.
I'm still new to C coding, and I've found a suitable answer to my problem by using scanf("%*[^\n]");
#include <stdio.h>
int main(void)
{
char firstch, secondch;
printf("Enter your first character: ");
scanf(" %c%*[^\n]", &firstch);
printf("Enter your second character: ");
scanf(" %c%*[^\n]", &secondch);
printf("\n First character : %c \n Second character : %c \n", firstch,
secondch);
return 0;
}
Results after running:
Enter your first character: ab
Enter your second character: c
First character : a
Second character : c
Thanks to #Eraklon #Chris Dodd #David C. Rankin
I'm going through lessons at S.Prata book: 'C Primer Plus'. Chapter 6, control question #8:
// Given the input Go west, young man!, what would each of the following
// programs produce for output? (The ! follows the space character in the
// ASCII sequence.)
#include <stdio.h>
int main(void) {
char ch;
scanf("%c", &ch);
while (ch != 'g') {
printf("%c", ch);
scanf("%c", &ch);
}
return 0;
}
The thing is... as far as I know %c in scanf should be used for a single character, not for a phrase like 'Go west, young man!'. Why this program read all the line and stores all of it (except last word), not only first character? Does it automatically store stuff in scanf as an array?
I thought it will print just 'G'... But it actually prints 'Go west, youn'. Why? It's not %s, but %c.
I suppose it could be because %c stores all input to 'char'.. but in specifications it said that it stores only single character, not several ones.
There is a loop, which has the scanf() in it's body
while ( ch != 'g' )
so, it keeps on reading the inputs present in the buffer, until it finds a 'g'.
So, for the input
'Go west, young man!'.
^---------------- here is the 'g'
It'll keep on reading the characters one by one, in each iteration till it reads the 'g' and encounters the exit criteria for the loop.
The character ch will never store a whole string, it only stores one character. The output you're getting is NOT given by a single printf execution, it's by multiple executions of printfs (The loop enters multiple times). You can confirm that by changing the code to:
#include <stdio.h>
int main(void)
{
char ch;
scanf("%c", &ch);
while (ch != 'g')
{
printf("PRINTING: %c\n", ch);
scanf("%c", &ch);
}
return 0;
}
Now, let's see why the loop enters multiple times.
You entered many characters in the scanf outside the loop, then in the loop you expect it to print the first character, which is totally correct. BUT, you think it will wait for the user input again, which is not correct. In the first scanf, when you entered multiple characters, it just read the first one. But there is somehow a hidden cursor in the stdin (standard input) that keeps track of what has been read. When you entered "Go west, young man!", the G is stored in ch and the cursor is put before the o. When you next call scanf, it will look at the cursor position and finds an o, so it won't wait for user input and just reads it. etc.
To summarize, I suspect your problem is that you misunderstand how scanf works. You think that it will always wait for user input whenever called. That is not the case, it may read from the previous input.
If you want the next scanfs to ignore the long first input, you should actually read it (or seek the stdin which will work in Windows but not Linux). Example:
#include <stdio.h>
int main(void)
{
char ch;
scanf("%c", &ch);
while (getchar() != '\n'); // Get to the end of the stdin.
// The previous line can be replaced with fseek(stdin, 0, SEEK_END); but it will work under Windows only.
while (ch != 'g')
{
printf("PRINTING: %c\n", ch);
scanf("%c", &ch);
}
return 0;
}
The program simply reads all characters one by one of the input.
So for an input such as
Go west, young man!
then the first call to scanf reads the single character 'G'. Then in the loop you print that single 'G', followed by reading the single character 'o'. Then in the next iteration of the loop you print the single character 'o' (that you read in the previous iteration) and then read the space ' '. And so on.
Also note that 'G' is not equal to 'g'. Character comparison is case-sensitive.
Here is something that confused me.
# include <stdio.h>
# include <limits.h>
int main()
{
int a;
int b;
printf("Enter two integers: ");
while(scanf("%d %d", &a, &b)!=2||b==0||a+b>INT_MAX||a*b>INT_MAX){
printf("Invalid entry, please re-enter: ");
while(getchar()=='\n');
}
printf("sum is %d, difference is %d, product is %lf, divid is %.2f, remainder is %d", a+b, a-b, (double)a*b, (float)a/b, a%b);
return 0;
}
With above code, if I enter "a 1" press ENTER:
Invalid entry, please re-enter:
pops up, then I enter "2 B" press ENTER, the last printf will execute.
However, if I change while(getchar()=='\n'); to while(getchar()!='\n');, and with the same entry (I enter "a 1" press ENTER)
Invalid entry, please re-enter:
pops up, then I enter "2 B" press ENTER), the last printf will not execute, and
Invalid entry, please re-enter:
pops up again.
What causes the difference here? How exactly do scanf and getchar work?
In the first case (while (getchar() == '\n');), the getchar() reads the a, but it isn't a newline, so the loop exits, leaving the space and the 1 in the input buffer. The repeated call to scanf() skips white space, reads 1, skips white space (newline included) and reads 2, leaving space and B in the input. Since the loop condition is now terminated (scanf() returned 2), the printf() is executed.
In the second case (while (getchar() != '\n');), this loop reads the a, the blank, the 1, and the newline before stopping. When you type 2 B, there aren't two numbers, so scanf() returns 1 and the main loop continues.
Note that your code will go into an infinite loop if you indicate EOF (usually Control-D on Unix, Control-Z on Windows) — at least, on most systems. You should always consider EOF. In context, you probably need something like:
int rc;
while (((rc = scanf(…)) != 2 && rc != EOF) || …)
You'd test rc against EOF before printing, too.
How do scanf and getchar work in C?
Sadly, they often do not work together well.
Code is a poor example of attempting to consume the rest of the input line when the input text is a problem.
If scanf("%d %d", &a, &b) failed to scan in 2 int, a prompt occurs and input is read with getchar until an Enter or '\n' happens.
If 2 int were scanned, various faulty tests are performed on a,b
// poor code
while(scanf("%d %d", &a, &b)!=2||b==0||a+b>INT_MAX||a*b>INT_MAX){
printf("Invalid entry, please re-enter: ");
while(getchar()=='\n');
}
The problem is that the code certainly intends to read a line of user input and then validate it. Unfortunately, scanf("%d %d" can consume multiple '\n' and leaves stdin with unclear contents when 2 int are not scanned. Code is an infinite loop on end-of-file.
Better to read a line of input with fgets(). Flushing stdout insures the prompt is seen before input is read.
char buf[80];
const char *prompt = "Enter two integers: ";
for (;;) {
fputs(prompt, stdout);
fflush(stdout);
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_EndOfFile_or_Error();
prompt = "Invalid entry, please re-enter: ";
int n;
if (sscanf(buf, "%d%d %n", &a, &b, &n) != 2) continue; // not 2 ints
if (buf[n]) continue; // extra text
if ((a < 0) ? (b < INT_MIN - a) : (b > INT_MAX - a)) continue; // + overflow
... // other tests
else break;
}
other tests
scanf() and getchar() read what is in the input buffer (stdin for standard input). When stdin is empty, the program will wait for the user to write something with the keyboard. When you press ENTER, the text you just wrote is stored in stdin. Then scanf() or getchar() can read something in stdin.
Notice that pressing ENTER will store a '\n' character (newline) in stdin.
A code like while( getchar() != '\n' ); is asking to getchar() to read one character from stdin while the character is not '\n'. It compares the return of getchar() with '\n'. So this is a way to "clean" the input buffer otherwise your program can go crazy.
EDIT
With the code you posted :
scanf() is called, you write "a 1", it tries to read a first integer but it is a character ('a') so it stops reading. printf() ask you to re-enter, then getchar() is called and reads the 'a'. Now scanf() is called a second time, reads the 1, then you have to enter something, you enter "2 B" so the second %d in scanf() can read the 2. Now the return of scanf() is 2, b is not 0 and the others conditions are false so the loop is ending. Notice that the 'B' character is still in stdin :)
I try to summarize what you need to know.
First, about your question. You do know the function of scanf is to read what the input (number) we give right? getchar on the other hand, is like scanf except that it is used for character/sentence only. You cannot use getchar to input number.
Second, there are no problem in your code except that it is okay not to use some line like that getchar line. It is also okay not to use while. Unless you want to make some condition, you may combine while with if / else function.
Third, you cannot input the number like you did: "1 a", "2 b". Those are considered invalid. This is because you are using %d in your scanf which refer to decimal number only. It means, you can input number 1-9 only and not the letters. So when the program asked to enter the 2 integers, you just type for example: 4 5. That's 4, space, 5. That is the correct way.
I want to write code that checks if the user enters correct input, i.e 1, 2, 3 or 4. Otherwise, the message "input error" is printed. If the user enters a letter for example, since the input variable in the scanf is char type, it works too.
But in the case of multiple characters, I throught about the following solution: I try to enter all the characters into a char array and to check how many members into it. I wrote the following code:
char option;
int countIn;
char inArray[10];
do { //while option!=4
scanf("%c", &option);
while (countIn < 10 && scanf("%c", &option) != -1 && option != '\n') {
inArray[countIn] = option;
countIn++;
}
if (countIn > 1) { option = 10; }
else { option = inArray[0]; }
countIn = 0;
} while (option != '4');
The problem is when I enter 1 for example, the program works well, but for the second loop iteration, the scanf doesn't work and the program does automatically the part 1 again and again.
what did I do wrong?
Replace both scanf() calls with:
scanf(" %c", &option);
Note the space in the format string, which tells scanf to consume all the whitespaces. The reason why it seems to skip is the newline left in the input buffer by previous input.
From scanf():
· A sequence of white-space characters (space, tab, newline,
etc.; see isspace(3)). This directive matches any amount of
white space, including none, in the input.
Note that even though EOF is typically defined as -1, it's not safe to assume so. I would strongly suggest to use EOF instead of -1.