How to determine invalid inputs in c - c

I want to take an float input but if the user gives a character input it will show invalid input, I didn't found a specific answer on the net.
How is it done?

While scanf is safe to parse a double, many compilers have deprecated its use (for good reason) becuase it is unsafe when parsing a string. Additionally, should the parse fail, you will be left with the remains in the input buffer and you will have to flush it yourself.
For these reasons, prefer a function like fgets, which checks the length of its supplied buffer, and then a function like strtod or sscanf to make the conversion.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char buf[64];
/* read */
if (fgets(buf, sizeof buf, stdin)) {
/* convert */
char *err;
double d = strtod(buf, &err);
if (*err) {
puts("entry invalid");
} else {
printf("you entered %lf", d);
}
}
return 0;
}

Consider the following code fragment:
int num;
float val;
num = scanf("%f", &val);
if(num != 1)
{
printf("You didn't enter a float!\n");
}
scanf returns the number of items that it successfully scans. In your case, you're trying to scan one item, a float. If the user doesn't enter a float, scanf will return 0.
Note: If scanf fails, whatever garbage data the user entered will still be in the stdin stream. You'll have to manually flush it. Here's one such way:
while(((ch = getchar()) != '\n') && (ch != EOF))
continue;
Warning: Don't use fflush on stdin.
Edit
Even if scanf doesn't fail, you may still have garbage in the stdin buffer. For example, if the user enters:
123xyz
123 will be assigned to the float, and everything after x will stay in the stdin stream.

Related

Why does scanf enter a loop when I input a character?

I have to finnish a college project, and a part of my code is acting strangely.
The goal of that part is to get an user input of an integer and store it in a variable so that i can use it later, however if the user inputs a character I have to ask for the number again.
I used the scanf function to get the user input and put it inside a while loop to continuously ask for the input in case it's invalid.
The problem is that when a user inputs a character, the code freaks out and starts running the while loop without stopping in the scanf to get the user input.
It makes sense that the loop condition is always true but the strange part is that it doesn't stop to read new inputs.
I deconstructed my code in order to replicate the problem to make it easier to debug.
I know that there are some useless variables but in my original code they are useful, I just kept them there to make it look similar to the original.
I can only use scanf to get user input, despite knowing them, in this project I am only allowed to use scanf. I can't use scanf's format to get characters, only numerical types are allowed in this project.
C11 is the version of the standart we are using in classes.
I'm sory if the solution for this is a dumb thing, I'm not good at C and I'm having some difficultlies this semester...
Thanks in advance.
while (!verification) {
printf(">>>"); //write values in here
check = scanf("\n%d", &var); //input a number and store the number of valid inputs
if (check) verification = 1; //if the input is a number then the while condition should turn to false with this statement
printf("var = %d, check = %d, verification = %d\n", var, check, verification); //printing all variables
}
If the user does not input an integer there are characters left in the input stream after the call to scanf. Therefor you need to read to end of line before making the next attempt to read an integer. Otherwise scanf will try to read the same non-integer characters again and again. Here is an example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int ch, i, n;
n = scanf("%d", &i);
while (n == 0) {
fprintf(stderr, "wrong input, integer expected\n");
do {
ch = getchar();
} while ((ch != EOF) && (ch != '\n'));
n = scanf("%d", &i);
}
if (n == 1) {
printf("%d\n", i);
} else { /*n == EOF*/
fprintf(stderr, "reading input failed\n");
exit(EXIT_FAILURE);
}
return 0;
}
Don't use scanf() to read input from the user.
It's really only meant for reading data that's known to be in a particular format, and input from a user... often isn't.
While you do correctly check the return value of scanf("%d"), and could fix the case where the input isn't a number, you'll still have problems if the input is either an empty line, or a number followed by something else (123 foobar).
In the case of an empty line scanf() will continue waiting for non-whitespace characters. This is probably confusing, since users will expect hitting enter to do something.
In the case there's trailing stuff after the number, that stuff stays in the input buffer, and the next time you read something, it gets read. This is again probably confusing, since users seldom expect their input to one question to also act as input to another.
Instead, read a full line with fgets() or getline(), then run sscanf() or strtol() on that. This is much more intuitive, and avoids the disconnect caused by scanf() consuming input lines only partially (or consuming more than one line). See also e.g. scanf() leaves the new line char in the buffer
Here, using getline() (POSIX, even if not in standard C. Use fgets() instead if getline() is not available):
#include <stdio.h>
int main(void)
{
char *line = NULL;
size_t len = 0;
int result;
printf("Please enter a number: ");
while (1) {
if (getline(&line, &len, stdin) == -1) {
/* eof or error, do whatever is sensible in your case */
return 1;
}
if (sscanf(line, "%d", &result) != 1) {
printf("That didn't seem like number, please try again: ");
continue;
}
break;
}
printf("You entered the number %d\n", result);
}
The problem is you must discard offending input when the conversion fails.
Here is a simple solution using only scanf() as instructed:
#include <stdio.h>
int main() {
int n;
for (;;) {
printf("Enter an number: ");
switch (scanf("%d", &n)) {
case 1:
/* successful conversion */
printf("The number is %d\n", n);
return 0;
case 0:
/* conversion failure: discard the rest of the line */
scanf("*[^\n]"); // discard characters before the newline if any
scanf("*1[\n]"); // optional: discard the newline if present
printf("Invalid input. Try again\n");
continue;
case EOF:
/* input failure */
printf("Premature end of file\n");
return 1;
}
}
}

How do I limit the input of scanf to integers and floats (numbers in general)

I am curently learning C Programming in University and I got the task to write a program witch puts out the interception points with 0 / x-axis of any function ax^2+bx+c.
In order to make sure that the input is correct (int, float, etc.) I run the following while loop. Prior to that a is definded as a double.
printf("Input for a=");
while (scanf("%lf", &a) == 0)
{
fflush(stdin);
scanf("%lf", &a);
printf("Incorrect Input! New Input needed.\n");
printf("a=");
}
I am aware that the fflush(stdin) operator only clears the buffer when a second input function occurs and therefore the fflush inside the loop does not clear the buffer and therefore the condition of the loop is always true and thus I created an infinite loop.
My professor also forbids the use of goto, which is why I am here, because I can't come up with a reasonable solution that solves this problem.
I also tried and failed with:
do
{
printf("\nInput for a= ");
scanf("%lf", &a);
}
while (isdigit(a));
{
printf("Thank you.\n");
}
With this arrangement I get the failure notification: Expression c >= -1 && <= 255. I guess this has to do with false variable definition (double, digit) or such.
However my original question was whether there is an elegant solution to this problem or at least any solution.
Lukas, I'm still not 100% clear and your:
"Im am asking how to distinguish between all numbers and every other possible input for scanf."
scanf can provide conversion to a single given type based on the conversion specifier used, so you can't read both int and float with the same scanf statement and a single conversion specifier. (now you can read a line with, e.g. fgets and then use alternate sscanf statements and check the remaining characters to do that)
That said, I think I understand what you are asking and can answer both the fflush and read of a value questions.
To begin, when using scanf you must check the return and handle three-cases. (1) EOF, the user cancels input with a Ctrl+d (or Ctrl+z on windows); (2) a matching or input failure occurs resulting in a return of less than the number of conversion specifiers used; and finally (3) the good input case (where you impose any additional checks you have, e.g. positive, less than 100, etc..)
While fflush(stdin) is undefined behavior on most systems, there are a number of implementations that allow it. (primarily windows, but Linux allows it for seekable stream, e.g. a file redirected on stdin) Bottom line, it isn't portable without caveats, so it's best to provide a simple equivalent with getchar(), e.g.
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
As for scanf, as I mentioned in the comment, it is far easier to enclose the scanf call within an infinite loop which you only break when the input satisfies all your constraints. A simple example requiring integer input would be:
int getint (int *value, const char *prompt)
{
/* loop continually until good input or canceled */
for (;;) {
int rtn;
fputs (prompt, stdout); /* display prompt */
rtn = scanf ("%d", value);
if (rtn == EOF) { /* user generated manual EOF */
fputs ("<user canceled input>\n", stderr);
return 0;
}
empty_stdin(); /* all other cases - empty input buffer */
if (rtn == 1) /* good input, break */
break;
/* otherwise matching failure */
fputs (" error: invalid integer input.\n", stderr);
}
return *value; /* value also availale through pointer */
}
Putting it altogether in a simple example, you would have:
#include <stdio.h>
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int getint (int *value, const char *prompt)
{
/* loop continually until good input or canceled */
for (;;) {
int rtn;
fputs (prompt, stdout); /* display prompt */
rtn = scanf ("%d", value);
if (rtn == EOF) { /* user generated manual EOF */
fputs ("<user canceled input>\n", stderr);
return 0;
}
empty_stdin(); /* all other cases - empty input buffer */
if (rtn == 1) /* good input, break */
break;
/* otherwise matching failure */
fputs (" error: invalid integer input.\n", stderr);
}
return *value; /* value also availale through pointer */
}
int main (void) {
int v,
i = getint (&v, "enter integer value: ");
if (i)
printf ("\ninteger: %d\n", v);
return 0;
}
Example Use/Output
Where you can now do your best to break any input routine you write. If you find a problem, go fix it and try to break it again.
The code above allows for fairly robust input of any one given type of value, e.g.
$ ./bin/scanfint
enter integer value: no
error: invalid integer input.
enter integer value: apples, banannas, and pears
error: invalid integer input.
enter integer value: 21
integer: 21
Look things over and let me know if your question was slightly different, or if you have further questions about the answer.

Reading until I manage to enter an integer

I'm pretty new in C, I used to work in Python, and I'm trying to see if something that I read is integer number. If not, to read until I manage to entry a number.
I did some research and I found out that the function scanf actually returns 1 if the read is done suitably, and 0 otherwise.
So, I have written this code, and I don't understand why this is an infinite loop, writing "Give an integer" on the console
#include <stdio.h>
int main() {
int a;
int b = 1;
do {
printf("Give an integer\n");
b = scanf("%d", &a);
} while (b == 0);
}
The problem with scanf() is that it stops reading when the first white space is encountered for most specifiers like "%d", so it's left in the input and that's why reading again would cause a problem if you don't discard such white space because it will then return immediately the next time you call it. There is a mandatory white space that is introduced when you press Enter or Return, the '\n' new line character (or line feed).
If you want to read an integer and make sure you did you can try like this
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int
main(void)
{
long int value; // You can adapt this to use `int'
// but be careful with overflow
char line[100];
while (fgets(line, sizeof(line), stdin) != NULL) {
char *endptr;
value = strtol(line, &endptr, 10);
if ((isspace(*endptr) != 0) && (endptr != line))
break;
}
fprintf(stdout, "%ld\n", value);
return 0;
}
read strtol()'s manual to understand this code
You could as suggested in the comments, remove the white space characters from the input, but IMHO that is harder and you would still have other problems with scanf(), like handing empty input which is not straight forward.
I don t understand why this is an infinite loop, writing "Give an intiger" on the console
The problem is that scanf() does not consume data that it cannot match against the specified format. It leaves such characters unread in the input stream. Therefore, if you try reading again from the same stream with the same format, without consuming at least one character by some other means, then you can be certain that the input will again not be matched. And again. And again.
To avoid your infinite loop, you need to consume at least one character of the non-matching input after each matching failure. There are many ways you could do that; here's a fairly simple one:
#include <stdio.h>
int main() {
int a;
do {
printf("Give an intiger\n");
if (scanf("%d", &a)) {
// breaks from the loop on a successful match or an error
break;
}
// consume the remainder of one line of input without storing it
if (scanf("%*[^\n]") == EOF) {
break;
}
} while (1);
}
That consumes the whole remainder of the line on which the non-matching input is encountered, which will yield less surprising interactive behavior for some inputs than many alternatives would.
If you've a penchant for writing terse code, or if you don't like to break out of the middle of a loop, then you might write the same thing like this:
#include <stdio.h>
int main() {
int a;
do {
printf("Give an intiger\n");
} while ((scanf("%d", &a) == 0) && (scanf("%*[^\n]") != EOF));
}
Because the && operator short circuits, the second scanf() call will be executed only if the first returns zero, and the loop will exit after the first iteration wherein either the first scanf() call returns nonzero or the second returns EOF (indicating an error).

Why does scanf get stuck in an infinite loop on invalid input? [duplicate]

This question already has answers here:
Why is scanf() causing infinite loop in this code?
(16 answers)
Closed 9 years ago.
In line 5 I read an integer and isint is getting 1 if it reads an integer or 0 if it's not an integer. If isint is 0 I have a loop asking user to give an integer and I read until the user gives an integer. I try this code giving a character instead of an integer but I have an infinite loop. The program just doesn't wait to give a new input. What's wrong with my code?
#include <stdio.h>
int main(void) {
int arg1;
//int arg2;
int attacknum = 1;
int isint = 1;
//printf("Insert argument attacks and press 0 when you have done this.\n");
printf("Attack %d\n", attacknum);
attacknum++;
printf("Give attacking argument:");
isint = scanf("%d", &arg1); //line 5
while(isint == 0){
printf("You did not enter a number. Please enter an argument's number\n");
isint = scanf("%d", &arg1);
printf("is int is %d\n", isint);
}
return 0;
}
As others have mentioned, if scanf can't parse the input, it leaves it unscanned.
Generally scanf is a poor choice for interactive input because of this kind of behavior, and because it doesn't match the line-at-a-time interface experienced by the user.
You are better off reading one line into a buffer using fgets. Then parse that line using sscanf. If you don't like the input, throw the whole line away and read another one.
Something like this:
#include <stdio.h>
int main(void)
{
char line[256];
int arg1;
int isint;
while (1) {
printf("Give attacking argument:");
fgets(line, sizeof line, stdin);
isint = sscanf(line, "%d",&arg1);
if (isint) break;
printf("You did not enter a number.Please enter an argument's number\n");
}
printf("Thanks for entering %d\n", arg1);
return 0;
}
(For production code you'll want to handle long lines, check return codes, also check for trailing garbage after the number, etc.)
Actually, an even better approach would be to not use scanf if you just want to read an integer, and instead use strtol. That gives you a handy pointer to the character just after the number, and you can check that it's whitespace or nul.
When scanf is confronted with a non-digit it will not consume any input and return that zero integers were read. The non-digit will stay in the input for the next call to scanf that will behave the same as the first call, etc.
In answer to your question below. You could use fgetc to parse at least one character, but this will give the error messages for every character already typed. Typically I think you want to skip until a newline. To this end you could use fgets as suggested by poolie. Or you could add the following after scanf.
int ch;
if (isint == 0)
while ((ch = fgetc(stdin)) != EOF && ch != '\n')
{
/* Skip characters */
}
P.S: In your case it is probably better to put it just before the first printf in the loop.

Getting keyboard input after fgets

I, for the life of me, cannot be at peace with c strings and input/output.
For my program I simply enter a string and it gets processed in the following code: (tmpstring and ch are already defined)
For my incomning input, I write in terminal: echo "test" | ./program
int main(int argc, char *argv[]) {
char tmpstring[2048];
int ch;
int r;
int c;
fgets(tmpstring, sizeof tmpstring, stdin);
while((ch = fgetc(stdin))!= EOF && ch != '\n');
tmpstring[strlen(tmpstring)-1]='\0';
strncpy(opponent, tmpstring+1, strlen(tmpstring+1));
move();
Inside of move();
char buffer[2048]={0};
int r, c;
r=0; c=0;
printf("Your move (row column):");
if((fgets(buffer, sizeof buffer, stdin)==NULL) || ((sscanf(buffer,"%d %d", &r, &c))!=2)){
printf("Invalid input. Please insert two numbers separated by whitespace.\n");
exit(1);
}
//continues
Executing this goes straight into the invalid input without asking for more input. I've read all around about how you shouldn't clear stdin (and that it's impossible) but I really don't know what to do. I clearly tried to "dump" stdin with the second part of the while loop. I've changed the && after the first condition to an || in the while loop. No change. Overall, how can I ask for more input after already used fgets?
*edit: more code and separated the original while loop
This kind of problem has been discussed elsewhere.
I will copy a part of my own post, from here:
Max string length using scanf -> ANSI C
It is defined a function my_scanf() with variable number of parameters, by invoking the stdarg.h library, joint to a combination of fgets() and vsscanf().
That function is designed to handle in a right manner combinations of fgets() and sscanf() (actually, we have to use vsscanf() in order to properly process the list of arguments).
The input is read up to an upper limit of characters. if the input has more than this limit, it is truncated. The '\n' are handled correctly. The function returns the same value as scanf() would return. So, you can use my_scanf() instead.
Here you have the code:
#include <stdio.h>
#include <stdarg.h>
int my_scanf(const char* fmt, const unsigned int maxbuff, ...) {
va_list ptr;
int ret;
if (maxbuff <= 0)
return EOF; /* Bad size for buffer[] */
char buffer[maxbuff+1];
buffer[maxbuff-1] = '\0'; /* Quick buffer cleaning... */
if (fgets(buffer, maxbuff+1, stdin) == NULL)
return EOF; /* Error detected */
else {
if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0'))
/* Condition logically equivalent to:
fgets() has not reached an '\n'
*/
while (getchar() != '\n')
; /* "Flushing" stdin... */
va_start(ptr, maxbuff);
ret = vsscanf(buffer, fmt, ptr);
va_end(ptr);
return ret;
}
}
#define MAXBUFF 20
int main(void) {
int x;
float z;
int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z);
printf("\nTest:\n x == %d\n z == %g\n scanfret == %d", x, z, scanf_ret);
getchar();
return 0;
}
The function my_scanf() has the prototype
int my_scanf(const char* fmt, const int maxbuff, ...);
It accepts a format string fmt that behaves in the same way as any other scanf()-like does.
The 2nd parameter is the maximum number of chars that will be effectively accepted from the standard input (keyboard).
The return value is an int, which is EOF if maxbuff has no sense, or well some input error happened. If a non-negative value is returned, it is the same that would be returned by the standard functions sscanf() or vsscanf().
Inside the function, maxbuff is incremented in 1, because fgets() makes some room for an additional '\0' character.
Non-positive values of maxbuff are immediatelly discarded.
fgets() will read a string from stdin (keyboard) with room for at most maxbuff characters, including '\n'.
If the user has entered a very long string, then it will be truncated, and some kind of "flush" mechanism is necessary in order to discard all the characters to the next '\n' (ENTER). If not, the next keyboard reading could have older characters, not desired at all.
The condition for "flushing" is that fgets() has not reached '\n' after reading stdin.
This is true if, and only if, buffer[maxbuff - 1] is not equal to '\0' nor '\n'. (Check it!)
Finally, an appropiate (and standard) combination of stdarg.h macros and the function vsscanf() is employed to process the variable list of parameters.

Resources