Verifying Input in C - c

I'm trying to write a simple binary calculator to get reaquainted with C. for some reason the first input verification works fine, and even though the second verification for the numbers is written in almost the same way, if the user enters faulty input, the while loop just loops infinitely without ever waiting for new user input. Here is the code, and thanks for the help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char operator[20];
char valid_operator[4] = "+-*/";
printf("Enter operator: ");
scanf("%s", operator);
printf("You entered: %s\n", operator);
while(strchr(valid_operator, (int)operator[0]) == NULL) {
printf("%s is not a valid operator. Enter +, -, /, or *: ", operator);
scanf("%s", operator);
}
The code works up until here. This next part is thrown into an infinite loop if the user enters faulty input the first time. The re-prompting never happens.
int input1;
int input2;
printf("Enter the two inputs (separated by whitespace): ");
int num_ints = 1;
num_ints = scanf("%d %d", &input1, &input2);
printf("Input 1: %d. Input 2: %d.\n", input1, input2);
while(num_ints < 2){
printf("Invalid input. Enter two integers separated by whitespace: ");
num_ints = 0;
num_ints = scanf("%d %d", &input1, &input2);
printf("Input 1: %d. Input 2: %d.\n", input1, input2);
}
return 0;

The reason it loops infinitely without ever waiting for new user input is that when scanf fails to read a char in the requested format (%d in your case) it won't advance the file pointer and at the next iteration of the loop it will try to read the same incorrect char again.
This is consistent with POSIX: http://pubs.opengroup.org/onlinepubs/009695399/functions/fscanf.html
if the comparison shows that they are not equivalent, the directive shall fail, and the differing and subsequent bytes shall remain unread.
Also, return value from the man scanf:
...return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.
So, you better combine fgets and sscanf.
do {
char buf[BUFSZ];
printf("Enter the two inputs (separated by whitespace): ");
if(fgets(buf, BUFSZ, stdin) == NULL)
{
/* Error exit. */
break;
}
num_ints = sscanf(buf, "%d %d", &input1, &input2);
} while(num_ints != 2);

You need to clear stdin. If you input a non-integer in your example "1 t", "t" is not consumed (left in the stream). Add this to your loop:
while(num_ints < 2){
while (fgetc(stdin) != '\n'); // clear input
. . .
See C program loops infinitely after scanf gets unexpected data for a good description of the issue.

Related

Why this code is not re-prompting correctly?

I am totally new to C.
I want to re-prompt when the input value is not a number and when it's a number it should be less than 1. when I give any sort of string it works correctly. But when I give any number it goes to the next line without printing "Number: ".Then in the next line, it prints "Number: "again if the input value is less than 1.
int x;
printf("Number: ");
while (scanf("%d", &x) != 1 || x < 1 )
{
printf("Number: ");
scanf("%*s");
}
and the result it gives me is this
result
It would be wise to use fgets to read the line, then use sscanf to parse the input. That way, you can get the line, then check if sscanf succeeds!
Simple example:
int target_number; // The number you will have at the end of this.
while (1) { // Loop for rechecking number
char line[16]; // See notes on how to read the whole line.
fgets(line, sizeof(line), stdin);
// We use 1 here because sscanf returns the number of format specifiers that are matched. Since you only need one number, we use 1.
if (sscanf(line, "%d", &target_number) != 1) {
fprintf(stderr, "Invalid Input! Please enter in a valid number.");
continue;
}
}
// Do whatever you will with target_number
Notes
You can see how to read the whole line here.
This code is not safe!
It does not protect against buffer overflow attacks and the like. Please see this on the right way to do this. If this is just for learning, you don't need to worry.
/*This is how it will work the way you want.
If I understand your goal correctly, of course?
If your goal was different,
please specify and I will try to solve it.*/
#include<stdio.h>
int main(void)
{
int x;
printf("Number: ");
while (scanf("%d.%*d", &x)!=1 || x<0)
{
if(x<0)
{
printf("Number: ");
continue;
}
else
printf("Number: ");
scanf("%*s");
}
printf("Hello world!");
return 0;
}

While loop misbehaving,

i am pretty new to c, i m trying to make the user input a number, but if they input a letter or word it shows a warning and asks for input again, my code works fine if the user puts in a number but it goes into an infinite loop if the user inputs something invalid, here is my code
#include <stdio.h>
int main(void) {
float salary;
int status = 0;
while (status == 0)
{
printf(" Please input your yearly salary to calculate taxes: \n");
status = scanf(" %f", &salary);
if (status == 0)
printf("invalid input!\n");
}
printf("%.2f\n", salary);
return 0;
}
i thought that i was something to do with the buffer left over from the first scanf , but adding a space " %f" didnt work, i tried using fflush(stdin) after then scanf also didnt work. i m not sure what else i can try.
thanks in advance for any help.
You need to clear the buffer or it will keep evaluating it and cause the endless loop. Add one line after your invalid input: scanf("%*[^\n]")
#include <stdio.h>
int main(void) {
float salary;
int status = 0;
while (status == 0)
{
printf(" Please input your yearly salary to calculate taxes: \n");
status = scanf(" %f", &salary);
if (status == 0)
printf("invalid input!\n");
scanf("%*[^\n]");
}
printf("%.2f\n", salary);
return 0;
}
This will work. You can see a better explanation here: Scanf and loops
The problem is that scanf won't advance the file stream. You ask it to read a floating point value and it isn't able to, so it doesn't consume the input.
For example, let's say your input is "foo", which isn't a number. Your scanf call isn't able to successfully read anything and returns 0. Then, in the next iteration, "foo" is still waiting to be read from stdin.
Try changing your if condition to something like
if (status == 0) {
char foo[256];
fgets(foo, sizeof(foo), stdin);
printf("Invalid input! Expected a nmuber, got: %s", foo);
}
Notice how the entire input is read from stdin by the gets call.

C Program - How to deny any non-numerical input

I've just started learning the language of C, and would love your help in cleaning up / simplifying my code if you know a better way to reach the following.
I want a program to ask for a number, and if that is found then proceed to print and end, however if anything else is put in (e.g. a letter key), then I want the program to loop asking for a number until one is given.
I started off by using a simple scanf input command, but this seemed to go into an infinite loop when I tried to check if a valid number (as we define them) was put in.
So instead I have ended up with this, from playing around / looking online, but I would love to know if there is any more efficient way!
//
// Name & Age Program
// Created by Ben Warren on 1/3/18.
//
#include <stdio.h>
int main (void)
{
//Setting up variables
int num;
char line[10]; /* this is for input */
//Collecting input
printf("Please enter any number? \t");
scanf("%d", &num);
//If Invalid input
while (num==0)
{
printf("\nTry again:\t");
fgets(line, 10, stdin); //turning input into line array
sscanf(line, "%d",&num); //scaning for number inside line and storing it as 'num'
if (num==0) printf("\nThat's not an number!");
}
//If Valid input
{
printf("\n%d is nice number, thank you! \n\n", num);
*}*
return 0;
}
Instead of checking if the value is different to 0, check the return value of
sscanf. It returns the number of conversions it made. In your case it should be 1. Unless the return value is 1, keep asking for a number.
#include <stdio.h>
int main(void)
{
int ret, num;
char line[1024];
do {
printf("Enter a number: ");
fflush(stdout);
if(fgets(line, sizeof line, stdin) == NULL)
{
fprintf(stderr, "Cannot read from stdin anymore\n");
return 1;
}
ret = sscanf(line, "%d", &num);
if(ret != 1)
fprintf(stderr, "That was not a number! Try again.\n");
} while(ret != 1);
printf("The number you entered is: %d\n", num);
return 0;
}
That is not a bad approach for someone new to C. One small improvement would be to actually check the return value of scanf(), since it returns the number of arguments successfully retrieved. Then you could get away from relying on num being 0 to indicate the input was valid. Unless you do want to specifically flag 0 as invalid input.
int ret = scanf("%d", &num);
ret == 1 would mean an integer was succesffully read into num, ret == 0 would mean it was not.
Consider using strtol to parse a string for a long int. This also allows you to detect trailing characters. In this example if the trailing character is not a newline, the input can be rejected. strtol can also detect overflow values. Read the documentation to see how that works.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
//Setting up variables
long int num = 0;
char line[40] = ""; /* this is for input */
char *parsed = NULL;
printf("Please enter any number? \t");
fflush ( stdout);
while ( fgets(line, 40, stdin))
{
parsed = line;//set parsed to point to start of line
num = strtol ( line, &parsed, 10);
if ( parsed == line) {//if parsed equals start of line there was no integer
printf("Please enter a number? \t");
printf("\nTry again:\t");
fflush ( stdout);
continue;
}
if ( '\n' != *parsed) {//if the last character is not a newline reject the input
printf("Please enter only a number? \t");
printf("\nTry again:\t");
fflush ( stdout);
}
else {
break;
}
}
if ( !parsed || '\n' != *parsed) {
fprintf ( stderr, "problem fgets\n");
return 0;
}
printf("\n%ld is nice number, thank you! \n\n", num);
return 0;
}
0 (zero) is a number...
But I see what you want to do...
You can check for a valid number, using isdigit or a combination of similar functions
I think its also important to follow the advice of other answers to use the return value from scanf using code such as:
int ret = scanf("%d", &num);
and examining ret for success or failure of scanf.

While input is not a number, goes into Infinite loop

I'm just a beginner and am trying to make a a program that asks for a number and if a letter is input, it says "that's not a number" and asks for a number again, until a number is input.
However, my program keeps going into an infinite loop with the current code. Any help would be appreciated to fix this. Also, I would also like the program to say "please input something" if nothing is input, but don't know how to do this. Thanks.
#include <stdio.h>
int main()
{
float i;
printf("enter a number");
while(scanf("%f", &i) != 1)
{
puts("That is not a number.");
scanf("%f", &i);
}
}
You need to clear the bad input from stdin after your scanf fails:
#include <stdio.h>
int main()
{
float i;
char trash[1024];
while (1)
{
printf("Please enter a number: ");
fflush(stdout);
if (1 == scanf("%f", &i))
break;
/* scanf failed: clear the bad input from stdin */
if (NULL == fgets(trash, sizeof(trash), stdin)) /* NOTE: assumes 1 entry per line and no line longer than 1023 characters */
exit((fprintf(stderr, "Unexpected EOF or error!\n"), 1));
puts("That is not a number.");
}
printf("You entered: %f!\n", i);
return 0;
}
As an alternative to the fgets() to clear the line, you could call scanf("%1023s", trash), which would only suck in the next whitespace delimited series of characters. This would allow you to handle multiple entries on a single line with mistakes intermixed, for example.
Your program goes into infinite loop because after the invalid input, (scanf("%d", &i) != 1)condition being TRUE, the invalid input which is left in the input buffer is not consumed, it's still in the buffer. So the same invalid input is read over and over again.
To avoid, once scanf() fails, you need to flush out all the input buffer contains before calling next scanf().
Maybe inside the while loop, calling getchar() until a newline or EOF will help. Also, the second scanf() can be removed, IMHO.
After your non numeric[More precisely input which doesn't match the formating of scanf()] input you need to clear the stdin. If not the same input will be read till stdin get cleaned or you terminate the program. A reference answer can be found on this question
Quoted
On success, the function returns the number of items of the argument list successfully filled. This count can match the expected number of items or be less (even zero) due to a matching failure, a reading error, or the reach of the end-of-file.
Reason for infinite loop : Since you don't clear stdin, same values will be read by scanf() and always full fill while condition resulting in a infinite loop.
Use following edited code :
#include <stdio.h>
int main()
{
float i;
char c;
printf("enter a number");
while(scanf("%f", &i) != 1)
{
puts("That is not a number.");
scanf("%f", &i);
while ((c = getchar()) != '\n' && c != EOF); // Flush stdin
}
}
Your code is taking input of a number. Thats why if you even give input a letter, it will take the ASCII value of the letter, which is a valid number. And Further more please take a character as an input. Here I have modified your code which should work
#include <stdio.h>
int main()
{
char i;
printf("enter a number");
while(1)
{
scanf("%c",&i);
if (c >=48 && c <= 57) // here ascii value of numbers between 0-9 is 48-57 respectively
{
puts("That is a number.");
break;
}
else
{
puts("That is not a number.");
scanf("%c",&i);
}
}
}

C programming minor issue with interactive menu when input a floating value

My program works well with invalid inputs such as char, number out of range, but a problem happens when a floating point value such as 1.2 is entered. The program prints menu again, and asks user for input before printing error message. What I try to fix is don't print menu again, but still struggle. For example,
Make your selection: 1.1
[Here is menu content]
Make your selection: That selection isn't valid. Please try again.
#include <stdio.h>
#define QUIT 0
int menu();
int main(void)
{
int choice;
char c;
choice = menu();
while(choice != QUIT) //execute so long as choice is not equal to QUIT
{
choice = menu();
}
}
int menu(void)
{
int option;
printf("Text Encoder Service\n\n");
printf("1.\tEnter name of input file (currently 'Secret.txt')\n");
printf("2.\tEnter name of output file (currently not set)\n");
printf("3.\tEnter number of characters data should be shifted (currently +7)\n");
printf("4.\tEncode the text\n\n");
printf("0.\tQuit\n\n");
printf("Make your selection: ");
while( (scanf(" %d", &option) != 1) /* non-numeric input */
|| (option < 0) /* number too small */
|| (option > 4)) /* number too large */
{
fflush(stdin); /* clear bad data from buffer */
printf("That selection isn't valid. Please try again.\n\n");
printf("Your choice? ");
}
return option;
}
I finally could validate floating input. Thanks your advices so much! This is my new code. What else do you think an invalid input?
int menu(void)
{
int option, parsed_inputs;
char overcount_char;
parsed_inputs = 1;
printf("Text Encoder Service\n\n");
printf("1.\tEnter name of input file (currently 'Secret.txt')\n");
printf("2.\tEnter name of output file (currently not set)\n");
printf("3.\tEnter number of characters data should be shifted (currently +7)\n");
printf("4.\tEncode the text\n\n");
printf("0.\tQuit\n\n");
printf("Make your selection: ");
parsed_inputs = scanf_s("%d%c", &option, &overcount_char);
while( parsed_inputs > 1 ) /* number too large */
{
if((overcount_char != '\n') || (option < 0) || (option > 4))
{
fflush(stdin); /* clear bad data from buffer */
printf("That selection isn't valid. Please try again.\n\n");
printf("Your choice? ");
scanf_s("%d%c", &option, &overcount_char);
}
else
break;
}
return option;
}
An input of 1.1 leads to the following:
The string is read into an internal buffer.
It is then matched against the given format string.
On the first non-match, the scanf() call is stopped and it returns the number of successfully scanned values.
Let's test it:
#include <stdio.h>
int main(int argc, char ** argv)
{
while (1) {
int option;
int n = scanf(" %d", &option);
printf("%d %d\n", n, option);
if (n <= 0) break;
}
}
This program reads one line.
Suppose I enter 123 132.
Then the following happens:
* As the format string starts with a space, all leading whitespace is consumed. In this case, there is none.
* Then the 123 is consumed and put into option.
* As the format string is over now, parsing is stopped, n=1 and option=123.
* In the next loop run, the same happens, giving n=1 and option=123.
But: Suppose I enter 123.321 or 123#321.
Then the following happens:
* As the format string starts with a space, all leading whitespace is consumed. In this case, there is none.
* Then the 123 is consumed and put into option.
* As the format string is over now, parsing is stopped, n=1 and option=123.
* In the next loop run, there is no whitespace to skip. .321 resp. #321 is tried to be matched to %d, but these are no valid ints. Thus, we get n=0 and option keeps its old value.
* As no characters are consumed from the input stream (the one used is put back again), the same happens over and over again - that's why I put if (n <= 0) break;.
So you see that the behaviour has nothing to do with floating point, as it doesn't matter if we use . or # to "disturb".
We change our program to
#include <stdio.h>
int main(int argc, char ** argv)
{
while (1) {
int option; char c;
int n = scanf("%d%c", &option, &c);
printf("%d %d %d %c\n", n, option, c, c);
if (n <= 0) break;
}
}
and run it, inputting 4.235#6x7.
Then we get
* n=2, option=4 and c='.' at the first run
* n=2, option=235 and c='#' at the 2nd run
* n=2, option=6 and c='x' at the 3rd run
* n=2, option=7 and c='\n' (newline) at the 3rd run
and are prompted for further input.
This makes you open to the option
(parsed_inputs = scanf("%d%c", &option, &overcount_char)) < 1
and then check what overcount_char contains, whenever parsed_inputs is > 1.
I think you should put scanf() before the while loop and explicitly check "option" variable in the while loop.
What happening is that, here scanf() will always return the value 1, because scanf() returns no. of arguments read successfully. Hence this while loop will run forever. For further information check this link->http://www.cplusplus.com/reference/cstdio/scanf/
Hope this helps!

Resources