how to control input data format (C)? - c

anyone knows an efficient way to check out the format of an scanf'ed data?
e.g. if I try to read an integer and I type a character, how would you do to tell the program that is not correct?

You can check if scanf() succeeds, it returns the number of successful conversions it performed.
You should always check this, before relying on the result since if it failed the variable(s) might contain undefined data leading to undefined results if referenced.
You can use if to check, and re-try with a different conversion specifier on failure:
if(scanf("%d", &x) == 1)
printf("got integer %d\n", x);
else if(scanf("%c", &y) == 1)
printf("got character '%c'\n", y);
else /* more attempts */
Of course it can become troublesome if there are "sub-matches", so the order can matter. It's also way better to split the input processing into two steps for the above:
Read a full line of input using fgets()
Use sscanf() to parse the line
That way you avoid problems due to the input being streamed in:
char line[128];
if(fgets(line, sizeof line, stdin) != NULL)
{
int x;
char y;
if(sscanf(line, "%d", &x) == 1)
printf("got integer %d\n", x);
else if(sscanf(line, "%c", &y) == 1)
printf("got character '%c'\n", y);
}
Note that if you wanted to scan for both an integer and a float, it can still become troublesome since a typical float (such as "3.1416") begins with what is a legal integer. For those cases you can use the strtoXXX() family of functions, which let you check the remainder after doing the conversion.

As you have mentioned in the question that you are playing with numbers and chars only there is a very simple solution as follows
//while reading a char
scanf("%c",&temp);
if(!((temp >= 65 && temp <= 90) || (temp >= 97 && temp <= 122)))
printf("Only characters are allowed!\n");
hope this helps!

scanf("%s", &c);
if(!atoi(c)) puts("You have entered a character");
if(atoi(c) != 0) puts("You have entered an integer");

Scanner sc = new Scanner (System.in);
try {
// assume that the input from the user is not an integer,
// in that case the program cannot convert the input (which is a String) into
// an integer. Because of this situation it'll jump to the 'catch' part of the
// program and execute the code.
int input = Integer.valueOf(sc.nextInt);
// if the input is an integer lines below the above code will be executed.
// Ex. "int x = ( input + 10 ) "
}
catch (Exception ex) {
System.out.println("Invalid input, please retry!");
// if you want to get more information about
// the error use the 'ex' object as follows.
System.out.println(ex);
}

Related

storing a negative integer in signed char

I'm trying to get a function that stores integers in char. I need to use char rather than int because I need to use the question mark (?) to terminate my loop. However, I can't seem to make my code work. Here's my work:
int main() {
signed char num;
scanf("%c", &num);
if (num!='?') {
printf("%c\n", num);
}
return 0;
}
When I input a negative number (say, -9), I get the output:
-
I tried using the integer print symbol (%d) rather than %c when I was printing the values, as I saw on this question: https://www.quora.com/Can-I-assign-a-negative-number-to-a-char-variable-Why-or-why-not but makes everything I input junky. ie when I input 2, it returns 50.
I was told that signed char should do the thing here, but I'm not sure that's the case now.
Thanks.
If you want to scan an integer and at the same time scan a character like ? you can do:
Try to scan an integer
If scan for integer fails, try to scan a char
Like
int num;
char c;
if (scanf("%d", &num) == 1)
{
// Okay you got an integer.
c = num; // BUT... watch out for over/underflow !!!
}
else if (scanf("%c", &c) == 1)
{
// Okay you got a char
if (c == '?')
{
// You got your ?
}
else
{
// Some other char
// Some kind of error handling... perhaps
c = 0;
}
}
else
{
// Input error that can't be recovered
exit(1);
}
See online example https://ideone.com/kTPE0M
You use the wrong format:
it has to be (but you will have to enter 63 instead of ?):
signed char num;
scanf("%hhd", &num);
or
char str[6];
char num;
fgets(str,5,stdin);
if (str[0]!='?') {
if(sscanf(str, "%hhd", &num) == 1)
printf("%c\n", num);
else {/* handle scanf error*/}
When you have to do anything at all complicated, scanf is almost never the right tool for the job.
And, although it might not be obvious at first, the task "read a thing that's either an integer, or a question mark that indicates the end of the input" is definitely, in this sense, something that's too complicated for scanf. There's no good format specifier for that kind of "thing".
The easiest thing is to read a line of text (using fgets, not scanf), then start trying to figure out what's in it — question mark, integer, or something else. (What if the user types "x"?)
#include <stdio.h>
int main()
{
char line[512];
int num; /* note int not char */
if(fgets(line, sizeof(line), stdin) == NULL)
printf("end of file or error\n");
else if(line[0] == '?')
printf("end of input\n");
else if(sscanf(line, "%d", &num) == 1)
printf("numeric input: %d\n", num);
else printf("unexpected input!\n");
}
Note that this program still isn't perfect: If the user, types, say, "123x", this program will say it saw numeric input, and won't notice or complain about the extra x. Also, it only looks at the first character of the line to see if it's a ?, so it will also accept things line ?? or ?Cat in the hat. (There are ways to fix both of those things, but they get rather elaborate, and are probably more trouble than they're worth for a simple exercise.)
See also What can I use for input conversion instead of scanf?

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 print Invalid for letters

How do I print invalid when someone enter big or small letters, because supposedly they only enter floats between 0 to 10.
I tried coding like this
It went so wrong.
#include<stdio.h>
int main()
{
int trial=0;
float judge1=0,judge2,judge3,judge4,judge5;
char a;
printf("\n%90s","Welcome to the constentant score calculator program :)");
printf("\n\n\n\n\n\rKindly enter the constentant score by 5 respected
judges:");
do
{
printf("\n\nScore by JUDGE 1 (0-10):\t");
scanf("%f",&judge1);
if ((judge1>-1)&& (judge1<11) )
printf("The constentant got %.2f from the judge",judge1);
else
printf("\aPlease input a valid score between 0 and 10:");
} while ((judge1<0) || (judge1>10)||(judge1=a>96) && (judge1=a<123)||
(judge1=a<91) && (judge1=a>64));
}
okay this is my second code
#include<stdio.h>
int main()
{
float judge1;
printf("\n%90s","Welcome to the constentant score calculator program :)");
printf("\n\n\n\n\n\rKindly enter the constentant score by 5 respected
judges:");
printf("\n\nScore by JUDGE 1 (0-10):\t");
scanf("%f",&judge1);
if ((judge1>-1) && (judge1<11))
printf("The constentant got %.2f from the judge",judge1);
else
printf("\aPlease input a valid score between 0 and 10:");
}
}
When you use the "%f" as the format string for scanf, it will read only characters that are valid for a floating point type and will stop reading if it detects any other characters. So if someone types "abc", nothing is written to judge1 and those characters are left in the input buffer to be read again. You'll then get stuck in an infinite loop reading those same characters.
Also, this expression doesn't make sense:
judge1=a>96
> has higher precedence than ==, so it is equivalent to:
judge1=(a>96)
Assuming a is assigned a value, a>96 compares that value with 96 and evaluates to either 0 or 1. Then you assign this value to judge1, overwriting what was read from the user. Assuming you meant to use == this doesn't make sense either. That being the case, either judge1==0 or judge1==1 is evaluated depending on the result of a>96. So the above expression will only be true if judge1 is 1 and a is greater than 96 or judge1 is 0 and a is less than or equal to 96.
Another problem is that a is never assigned a value. You seem to be under the impression that when you call scanf("%f",&judge1); that the first character read is written to a. There is no link that causes that to happen, so a is left uninitialized.
What you want to do instead is read in a line of text using fgets, then using strtof to read a float. The strtof function accepts the address of a pointer as the second parameter to let you know where in the string the parsing stopped. So if this pointer does not point to the null terminator at the end of the string (or to a newline character, since fgets reads and stores the newline), then you know you read a non-float character.
float judge1;
char line[100];
char *p;
int invalid_input;
do {
invalid_input = 0;
fgets(line, sizeof(line), stdin);
errno = 0;
judge1 = strtof(line, &p);
if (errno || ((*p != 0) && (*p != '\n')) || (judge1 < 0) || (judge1 > 10)) {
printf("Please input a valid score between 0 and 10:");
invalid_input = 1;
} else {
printf("The constentant got %.2f from the judge\n ",judge1);
}
} while (invalid_input);
First, check the return value of scanf. If it fails to match the item it will return 0. Then you can check whether the number entered is within bounds:
int r, judge1;
...
r = scanf("%d", &judge1);
if(r != 1)
{
printf("invalid input\n");
while((r = fgetc(stdin)) != EOF && r != '\n');
}
else if((judge1 < 0) || (judge1 > 10))
printf("input out of range\n");
else
printf("valid input\n");
The problem is you have the bad charachter stuck in the stream. The solution is here:
scanf fails why?.
The suggested thing to do from John Bode is to use a getchar to get it out. Also apply the check mnistic suggested and it should work.
it doesn't offer anything and it only messes with the greater picture.

scanf test failing inside a function in C

I'm trying to do a program with a simple game for a user to guess the number. My code is below:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 30
#define TRYING 5
void guessnumber(int, int, int *);
int main(void) {
int mytry = 1;
guessnumber(MAX, TRYING, &mytry);
if (mytry <= TRYING)
printf("Congratulations! You got it right in %d tries\n", mytry);
else
printf("Unfortunately you could not guess the number in the number of tries predefined\n");
printf("End\n");
return EXIT_SUCCESS;
}
void guessnumber(int _n, int _m, int *_mytry) {
srandom(time(NULL));
int generated = 0, mynum = 0, test = 0;
generated = rand() % (_n + 1);
printf("Welcome to \"Guess the number\" \n");
printf("A number between 0 and %d was generated\n", _n);
printf("Guess the number:\n");
while (*_mytry <= TRYING) {
test = scanf(" %d", &mynum);
if (test != 1 || mynum < 0 || mynum > MAX)
printf("ERROR: please enter a valid number \n");
else
if (mynum > generated)
printf("Wrong! The number your trying to guess is smaller\n");
else
if (mynum < generated)
printf("Wrong ! The number your trying to guess is bigger\n");
else
break;
*_mytry = *_mytry + 1;
}
}
Okay, now the program is working pretty ok except for one thing: the scanf test.
It works if I try to enter a number out of my range (negative or above my upper limit) but it fails if I for example try to enter a letter. What it does is that it prints the message of error _m times and then it prints "Unfortunately you could not guess the number in the number of tries predefined" and "End".
What am I doing wrong and how can I fix this?
In case, a character is entered, you're trying to detect it correctly
if(test!=1 ......
but you took no action to correct it.
To elaborate, once a character is inputted, it causes a matching failure. So the input is not consumed and the loop falls back to the genesis position, only the loop counter is increased. Now, the previous input being unconsumed, is fed again to the scanf() causing failure once again.
This way, the loop continues, until the loop condition is false. Also, for every hit to scanf(), as unconsumed data is already present in the input buffer, no new prompt is given.
Solution: You need to clean the input buffer of existing contents when you face a failure. You can do something like
while ((c = getchar()) != '\n' && c != EOF);
to clean the buffer off existing contents.
When you enter a letter, scanf() leaves the letter in the input stream since it does not match the %d conversion specifier. The simplest thing to do is use getchar() to remove the unwanted character:
if (test != 1) {
getchar();
}
A better solution would be to use fgets() to get a line of input, and sscanf() to parse the input:
char buffer[100];
while (*_mytry<=TRYING)
{
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
fprintf(stderr, "Error in fgets()");
exit(EXIT_FAILURE);
}
test=sscanf(buffer, "%d", &mynum);
if(test!=1 || mynum<0 || mynum>MAX)
printf ("ERROR: please enter a valid number \n");
else if(mynum>generated)
printf("Wrong! The number your trying to guess is smaller\n");
else if(mynum<generated)
printf("Wrong ! The number your trying to guess is bigger\n");
else
break;
*_mytry=*_mytry+1;
}
In the above code, note that the leading space has been removed from the format string. A leading space in a format string causes scanf() to skip leading whitespaces, including newlines. This is useful when the first conversion specifier is %c, for example, because any previous input may have left a newline behind. But, the %d conversion specifier (and most other conversion specifiers) already skips leading whitespace, so it is not needed here.
Additionally, your code has srandom() instead of srand(); and the call to srand() should be made only once, and probably should be at the beginning of main(). And, identifiers with leading underscores are reserved in C, so you should change the names _m, _n, and _mytry.

Validating Integer in C Programming

How can I make sure the number input by user is integer ranging from 0 to 4 only and also making sure that it is non negative/non symbol/alphabet??
If I do this,then it will not be able to validate alphabet/symbol
printf("Enter number 0 to 4");
scanf("%d",x);
if((x<0)||(x>4))
{
printf("0 to 4 only");
scanf("%d",x);
}
else
{
xxxxxx
}
First %d format from scanf expects a pointer to int. So you will write:
scanf("%d", &x);
Then you can test whether the read data match with the format, using scanf return value:
if (scanf("%d", &x) != 1 || x < 0 || x > 4)
{
/* Wrong input */
}
else
{
/* Well-formed input */
}
Read man scanf for further informations.
If the input should be a single number on the line, then:
char line[4096];
int x;
if (fgets(line, sizeof(line), stdin) == 0)
...EOF or other major trouble...
else if (sscanf(line, "%d", &x) != 1)
...not an integer...
else if (x < 0)
...negative - not allowed...
else if (x > 4)
...too large - maximum is 4...
else
...Hooray - number is valid in the range 0-4...use it...
You get to choose how the errors are handled. The first error handling should abandon the efforts to get a number from the user; the other three could warrant a retry (but keep an eye on how many retries you allow; if they get it wrong 10 times in a row, it is probably time to give up).
The key point is that the code uses fgets() to get the whole line, and then parses that. It would be possible to do further analysis — to make sure there isn't extra information on the line (so the user didn't type '3 dogs' instead of just '3'). This also allows you to report errors in terms of the whole line. The test for if (sscanf(line, "%d", &x) != 1) is also important. The members of the scanf()-family of functions report the number of successful conversion specifications (%d is a conversion specification). Here, if sscanf() successfully converts an integer, it will return 1; otherwise, it may return 0 or EOF (though EOF is unlikely with sscanf()). If there were 3 conversion specifications, the correct check would be != 3; it might report 1 or 2 successful conversions.

Resources