scanf() is getting skipped - c

Hi
Just started learning c for uni (usually use objective c) and have run into a strange issue with scanf, i have the following code
while(stringCheck == 0){
scanf("%c",&computerType);
computerType = toupper(computerType);
if ( computerType == 'L') {
/*set stringCheck to 1 so the scanf while loop breaks*/
stringCheck = 1;
counter = 0;
} else {
printf("ERROR\n");
}
}
This i printing out "ERROR" then asking for input (so it is skipping the scanf statment the first time). If i change the it to another variable that is a string it works fine, it stops on the first time.
The rest of the code works fine, its just the fact that it print an error as soon as it enters the loop that is annoying.
I have tried getChar() and it does the same thing.
Thank you for any help you have to offer.

If it's printing an error the first time you enter the loop, then there's already something in the input buffer. I'll guarantee (assuming your compiler is not brain-dead) that it is not skipping the scanf. You should check what it's actually receiving by changing:
printf("ERROR\n");
to:
printf("ERROR, code = %02x\n", computerType);
I would suggest that it's the newline from the last time your program ran that code (you say it's the first time but it's unclear as to whether you mean the first time into that loop ever (since program started) or first time entering that loop but you've been through it before on this program run.
When you enter LENTER the first time, your code will pull out the L but not the ENTER. If you then call that code again, it will get the ENTER key.
You should either understand and allow for what's actually entered or use a safe and sound input function like this one.

You should always check the return value from scanf(); it tells you how many of the conversions succeeded. In this context, if you don't get back 1, you have a problem. The first time around the loop, scanf() reads a character - but not an ell (l or L) because you say you get an error message. The next iteration attempts to read the newline or whatever else follows the previous erroneous character, and the newline is certainly not an ell, and the other characters quite likely aren't an ell either, thus producing at least one more error message. You would get an error printed for each non-ell character.
Generally, if you use scanf(), it is fairly hard to recover from errors. You're likely to be better off reading a line into a buffer (character array) and use sscanf() to parse it.

You should just need to add a space before %c. I am unsure why it works, but it does. This also happens with other data types.
Replace your scanf statement with scanf(" %c",&computerType);

Related

C skips user input from subsequent scanf statement [duplicate]

I've been having a lot of problems trying to figure out how to use scanf(). It seems to work fine with integers, being fairly straight forward scanf("%d", &i).
Where I am running into issues is using scanf() in loops trying to read input. For example:
do {
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
} while (command != 'q');
When I enter in a validly structured input like c P101, it seems to loop again before prompting me. This seems to happen even with a single:
scanf("%c", &c)
in a while loop. It'll do the loop twice before prompting me again. What is making it loop twice, and how do I stop it?
When I enter in less amount of input that programmatically wouldn't have another character or number such as q, pressing enter seems to prompt me to enter more. How do I get scanf() to process both single and double character entries?
When you enter "c P101" the program actually receives "c P101\n". Most of the conversion specifiers skip leading whitespace including newlines but %c does not. The first time around everything up til the "\n" is read, the second time around the "\n" is read into command, "c" is read into prefix, and "P" is left which is not a number so the conversion fails and "P101\n" is left on the stream. The next time "P" is stored into command, "1" is stored into prefix, and 1 (from the remaining "01") is stored into input with the "\n" still on the stream for next time. You can fix this issue by putting a space at the beginning of the format string which will skip any leading whitespace including newlines.
A similiar thing is happening for the second case, when you enter "q", "q\n" is entered into the stream, the first time around the "q" is read, the second time the "\n" is read, only on the third call is the second "q" read, you can avoid the problem again by adding a space character at the beginning of the format string.
A better way to do this would be to use something like fgets() to process a line at a time and then use sscanf() to do the parsing.
It's really broken! I didn't know it
#include <stdio.h>
int main(void)
{
int counter = 1;
char command, prefix;
int input;
do
{
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
printf("---%c %c%d---\n", command, prefix, input);
counter++;
} while (command != 'q');
}
counter: 1: a b1
---a b1---
counter: 2: c d2
---
c1---
counter: 3: e f3
---d 21---
counter: 4: ---e f3---
counter: 5: g h4
---
g3---
The output seems to fit with Robert's answer.
Once you have the string that contains the line. i.e. "C P101", you can use the parsing abilities of sscanf.
See:
http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html
For question 1, I suspect that you've got a problem with your printf(), since there is no terminating "\n".
The default behavior of printf is to buffer output until it has a complete line. That is unless you explicitly change the buffering on stdout.
For question 2, you've just hit one of the biggest problems with scanf(). Unless your input exactly matches the scan string that you've specified, your results are going to be nothing like what you expect.
If you've got an option you'll have better results (and fewer security issues) by ignoring scanf() and doing your own parsing. For example, use fgets() to read an entire line into a string, and then process the individual fields of the string — maybe even using sscanf().
Perhaps using a while loop, not a do...while loop will help. This way the condition is tested before execution of the code.
Try the following code snippet:
while(command != 'q')
{
//statements
}
Also, if you know the string length ahead of time, 'for' loops can be much easier to work with than 'while' loops. There are also some trickier ways to dynamically determine the length as well.
As a final rant: scanf() does not "suck." It does what it does and that is all.
The gets() function is very dangerous (though convenient for no-risk applications), since it does not natively do any checking of the input. It is VERY commonly known as a point of exploit, specifically buffer overflow attacks, overwriting space in registers not allocated for that variable. Therefore if you choose to use it, spend some time putting some solid error checking/correction in.
However, almost invariably, either fgets() or POSIX getline() should be used to read the line — noting that the functions both include the newline in the input string, unlike gets(). You can remove the trailing newline from string read by either fgets() or getline() using string[strcspn(string, "\n")] = '\0'; — this works reliably.

scanf for string and number in C

I've been trying to use scanf() for reading string and integer. It works fine, but I am unable to check if the input is given correctly.
char command[6];
int cmd_num;
scanf("%5s %d", command, &cmd_num);
It works fine for reading the right input, I am able to check if the string is right by strcmp. I tried to check the number by the function isdigit(), but it cannot check correctly, I guess because of whitespaces, but I am not sure exactly how it works.
I tried to google this, I played around with [^\n] but still it doesn't work. Could anyone enlighten me how scanf exactly works please?
I think solution would be if I exactly could tell scanf what to read ->string(space)integer. Is it possible to acquire this with regular expressions or any other way?
What I need basically is to scanf read the line recognize the string and then to check if there is a number after it too.
Another question is, I need to read the input for as long as the user is giving it, I tried to use getchar for while loop, to repeat as long as the char is not '\n' but this closes the loop right in the beginning, but if I give it EOF condition it never ends even with multiple newlines. I guess it could be limited by the scanf too, but I am not sure exactly how, threads on this forum couldn't give me the answer for it.
This will not procced:
while ( ( c = getchar() ) != '\n')
{
//code
}
This will proceed no matter of newlines:
while ( (c = getchar() ) != EOF )
{
//code
}
You don't check if a number is a number, and isdigit() is used to check if an ascii value is a number between 0 and 9.
To check that scanf() succeeded and the input is correct, thus the value of cmd_num is correct and is an integer read from the input, you have to check the return value of scanf().
It returns, the number of matched format specifiers. You have two of them so
if (scanf("%5s%d", command, &cmd_num) == 2) // this means it's correct
// ^ your code is missing the address of operator

Infinity loop in while statement

Here is a snippet from my code
scanf("%d", &s);
while(s!=1 && s!=2) {
if(scanf("%d", &s) != 1) {
show_warning(); //just print some info msg
}
}
The idea is to execute show_warning function only if user enter something different of 1,2 and entered value to be only integer.
With the code above it jumps in infinity loop. How to fix that ?
The problem is that the failed input operation doesn't extract any characters from the stream (and you'll keep reading the invalid input over and over), so you have to empty the input manually. For example:
char buf[1000];
// ...
if(scanf("%d", &s) != 1)
{
puts("Error, try again: ");
fgets(buf, 1000, stdin);
}
As I suggested in the other question, if you use fgets from the start to always read one line and process it later, you overcome this problem.
(The same philosophy is true in C++: read the whole line first so the input stream can move on, and process the line later to see if its valid.)
Why are you using a while loop? Do you want show_warning(); to be called once, or repeatedly? If you answered once then you only need an if-statement.
What makes you think it is looping until infinity?
You only get the warning message when you have not entered a number because it did not read a token.
Changing the && to || though is a certain way to ensure it will run to infinity as your loop will never break then.
You might want an alternative message to prompt the user to enter data when they did enter a number but not 1 or 2?
I'm assuming you're having issues when a non-integer is input. This is because scanf leaves non-matching characters in the buffer, so subsequent calls are seeing the same input and looping.
What you need to do is if the scanf call returns any number other 1 is: read that character in using scanf("%c",&somechar) so you can print it and tell the user that it isn't accepted. The non-accepted input will then have been removed so the next call to scanf will give you the next input rather than the one you saw on the previous iteration.
Also what happens when no scanf succeeded? The variable s remains unchanged (and perhaps with an undefined value, if you did not initialize it). You should set it, or change the condition of the while !
And you really should learn to compile with warnings enabled and debugging information (i.e. gcc -Wall -g on Linux) and to use a debugger (e.g. gdb on Linux)

Scanf and loops

here a a piece of code that is supposed to loop over and over until the user inputs a number between 0 and 15
int input;
do
{
printf("Enter a number => ");
scanf("%d",&input);
printf("\n %d \n",input);
}
while (!(input>0 && input <15));
However if the user puts in something like "gfggdf" it results in the loop repeating over and over and over and never prompting the user for input again... the console looks like this
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
Enter a number =>
0
(looping indefinitely)
After looking through this book, it seems I need to do something like this to prevent this from happening.
int input, error, status;
char skip_ch;
do
{
error = 0;
printf("Enter a number => ");
status = scanf("%d",&input);
printf("\n %d \n",input);
if(status!=1)
{
error=1;
}
else if(input < 0 || input >15){
error = 1;
}
do
{
scanf("%c",&skip_ch);
}while(skip_ch != '\n');
}
while (error);
I understand needing to check for the scanf status to make sure it was valid input, What I don't understand the the inner do-while loop. I feel like the book never really explained to me why scanf needs to be called several times like that, it's like somehow the scanf buffer got filled up with a bunch of garbage and it's somehow cleaning it out by just looping through it a million times for you.
Could anyone please explain this black magic to me?
That's why there are so many answers to similar questions that recommend not using scanf().
Also, you should check the return value from scanf() because it tells you when something has gone wrong - and no value could be converted.
The normal recommended solution is a combination of fgets() to read lines of input and sscanf() to parse the line once it is read.
The second loop in your example goes around reading the characters up to and including a newline, thus resynchronizing scanf() and skipping any bogus data. It is a long-winded way of doing it; it would be simpler to use getchar() instead:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
Note the use of 'int c;' - the type is crucially not 'char' or 'unsigned char' because it must store all possible char values plus EOF.
The original code loops indefinitely because the invalid data (the "gfggdf") is not removed from the input buffer when scanf fails to convert it to an integer -- it's left in the input buffer, so the next call to scanf looks at the same data, and (of course) still can't convert it to an integer, so the loop executes yet again, and the results still haven't changed.
The:
do {
scanf("%c",&skip_ch);
}while(skip_ch != '\n');
simply reads one character at a time (and ignores it) until it gets to the end of the line. If you prefer to get rid of the garbage in the input buffer without a loop, you can use something like: scanf("%*[^\n]");
Another possibility that's (probably more) widely used is to start by reading an entire line, then attempting to convert what's in the line. Whether it converts or not, you've already read all the data to the end of the line so the next attempt at reading/converting will start from the next line whether the conversion worked or not. This does have one potential weakness: if you got a really long line of input, you could end up reading and storing a lot of data for which you have no real use. It's rarely a big deal, but you should still be aware of it.
First of all, avoid using scanf(), use fgets() instead.
To evaluate your condition (first code). 0 > 0 is false. 0 < 15 is true. false && true is false. !false is true. That's why it's looping indefinitely.

Parsing input with scanf in C

I've been having a lot of problems trying to figure out how to use scanf(). It seems to work fine with integers, being fairly straight forward scanf("%d", &i).
Where I am running into issues is using scanf() in loops trying to read input. For example:
do {
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
} while (command != 'q');
When I enter in a validly structured input like c P101, it seems to loop again before prompting me. This seems to happen even with a single:
scanf("%c", &c)
in a while loop. It'll do the loop twice before prompting me again. What is making it loop twice, and how do I stop it?
When I enter in less amount of input that programmatically wouldn't have another character or number such as q, pressing enter seems to prompt me to enter more. How do I get scanf() to process both single and double character entries?
When you enter "c P101" the program actually receives "c P101\n". Most of the conversion specifiers skip leading whitespace including newlines but %c does not. The first time around everything up til the "\n" is read, the second time around the "\n" is read into command, "c" is read into prefix, and "P" is left which is not a number so the conversion fails and "P101\n" is left on the stream. The next time "P" is stored into command, "1" is stored into prefix, and 1 (from the remaining "01") is stored into input with the "\n" still on the stream for next time. You can fix this issue by putting a space at the beginning of the format string which will skip any leading whitespace including newlines.
A similiar thing is happening for the second case, when you enter "q", "q\n" is entered into the stream, the first time around the "q" is read, the second time the "\n" is read, only on the third call is the second "q" read, you can avoid the problem again by adding a space character at the beginning of the format string.
A better way to do this would be to use something like fgets() to process a line at a time and then use sscanf() to do the parsing.
It's really broken! I didn't know it
#include <stdio.h>
int main(void)
{
int counter = 1;
char command, prefix;
int input;
do
{
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
printf("---%c %c%d---\n", command, prefix, input);
counter++;
} while (command != 'q');
}
counter: 1: a b1
---a b1---
counter: 2: c d2
---
c1---
counter: 3: e f3
---d 21---
counter: 4: ---e f3---
counter: 5: g h4
---
g3---
The output seems to fit with Robert's answer.
Once you have the string that contains the line. i.e. "C P101", you can use the parsing abilities of sscanf.
See:
http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html
For question 1, I suspect that you've got a problem with your printf(), since there is no terminating "\n".
The default behavior of printf is to buffer output until it has a complete line. That is unless you explicitly change the buffering on stdout.
For question 2, you've just hit one of the biggest problems with scanf(). Unless your input exactly matches the scan string that you've specified, your results are going to be nothing like what you expect.
If you've got an option you'll have better results (and fewer security issues) by ignoring scanf() and doing your own parsing. For example, use fgets() to read an entire line into a string, and then process the individual fields of the string — maybe even using sscanf().
Perhaps using a while loop, not a do...while loop will help. This way the condition is tested before execution of the code.
Try the following code snippet:
while(command != 'q')
{
//statements
}
Also, if you know the string length ahead of time, 'for' loops can be much easier to work with than 'while' loops. There are also some trickier ways to dynamically determine the length as well.
As a final rant: scanf() does not "suck." It does what it does and that is all.
The gets() function is very dangerous (though convenient for no-risk applications), since it does not natively do any checking of the input. It is VERY commonly known as a point of exploit, specifically buffer overflow attacks, overwriting space in registers not allocated for that variable. Therefore if you choose to use it, spend some time putting some solid error checking/correction in.
However, almost invariably, either fgets() or POSIX getline() should be used to read the line — noting that the functions both include the newline in the input string, unlike gets(). You can remove the trailing newline from string read by either fgets() or getline() using string[strcspn(string, "\n")] = '\0'; — this works reliably.

Resources