scanf("%d",a) with a "while" grammar bypass the scanf - c

if there is no initialization ("mod=0") , this code go infinite loop.
I can't understand why this code go loop, even if I used getchar();
to erase the buffer.
when I typed "1" first, and typed "a" next, there goes an infinite loop.
Can anybody help me with understanding this situation?
int main()
{
srand((unsigned)time(NULL));
int mod = 0;
int val = 0;
do {
printf("\t-----------------------------\n");
printf("\t|%5s %5s %5s %5s|\n", "1.create", "2.modify", "3.print", "4.quit");
printf("\t|%15s","Input command : ");
scanf("%d", &mod);
printf("\t-----------------------------\n");
switch (mod){
case 1: random(); val++; break;
case 2: if(val != 0) { modify(); break; }
case 3: if(val != 0) { print(); break; }
default: getchar(); printf("\tUnknown Command!! Retry!! \n"); break;
}
} while (mod != 4);
}
I compiled this code with Visual Studio 2015.

When you input a, it's an invalid input for mod as scanf() expects an int for %d. So it's not read into mod. So the mod is left with the value of mod inputted in the previous iteration.
And the reason it goes in an infinite loop is because scanf() doesn't discard the invalid input. So repeatedly attempts to read a and fails and loop goes on.
Check the return value of scanf() and discard any invalid input(s).
scanf() is notoriously bad for reading user input and proper handling input failures is generally harder using it.
A better approach is to read a line input using fgets() and then parse it using sscanf().
do {
...
printf("\t|%15s","Input command : ");
fgets(line, sizeof line, stdin);
char *p = strchr(line, '\n');
if(p) *p = 0; /* remove tailing newline, if present */
if( sscanf(line, "%d", &mod) != 1) {
printf("Invalid input\n");
continue;
}
printf("\t-----------------------------\n");
....
}while (mod != 4);

The problem with your code is, that once you typed in an number, which is a valid menu option, the variable mod is always equal to the same number, that was input during the first time you entered it, if you enter a wrong input the second time. This behavior comes from the fact, that
scanf(%d, &mod);
tries to read an integer, but as you entered an 'a' as a second option for example, the input is not able to read an integer from your Standard input. So it will not enter the default case of your switch method, as the variable mod is equal to the input from the first valid input you entered.

Related

How to go back to the beginning of a case if the conditions aren't met

`
switch(selectedOption){
case 'B':
printf("Please enter the first number\n");
if (scanf("%f", &firstNumber) == 1){
printf("Is a valid number\n");
}
else{
printf("Is not a valid number\n");
}
}
`
I have a school assignment where I have to program a calculator. One of the requirements is to ask for the user to input another number if they for example input a character instead of a number. I'm not sure how to go about this and I looked everywhere and no solutions made sense. I would appreciate it a ton if someone could help me out with this problem.
The simple answer is to loop until valid input has been read (assuming the input comes from an interactive agent such as a person sat at a terminal).
The following will not work:
switch(selectedOption){
case 'B':
while (1) {
printf("Please enter the first number\n");
if (scanf("%f", &firstNumber) == 1){
printf("Is a valid number\n");
break;
}
else{
printf("Is not a valid number\n");
}
}
/* ... */
break;
}
The problem is that scanf will stop reading input when it sees a character that is not part of the number, and will push that character back onto the stream (c.f. ungetc). For example, if the input is -foo, scanf will read the spaces, then the - (which could be part of the number), then the f which is not part of the number. The f will be pushed back onto the stream and scanf will return 0. On the next iteration of the while loop, scanf will read the f, push it back onto the stream and return 0. Loop ad infinitum, et ultra.
To break the infinite loop, the code needs to read something from the stream and discard it. One option is to read and discard the next word by calling scanf("%*s");, or discard the next word and the following whitespace character by calling scanf("%*s%*c");, or discard the remainder of the line and the newline by calling scanf("%*[^\n]%*c");. E.g.:
switch(selectedOption){
case 'B':
while (1) {
printf("Please enter the first number\n");
if (scanf("%f", &firstNumber) == 1){
printf("Is a valid number\n");
break;
}
else{
printf("Is not a valid number\n");
scanf("%*s");
}
}
/* ... */
break;
}
Note that input such as 42foo will be considered valid by the above code. scanf will push the f back onto the stream and return 1 because it has read a valid number 42. You may want to read the next character and check that it makes sense. You can always push at least one character back onto the stream by calling ungetc(ch, stdin); so that it can be re-read later.
You do not need switch - case.
You just need to do:
while (true) {
char number = 0;
scanf_s("%c", &number);
if (number >= '0' && number <= '9') break;
else printf("Is not a valid number\n");
}

infinite loop in the guessing number program in c

I am fairly new when it comes down to C programmming. That's why i am working my way up by doing some of the easier exercises. The exercise i'm working on is the "guess the number" game, where the user must guess the number that lies between two numbers (upper and lower bounds). The program is doing what it must, with one exception: when the user enters a character instead of an integer, the program gets stuck in an infinite loop. The only way to break out of this loop is by using a break statement and restarting the program. What i want instead, is to have the program request for the users input again, untill an integer is entered.
Can someone tell me why the programm gets stuck in this infinite loop and why it is not requesting for input again trough scnanf like it did in the first iteration? your help will be appreciated. thank you.
//globals
int secret_nr;
int guess;
int upper_bound = 100;
int lower_bound = 1;
int total_guesses = 1;
void check_input(void) {
if (guess < lower_bound || guess > upper_bound) {
printf("Invalid input! Your guess must be between %d and %d\n", lower_bound, upper_bound);
}
else if (guess < secret_nr) {
printf("Higher\n");
total_guesses++;
}
else if (guess > secret_nr) {
printf("Lower\n");
total_guesses++;
}
else if (guess == secret_nr) {
printf("correct! You guessed the number after guessing %d times!\n", total_guesses);
}
}
int main(int argc, char* argv[]) {
srand(time(NULL));
secret_nr = (rand() % upper_bound) + 1;
printf("Guess the number between %d and %d:\n", lower_bound, upper_bound);
do {
if (scanf("%d", &guess)) {
check_input();
}
else {
printf("Invalid input! Only integer values are allowed!\n");
//break;
}
} while (guess != secret_nr);
return 0;
}
If scanf fails to parse its input according to the specified format, then the input will be left in the input buffer for the next call to scanf which will read the very same input and again fail. And so on and on and on...
The simple solution is to first of all read the whole line of input, using e.g. fgets. Then you can use sscanf in that (now extracted) input to attempt to parse it.
Further complicating your current code is the fact that if scanf fails in some other way, it will return EOF which is the integer -1, which is "true". That will of course lead to problems with your logic and looping as well.
I see this reply in another post: https://stackoverflow.com/a/1716066/5687321
scanf consumes only the input that matches the format string, returning the number of characters consumed. Any character that doesn't match the format string causes it to stop scanning and leaves the invalid character still in the buffer. As others said, you still need to flush the invalid character out of the buffer before you proceed. This is a pretty dirty fix, but it will remove the offending characters from the output.
char c = '0';
if (scanf("%d", &number) == 0) {
printf("Err. . .\n");
do {
c = getchar();
}
while (!isdigit(c));
ungetc(c, stdin);
//consume non-numeric chars from buffer
}

How to accept ";' semicolon, as input, and not execute the next line of codes?

Here's a small portion of a practice I'm doing preventing erroneous inputs.
while(1) {
printf("Choose From 1 to 7 ");
if( scanf("%d", &nNum ) != 1) {
printf("Please only choose from the numbers 1-7.");
fgets(sErraticInputs, 100 , stdin);
} else if (nNum > 7 || nNum <= 0) {
printf("Please only choose from the numbers 1-7.");
} else {
break;
}
}
I was doing a good job, until I entered "6;p". It executed the 6 portion and ran correctly, but technically speaking it should have taken the whole thing as the input, and proceeded with the error message.
First of all I don't think the posted code can give the said result. The break statement will end the while(1) when 6 has been read so there will not be printed an error message.
If we assume that the break isn't part of your real code this is what happens:
When scanf is told to read an integer, it will continue reading from the input stream as long as the next character (together with the previous read characters) can be converted into an integer. As soon as the next character can not be used as part of an integer, scanf will stop and give you the result of what it has parsed so far.
In your case the input stream contains
6;p\n
So scanf will read the 6 and stop (i.e. return 6). The input stream now contains:
;p\n
Consequently this will be the input for your next scanf and cause the input error, you saw.
One way to solve this would be to flush stdin after all scanf - both on success and on failure:
nNum = 0;
while(nNum != 7) // Just as an example I use input 7 to terminate the loop
{
printf("Choose From 1 to 7 ");
if( scanf("%d", &nNum ) != 1 || nNum > 7 || nNum <= 0)
{
printf("Please only choose from the numbers 1-7.");
}
else
{
printf("Valid input %d\n", nNum);
// **************************** break;
}
fgets(sErraticInputs, 100 , stdin); // Always empty stdin
}
note: Using fgets with size 100 doesn't really ensure a complete flush... you should actually use a loop and continue until a '\n' is read.
With the change above input like 6;p will be taken as a valid input with value 6 and the ;p will be thrown away.
If that's not acceptable, you could drop the use of scanf and do the parsing yourself. There are several options, e.g. fgets or fgetc
The example below uses fgetc
#include <stdio.h>
#include <stdlib.h>
int get_next()
{
int in = fgetc(stdin);
if (in == EOF) exit(1); // Input error
return in;
}
void empty_stdin()
{
while(get_next() != '\n') {};
}
int main(void) {
int in;
int nNum = 0;
while(nNum != 7)
{
printf("Choose From 1 to 7 \n");
in = get_next();
if (in == '\n' || in <= '0' || in > '7') // First input must be 1..7
{
printf("Please only choose from the numbers 1-7.\n");
if (in != '\n') empty_stdin();
}
else
{
nNum = in - '0';
in = get_next();
if (in != '\n') // Second input must be \n
{
printf("Please only choose from the numbers 1-7.\n");
empty_stdin();
}
else
{
printf("Valid input: %d\n", nNum);
}
}
}
return 0;
}
This code will only accept a number (1..7) followed by a newline
Here's why the "whole thing" is not taken as the input. From the man pages:
The format string consists of a sequence of directives which describe
how to process the sequence
of input characters. If processing of a directive fails, no further input is read, and scanf()
returns. A "failure" can be either of the following: input failure, meaning that input characters
were unavailable, or matching failure, meaning that the input was inappropriate...
Here's the full text. Have a look at this as well.
One approach would be to read in the whole input using fgets and check whether the length of the input is greater than 1. For an input of length 1, check if the input is a number and so on...

Error check for character when reading in integers in C

For my programming class I've written a program to calculate the sum of divisors. So I've gotten to my final part which is error checking, which I am having a problem with if I read a character in. I have searched on S.O. earlier,as well as tried to figure something out, and couldn't find a solution that works for endless negative numbers until 100.
When I hit a character it sets it to 0 and just goes to the end, where I want it to exit once it reads it in
int main (void){
int userIN=0;
int i = 0;
int next = 0;
int temp= 105;
int cycle;
puts("Enter up to 10 integers less than or equal to 100");
while(scanf("%d ", &userIN) !=EOF && (i < 10))
{
if(userIN > 100){
printf("Invalid Input\n");
exit(1);
}
else if(userIN < 100)
{
Thanks for the help in advance
EDIT: The program is cycling through correctly, My Issue is error checking for a character being entered not anything with the code itself
scanf() returns a value other than EOF if it cannot read the values specified by the format string (e.g. with %d, it encounters data like foo). You can check for that. The caveat is that it does not read the offending data from stdin, so it will still be there to affect the next call of scanf() - which can result in an infinite loop (scanf() reporting an error, call scanf() again, it encounters the same input so reports the same error).
You are probably better off reading a whole line of input, using fgets(). Then check the input manually or use sscanf() (note the additional s in the name). The advantage of such an approach is that it is easier to avoid an infinite loop on unexpected user input.
You could loop while i is less than 10. The first if will see if scanf failed. If so the input buffer is cleared and the while loop tries again. If EOF is captured, then exit. If scanf is successful, the input is compared to 100 and if in range, the while loop counter is incremented.
Declare int ch = 0;
while ( i < 10) {
printf("Enter %d of 10 integers. (less than or equal to 100)\n", i + 1);
if(scanf(" %d", &userIN) != 1)
{
while ( ( ch = getchar()) != '\n' && ch != EOF) {
//clear input buffer
}
if ( ch == EOF) {
exit ( 1);
}
}
else {
if(userIN > 100){
printf("Invalid Input\n");
}
else
{
i++;// good input advance to the next input
printf("Valid");
}
}
}

Exit out of a loop after hitting enter in c

How should i exit out of a loop just by hitting the enter key:
I tried the following code but it is not working!
int main()
{
int n,i,j,no,arr[10];
char c;
scanf("%d",&n);
for(i=0;i<n;i++)
{
j=0;
while(c!='\n')
{
scanf("%d",&arr[j]);
c=getchar();
j++;
}
scanf("%d",&no);
}
return 0;
}
I have to take input as follows:
3//No of inputs
3 4 5//input 1
6
4 3//input 2
5
8//input 3
9
Your best bet is to use fgets for line based input and detect if the only thing in the line was the newline character.
If not, you can then sscanf the line you've entered to get an integer, rather than directly scanfing standard input.
A robust line input function can be found in this answer, then you just need to modify your scanf to use sscanf.
If you don't want to use that full featured input function, you can use a simpler method such as:
#include <stdio.h>
#include <string.h>
int main(void) {
char inputStr[1024];
int intVal;
// Loop forever.
for (;;) {
// Get a string from the user, break on error.
printf ("Enter your string: ");
if (fgets (inputStr, sizeof (inputStr), stdin) == NULL)
break;
// Break if nothing entered.
if (strcmp (inputStr, "\n") == 0)
break;
// Get and print integer.
if (sscanf (inputStr, "%d", &intVal) != 1)
printf ("scanf failure\n");
else
printf ("You entered %d\n", intVal);
}
return 0;
}
There is a difference between new line feed (\n or 10 decimal Ascii) and carriage return (\r or 13 decimal Ascii).
In your code you should try:
switch(c)
{
case 10:
scanf("%d",&no);
/*c=something if you need to enter the loop again after reading no*/
break;
case 13:
scanf("%d",&no);
/*c=something if you need to enter the loop again after reading no*/
break;
default:
scanf("%d",&arr[j]);
c=getchar();
j++;
break;
}
You also should note that your variable c was not initialized in the first test, if you don't expected any input beginning with '\n' or '\r', it would be good to attribute some value to it before the first test.
change
j=0;
to
j=0;c=' ';//initialize c, clear '\n'
When the program comes out of while loop, c contains '\n' so next time the program cannot go inside the while loop. You should assign some value to c other than '\n' along with j=0 inside for loop.

Resources