Why is the scanf() skipped? - c

#include <stdio.h>
int main() {
char opt;
scanf(" %c", &opt);
switch (opt) {
case 'A':
printf("Please Enter a New Name:");
char name[200];
scanf("%[^\n]s", name);
printf("Please Enter a New Code:");
char code[200];
scanf("%s", code);
printf("Please Enter the Number:");
int number;
scanf("%d", number);
printf("%s\n%s\n%d", name, code, number);
printf("\nPlease press Enter to confirm Creation");
}
}
Why is the scanf of the name skipped? the output looks like
A
Please Enter a New Name:Please Enter a New Code:
Also when switch() is removed, it works normally. Is the problem on the switch()? It does not have other cases because it is an unfinished code.

As commented by melonduofromage, your first scanf leaves the newline (\n) typed by the user after the A in the input stream. Next scanf("%[^\n]s", name) fails because the first byte from the input stream is a newline, so scanf returns immediately with a return value of 0, which you should not ignore. The program then prompts for the code and scanf skips initial white space, including the pending newline and waits for user input.
To fix this problem, add a space before the conversion specifier to skip initial white space. You should also limit the number of characters stored into the destination array: specify this number between the % and the [. Note also that the trailing s in "%[^\n]s" is useless: it is not part of the conversion specifier and scanf() will try and match it against the input stream. The correct format is scanf(" %199[^\n]", name) and the return value must be 1 for a successful conversion.
Also note that there is a missing & in scanf("%d", number): you must pass the address of the destination variable: scanf("%d", &number);
Here is a modified version:
#include <stdio.h>
int invalid_input(void) {
fprintf(stderr, "invalid or missing input\n");
return 1;
}
int main() {
char opt;
if (scanf(" %c", &opt) != 1)
return invalid_input();
switch (opt) {
case 'A':
printf("Please Enter a New Name:");
char name[200];
if (scanf(" %199[^\n]", name) != 1)
return invalid_input();
printf("Please Enter a New Code:");
char code[200];
if (scanf("%199s", code) != 1)
return invalid_input();
printf("Please Enter the Number:");
int number;
if (scanf("%d", &number) != 1)
return invalid_input();
printf("%s\n%s\n%d", name, code, number);
printf("\nPlease press Enter to confirm Creation");
//...
}
return 0;
}

When you prompt user with the first scanf here
char opt;
scanf(" %c", &opt);
When the user enters a character, say A, "A\n" is placed in the buffer, \n coming from the user hitting the return key. The scanf takes one character as requested with the " %c" format string, and leaves the \n on the buffer.
When the second scanf is executed as
printf("Please Enter a New Name:");
char name[200];
scanf("%[^\n]s", name);
the format string "%[^\n]s" requests it to read until a \n is encountered, mind you, your buffer already contains a \n as the first character, hence scanf returns without reading anything, still leaving the \n in the buffer.
When the third scanf is executed as:
printf("Please Enter a New Code:");
char code[200];
scanf("%s", code);
(Corrected after the comments of chqrlie)
The format string "%s" ignores the leading whitespaces, hence now the \n is ignored, and scanf happily waits for your input.
Notice the leading space in the format string " %c", the space is there to get scanf ignore the leading whitespace, you can implement the same logic with your second scanf. You can either ensure that all consecutive scanf ignore the \n left in the buffer, which turns out most format specifiers do, or you can ensure that no scanf leaves it to begin with with using something like "<...>%*c" to get rid of it. Though none of which are reliable and consistent methods, and as said countless times, scanf is not designed to perform such tasks like taking user input, and you should seek alternative methods.
Also, the s in "%[^\n]s" certainly doesn't do what you expect. man page of the scanf states that
An ordinary character (i.e., one other than white space or '%'). This character must exactly match the next character of input.
If it matches, scanf discards it and continues parsing according to the remaining format specifiers. If it doesn't, scanf stops there and returns. Since it is at the end of your format string, it returns either way, hiding a potential bug from you.

Related

Why is fgets waiting for input before it's even called?

I'm trying to write a simple program to read an integer and then a string, then print both to standard output. Ideally, the execution should look something like this:
Input the number.
> 10
Input the string.
> a string
number: 10
string: a string
However, when I run the program, it freezes after the call to scanf() until more input is provided.
Input the number.
> 10
a string
Input the string.
>
number: 10
string: a string
Why is it waiting for input before fgets() is ever called?
#include <stdio.h>
int main()
{
int number;
char string[32];
printf("Input the number.\n> ");
scanf("%d\n", &number);
printf("\nInput the string.\n> ");
fgets(string, 32, stdin);
printf("\nnumber: %d\nstring: %s\n", number, string);
}
From a previous post...
https://stackoverflow.com/a/5918223/2203541
#include <stdio.h>
int main()
{
int number;
int c;
char string[32];
printf("Input the number.\n> ");
scanf("%d", &number);
do
{
c = getchar();
} while (c != '\n');
printf("\nInput the string.\n> ");
fgets(string, 32, stdin);
printf("\nnumber: %d\nstring: %s\n", number, string);
}
"Why is fgets waiting for input before it's even called"
fgets() does not act until it is called, but if when called, and if pointing to stdin and there is content remaining in the stdin stream, it will consume it immediately. If that contents contained EOF, n-1, OR a newline (read link) execution flow will continue.
The problem here is that scanf() (called prior to fgets()) is notorious for doing exactly what it is asked to do. For example, upon user entering 12<return> two recognizable items are entered into stdin, digits and a newline but by using "%d" as the format specifier, only the first of those items is consumed, leaving the \n hanging, until the very next call to fgets(), which accepts it as input, allowing execution flow to resume immediately (as described above), causing the apparent skip you are seeing.
[This is one (of several) examples that will provide a work around for the scanf() issue:
Change this:
printf("Input the number.\n> ");
scanf("%d", &number);//leaves the newline
To this:
char c;
...
printf("Input the number.\n> ");
scanf("%d%c", &number, &c);//consumes the newline
From comments:
"is there a way to use fgets to read an integer"
Yes, I prefer fgets() coupled with your favorite string to number converter. (There are several) The simplest is this:
char cNum[10];
int num;
printf("Input the number.\n> ");
if(fgets(cNum, sizeof cNum, stdin))
{
num = atoi(cNum);
}
else //handle error
See also strtol() for a more robust solution.
Alright, so I played around with it some more and did a little more studying on scanf() format syntax, and figured out a solution. Apparently, putting the whitespace character at the end of my scanf call there tells it to keep reading until it finds something AFTER the whitespace, so of course it would hang up there until you give more input.
Remove the whitespace character in the scanf formatter, and add a leading space to the following scanf call.
The reason I had used fgets originally was so I could specify a buffer length to avoid overflow. Apparently, the same effect can be achieved using %32s in the scanf call. The fixed code looks like this:
#include <stdio.h>
int main()
{
int number;
char string[32];
printf("Input the number.\n> ");
scanf("%d", &number);
printf("\nInput the string.\n> ");
scanf(" %32s", &string);
printf("\nnumber: %d\nstring: %s\n", number, string);
}

why scanf("%[^\n]", mystring) failed to take input string containing space on linux? [duplicate]

I have the following program:
int main(int argc, char *argv[])
{
int a, b;
char c1, c2;
printf("Enter something: ");
scanf("%d", &a); // line 1
printf("Enter other something: ");
scanf("%d", &b); // line 2
printf("Enter a char: ");
scanf("%c", &c1); // line 3
printf("Enter another char: ");
scanf("%c", &c2); // line 4
printf("Done"); // line 5
system("PAUSE");
return 0;
}
As I read in the C book, the author says that scanf() left a newline character in the buffer, therefore, the program does not stop at line 4 for user to enter the data, rather it stores the new line character in c2 and moves to line 5.
Is that right?
However, does this only happen with char data types? Because I did not see this problem with int data types as in line 1, 2, 3. Is it right?
The scanf() function skips leading whitespace automatically before trying to parse conversions other than characters. The character formats (primarily %c; also scan sets %[…] — and %n) are the exception; they don't skip whitespace.
Use " %c" with a leading blank to skip optional white space. Do not use a trailing blank in a scanf() format string.
Note that this still doesn't consume any trailing whitespace left in the input stream, not even to the end of a line, so beware of that if also using getchar() or fgets() on the same input stream. We're just getting scanf to skip over whitespace before conversions, like it does for %d and other non-character conversions.
Note that non-whitespace "directives" (to use POSIX scanf terminology) other than conversions, like the literal text in scanf("order = %d", &order); doesn't skip whitespace either. The literal order has to match the next character to be read.
So you probably want " order = %d" there if you want to skip a newline from the previous line but still require a literal match on a fixed string, like this question.
Use scanf(" %c", &c2);. This will solve your problem.
Another option (that I got from here) is to read and discard the newline by using the assignment-supression option. To do that, we just put a format to read a character with an asterisk between % and c:
scanf("%d%*c",&a); // line 1
scanf("%c%*c",&c1); // line 3
scanf will then read the next char (that is, the newline) but not assign it to any pointer.
In the end, however, I would second the FAQ's last option:
Or, depending on your requirements, you could also forget about scanf()/getchar(), use fgets() to get a line of text from the user and parse it yourself.
To echo what I have posted in another answer about C++: I suggest to toss scanf() away, to never use it, and to instead use fgets() and sscanf().
The reason for this is, that at least in Unix-like systems by default, the terminal your CLI program runs on does some processing of the user input before your program sees it. It buffers input until a newline is entered, and allows for some rudimentary line editing, like making backspace work.
So, you can never get a single character at a time, or a few single characters, just a full line. But that's not what e.g. scanf("%d") processes, instead it processes just the digits, and stops there, leaving the rest buffered in the C library, for a future stdio function to use. If your program has e.g.
printf("Enter a number: ");
scanf("%d", &a);
printf("Enter a word: ");
scanf("%s", word);
and you enter the line 123 abcd, it completes both scanf()s at once, but only after a newline is given. The first scanf() doesn't return when a user has hit space, even though that's where the number ends (because at that point the line is still in the terminal's line buffer); and the second scanf() doesn't wait for you to enter another line (because the input buffer already contains enough to fill the %s conversion).
This isn't what users usually expect!
Instead, they expect that hitting enter completes the input, and if you hit enter, you either get a default value, or an error, with possibly a suggestion to please really just give the answer.
You can't really do that with scanf("%d"). If the user just hits enter, nothing happens. Because scanf() is still waiting for the number. The terminal sends the line onward, but your program doesn't see it, because scanf() eats it. You don't get a chance to react to the user's mistake.
That's also not very useful.
Hence, I suggest using fgets() or getline() to read a full line of input at a time. This exactly matches what the terminal gives, and always gives your program control after the user has entered a line. What you do with the input line is up to you, if you want a number, you can use atoi(), strtol(), or even sscanf(buf, "%d", &a) to parse the number. sscanf() doesn't have the same mismatch as scanf(), because the buffer it reads from is limited in size, and when it ends, it ends -- the function can't wait for more.
(fscanf() on a regular file can also be fine if the file format is one that supports how it skims over newlines like any whitespace. For line-oriented data, I'd still use fgets() and sscanf().)
So, instead of what I had above, use something like this:
printf("Enter a number: ");
fgets(buf, bufsize, stdin);
sscanf(buf, "%d", &a);
or, actually, check the return value of sscanf() too, so you can detect empty lines and otherwise invalid data:
#include <stdio.h>
int main(void)
{
const int bufsize = 100;
char buf[bufsize];
int a;
int ret;
char word[bufsize];
printf("Enter a number: ");
fgets(buf, bufsize, stdin);
ret = sscanf(buf, "%d", &a);
if (ret != 1) {
fprintf(stderr, "Ok, you don't have to.\n");
return 1;
}
printf("Enter a word: ");
fgets(buf, bufsize, stdin);
ret = sscanf(buf, "%s", word);
if (ret != 1) {
fprintf(stderr, "You make me sad.\n");
return 1;
}
printf("You entered %d and %s\n", a, word);
}
Of course, if you want the program to insist, you can create a simple function to loop over the fgets() and sscanf() until the user deigns to do what they're told; or to just exit with an error immediately. Depends on what you think your program should do if the user doesn't want to play ball.
You could do something similar e.g. by looping over getchar() to read characters until a newline after scanf("%d") returned, thus clearing up any garbage left in the buffer, but that doesn't do anything about the case where the user just hits enter on an empty line. Anyway, fgets() would read until a newline, so you don't have to do it yourself.
Use getchar() before calling second scanf().
scanf("%c", &c1);
getchar(); // <== remove newline
scanf("%c", &c2);
Two workarounds. One is catch the extra whitespace trickly.
getchar(); // (1) add `getchar()`
scanf("%c", &c1);
scanf(" %c", &c1); // (2) add whitespace before %c
The other is using fgets() to instead scanf(). Note: gets() is unsafe, see why gets is dangerous
By contrast, I would prefer to recommend the second way. Because it's more readable and maintainable. For example, in first way, you must think a while before adding/moving some scanf().
/*Take char input using scanf after int input using scanf just use fflush(stdin) function after int input */
#include<stdio.h>
#include<conio.h>
void main()
{
int x;
char y;
clrscr();
printf(" enter an int ");
scanf("%d",&x);
fflush(stdin);
printf("\n Now enter a char");
scanf("%c",&y);
printf("\n X=%d and Y=%c",x,y);
getch();
}

Regarding structures in C

If I try to run this code then it doesn't ask me the value of s2.name. Why is it so?
#include<stdio.h>
int main()
{
struct student
{
char name;
int roll;
int age;
};
struct student s1;
struct student s2;
printf("Enter name of the student: ");
scanf("%c", &s1.name);
printf("%c", s1.name);
printf("\n");
printf("Enter name of the student: ");
scanf("%c", &s2.name);
printf("%c", s2.name);
return 0;
}
When you input a single character and press the Enter key, you are actually inputting two characters: The character in your input and a newline from the Enter key.
The second scanf reads this newline.
Or if you give multiple characters as input to the first name, then the second character will be read by the second scanf.
The way to solve the first problem is easy: Tell scanf to read and discard leading white-space (which newline is) by adding a single space in front of the format, like
scanf(" %c", &s2.name);
// ^
// Note space here
The way to solve the second problem is to read strings instead, which means you have to turn your name members into arrays and then use the "%s" format (preferably with a specified width so you don't read to many characters).
You are basically inputting two characters:
- the one that you type
- the newline character `\n` because you hit `enter`
A solution to this problem is clearing stdin after reading in the first "name":
#include<stdio.h>
int main()
{
struct student
{
char name;
int roll;
int age;
};
struct student s1;
struct student s2;
printf("Enter name of the student: ");
scanf("%c", &s1.name);
printf("%c", s1.name);
printf("\n");
fflush(stdin); //only works on windows, clears the input buffer
printf("Enter name of the student: ");
scanf("%c", &s2.name);
printf("%c", s2.name);
return 0;
}
Another way to clear the input buffer is:
while (getchar() != '\n');
This reads in all characters from the input buffer, because as soon as input is read by functions like getchar() or scanf(), the input is removed from stdin.
EDIT:
When you input values using getchar(), scanf(), etc., then the symbols that you type into stdin (most of the times via a keyboard) are stored in the input buffer at first (stdin). getchar() or any similar function then takes the values that it should read in, out of the input buffer. For example:
scanf("%d", &var);
scanf("%d", &var2);
If I input 5x, the characters in the input buffer are '5', 'x' and \n (because you hit the enter key). The first scanf() then takes out the '5', as it fits the format string %d. After that, the characters in the input buffer are 'x' and \n. In this case scanf returns 1, because it read in one value correctly.
When it then continues to the second one, scanf() won't even let you type anything, as there is already something in the input buffer stdin. It won't store any data however, because the first "item" in stdin ist 'x'. That doesn't fit the format string %d. The compiler then doesn't continue to read. In this case scanf would return 0, as no value was read in correctly.

char Input in C by scanf

Help me Please.
I want to know why it happen.
This code is not give right answer:
#include < stdio.h>
int main()
{
char c,ch;
int i;
printf("Welcome buddy!\n\nPlease input first character of your name: ");
scanf("%c",&c);
printf("\nPlease input first character of your lovers name: ");
scanf("%c",&ch);
printf("\nHow many children do you want? ");
scanf("%d",&i);
printf("\n\n%c loves %c and %c want %d children",c,ch,c,i);
return 0;
}
but this code give right answer.
#include < stdio.h>
int main()
{
char c,ch;
int i;
printf("Welcome buddy!\n\nPlease input first character of your name: ");
scanf(" %c",&c);
printf("\nPlease input first character of your lovers name: ");
scanf(" %c",&ch);
printf("\nHow many children do you want? ");
scanf("%d",&i);
printf("\n\n%c loves %c and %c want %d children",c,ch,c,i);
return 0;
}
Why?
and How?
Please help me anyone who know this why it happend.
While you are giving like this, It will not ignore the white spaces.
scanf("%c",&ch);
When you are giving the input to the first scanf then you will give the enter('\n'). It is one character so it will take that as input to the second scanf. So second input will not get input from the user.
scanf(" %c",&ch);
If you give like this, then it will ignore that white space character, then it will ask for the input from the user.
The first program doesn't work properly, because the scanf function when checking for input doesn't remove automatically whitespaces when trying to parse characters.
So in the first program the value of c will be a char and the value of ch will be the '\n' (newline) char.
Using scanf("\n%c", &varname); or scanf(" %c", &varname); will parse the newline inserted while pressing enter.
The scanf function reads data from standard input stream stdin.
int scanf(const char *format, …);
The white-space characters in format, such as blanks and new-line characters, causes scanf to read, but not store, all consecutive white-space characters in the input up to the next character that is not a white-space character.
Now, when you press, by example, "a" and "return", you have two chars in the stdin stream: a and the \n char.
That is why the second call to scanf assign the \n char to ch var.
your scanf() function takes input from stdin. Now when you hit any character from keyboard and hit enter, character entered by you is scanned by scanf() but still enter is present in stdin which will be scanned by scanf() below it. To ignore white spaces you have to use scanf() with " %c".

scanf anomaly with %c and %s related behaviour

I need to use scanf to get a character and a string which would store the user's answer. (yes/no)
The code below skips scanf("%c", &elem).
while ( !strcmp ("yes", option))
{
printf("enter the elements \n\n");
elem=getchar();
printf("you have entered %c\n",elem);
enqueue(st, elem);
printf("please enter yes or no ");
scanf("%s[^\n]",option);
}
./out
enter the elements
a
you have entered a
enqueue elem= a
please enter yes or no yes
enter the elements
you have entered
enqueue elem=
You don't have any scanf("%c", &elem) in your code... btw the problem is with the enter for scanf. When you get an input by scanf, an enter character stays in the input buffer which will be read by your getchar() function in the second round. one simple way to solve it is to add a dummy getchar after your scanf line:
while ( !strcmp ("yes",option))
{
printf("enter the elements \n\n");
elem=getchar();
printf("you have entered %c\n",elem);
enqueue(st,elem);
printf("please enter yes or no ");
scanf("%s[^\n]",option);
getchar();
}
You can find more information about how to clear your input buffer here: How to clear input buffer in C?
I can recommend you consider two things:
For getting only a character, I personally found it much more easier to use getch and getche function in Windows, and equivalent of them for GCC-compatible environments. You can find samples of it online or on this line [What is Equivalent to getch() & getche() in Linux?
Always flush the input buffer after you read your input to prevent any similar problems to happen.
The input functions check the input buffer, which you can find at 0xb8000000, and check the first input there. If the buffer is empty, they wait for the user to enter the input, otherwise, they check the first element in the buffer and then examine that to what they expect to read. If they succeed, they read it and remove it from buffer. Otherwise, they fail to give you your input and depending on the function, the result is different.
For Example, consider the following line:
scanf("%d %d %f", &a, &b &c);
and give the input as:
a 2 4
The scanf will return 0, which means it reads zero inputs so 'a', 2, and 4 remains in your buffer. So your buffer looks like: [a, 2, 4]. As a result if you add the following line:
scanf("%c", &ch);
scanf will try to get a character from the buffer, and it reads character 'a' and put it in variable ch. So it doesn't get any input from user. And you end up with having 2 and 4 on your buffer again.
When you are pressing Enter/Return key to enter the element then a \n character is also passed to the buffer along with the element. This \n is read by your getchar on next call.
To consume this \n place this line after the getchar();
int ch;
while((ch = getchar()) != EOF && ch != '\n');
Take care mixing scanf() format specifiers "%c", "%s" and "%[]".
Correct usage of "%[^\n]": there is no s. If leading whitespace in not wanted to be saved, include a leading space as in " %[^\n]"
char option[100];
// scanf("%s[^\n]", option);
scanf(" %[^\n]", option);
// or better
scanf(" %99[^\n]", option);
// or pedantic
switch (scanf(" %99[^\n]", option)) {
case EOF: HandleEOForIOError(); break;
case 0: HandleNoData(); break; // might not be possible here.
case 1: HandleSuccess();
Correct usage of "%c". If leading whitespace in not wanted to be save, include a leading space as in " %c". This may be the case in OP's code so the preceding inputs Enter or '\n' is consumed.
char elem;
scanf(" %c", &elem);
Correct usage of "%s". Leading whitespace is not saved with or without a leading space.
char option[100];
scanf("%99s", option);
// Following works the same.
scanf(" %99s", option);

Resources