# Detecting illegal characters

• 02-27-2009
paul_harris77
Detecting illegal characters
I have just created a program to act as a quadratic root solver. The user inputs the a, b and c values from their ax^2 + bx + c =o equation and the program finds the roots and prints them on the screen or if there are no real roots it prints "There are no real roots to this quadratic equation".

However, the requirement of the program is to be able to cope without crashing if illegal characters (e.g. letters or symbols or .1 etc.) are entered. Ideally it would need to print on the screen "You have entered an illegal character".

Is there a very simple way of coding this function into the program?

The existing code is shown below.

Thanks.

Paul

Code:

``` #include <stdio.h> #include <math.h> main() {       float a, b, c, determinate, root1, root2;             printf("Enter the required a followed by b followed by c and the program will calculate the roots for you: \n");       scanf("%f %f %f", &a, &b, &c);       printf("\n");             determinate = (b*b)-(4.0*a*c);                         if (determinate>0)                     {root1 = (((-b)+sqrt(determinate))/(2*a));                     root2 = (((-b)-sqrt(determinate))/(2*a));                     printf("Root 1 = %8.5f      Root 2 = %8.5f\n", root1, root2);}                                 if (determinate == 0)                     {root1 = (((-b)+sqrt(determinate))/(2*a));                     printf("Repeated root = %8.5f \n", root1);}                                 if (determinate<0)                   printf("There are no real roots to this quadratic equation.\n");                                                 printf("\n");             system ("pause");}```
• 02-27-2009
matsp
scanf returns the number of successfully read in. So check the return value from scanf, and if it's not 3, then something was not entered correctly. You then should clean up the input buffer, which there is a FAQ entry that describes how that is done.

Note that there is a subtle difference between what I am suggesting and what you are specifically asking for. Conceptually they lead to the same thing: The program behaves correctly with invalid input. But it is much harder to determine what the input was, than to determine IF it is correct or not.

--
Mats
• 02-27-2009
Meldreth
scanf will return 3 if all three numbers are valid. you can do this.
Code:

```if (scanf("%f %f %f", &a, &b, &c) != 3) {     fprintf(stderr, "bad input\n");     exit(EXIT_FAILURE); }```
• 02-27-2009
MK27
You should learn to use fgetc() to do this instead of scanf().

Remember, input is buffered, so if you ask for a line, you can then iterate thru it one byte at a time, giving you the opportunity to parse it however you like, etc.

Have a look at the getrow() function in this post.
• 02-27-2009
Elysia
And don't quit on failure; ask the user to input something again.
Nothing is more frustrating than when the application quits because you entered something wrong.
• 02-27-2009
laserlight
I have deleted some posts that ended up in a flamewar.

Anyway, Meldreth wanted to make a point, namely, that besides just asking the user to input again, you need to ignore the invalid input that is left in the buffer.

One way to accomplish the task is to use fgets() + sscanf() instead of using scanf() directly.
• 02-27-2009
dwks
Quote:

One way to accomplish the task is to use fgets() + sscanf() instead of using scanf() directly.
e.g.
Code:

```char line[BUFSIZ]; do {     if(!fgets(line, sizeof line, stdin)) {         printf("Error in input or end of input reached\n");         exit(1);     } } while(sscanf(line, "%f%f%f", &a, &b, &c) != 3);```
Or you could continue to use scanf(), I suppose . . .
Code:

```while(scanf("%f%f%f", &a, &b, &c) != 3) {     int c;     while((c = getchar()) != '\n' && c != EOF) {}  /* discard input until newline */     if(c == EOF) {  /* EOF = End Of Input */         printf("Error in input or end of input reached\n");         exit(1);     } }```
I wouldn't recommend that over the former solution, though, since it still allows the user to enter newlines between numbers, and perhaps getting confused . . .

BTW, I've never heard what I know as the discriminant called a "determinate" before.
• 02-27-2009
paul_harris77
Thanks for your replies guys. I've tried using the scanf("%f %f %f", &a, &b, &c) != 3 idea and it does seem to determine when a letter is entered instead of a number and prints :"You have entered an illegal character".

However as someone suggested, the invalid input is still in the input buffer and causes the following if statement to be true and run as well which is undesirable:

Code:

```if (determinate<0)                   printf("There are no real roots to this quadratic equation.\n");```
I tried to stop the if statement running by changing it to run if the determinate is <0 and if the number of successfully entered numbers is 3 as you can see below, but the if statement still runs.

Code:

``` if (determinate<0 && scanf("%f %f %f", &a, &b, &c) == 3);                   {printf("There are no real roots to this quadratic equation. \n");}```
Any ideas?

The full code is below.

Code:

```#include <stdio.h> #include <math.h> main() {       float a, b, c, discriminant, root1, root2;             printf("Enter the required a followed by b followed by c and the program will calculate the roots for you: \n");       scanf("%f %f %f", &a, &b, &c);       printf("\n");             discriminant = (b*b)-(4.0*a*c);                         if (scanf("%f %f %f", &a, &b, &c) != 3)               {printf("You have entered an illegal character.");}                         if (discriminant>0)                     {root1 = (((-b)+sqrt(determinate))/(2*a));                     root2 = (((-b)-sqrt(determinate))/(2*a));                     printf("Root 1 = %8.5f      Root 2 = %8.5f\n", root1, root2);}                                 if (discriminant == 0)                     {root1 = (((-b)+sqrt(determinate))/(2*a));                     printf("Repeated root = %8.5f \n", root1);}                         if (discriminant<0 && scanf("%f %f %f", &a, &b, &c) == 3);                   {printf("There are no real roots to this quadratic equation. \n");}                     system ("pause");}```
BTW determinate is the same as discriminant, I was taught to use determinate at school.

Thank you

Paul
• 02-27-2009
MK27
As I already tried to pointed out, and as life seems to be demonstrating, scanf is a very poor choice for doing this kind of thing. You will be much happier if you just learn to use fgetc and low level parsing routines, whether that's today, or tomorrow, or next week, because it will have to happen or you will just get frustrated with programming and quit. I promise. They are much more secure and versatile.

But by all means, bang away.
• 02-27-2009
whiteflags
The scanf function can read numbers separated by white space with relative ease (as dwks has demonstrated).

fgetc, IMO, is the exception rather than the rule, because it leads to this....

The post that you are alluding to has its' own problems: atoi is a good idea if you are sure a string contains digits, only, and if the conversion does not cause overflow at some point. Not to mention that a more stringent method, like strtol, at least checks for overflow. There's also strtod for floating point. Using such workhorses to their potential takes a bit of know-how, but I'd rather see examples using it than some other way, if you're going to really recommend rolling your own to someone.

"... by all means, bang away."
• 02-27-2009
MK27
"The post that I was alluding to" was not meant as a drop in replacement. The point is YOU COULD put some error checking into it because it works byte by byte BEFORE the atoi (or I guess the OP will want atof) call. Or, as you suggest, the strtol/strtod. But you are being intentionally deceptive about scanf. Sorry.

Anyone who creates an overflow doing this needs a different kind of therapy, because I don't think I could do it if I tried. What on earth would are you going to overflow???
• 02-27-2009
whiteflags
Whether or not you intended it to be a drop-in replacement is meaningless in the context of what I actually said, since I took issue with how you used atoi in an example you thought was relevant here. I have just as much a right to evaluate examples as anyone else here.

You can type numbers that are too small or too large for integers. atoi doesn't let you know that's the case, though, and you'll end up with a representation of some other number. That is what I mean--perhaps my vocab is rusty and my use of overflow incorrect--but things should be clear as crystal now.
• 02-27-2009
MK27
CLear enough -- I'm just trying to do the OP a favour and I think you should have distinguished your argument "strtof vs. atof" (a good one) from your "scanf vs. fgetc" (a bad one, forget it, those apples, these oranges, this a box, that a fluted hi-ball glass).

I'm here all day most days and easily 5-10%+ of posts (or more) are about why scanf didn't invent my computer:
Code:

```#include <scan.f> int main(int scanf, char scanf) {         scanf myscanf;         while (1) {               scanf("%@\$", myscanf);               if (scanf) scanf(myscanf);         }         return scanf(); }```
"I am new to scanf programming and don't understand why C doesn't work."

It's a useful function, IMO, but there may be a reason that there are, in fact, other functions for input as well.

To concur with laserlight, IMO the (s)scanf stuff is usually better to work on an existing string and not so much for creating them.
• 02-27-2009
whiteflags
Quote:

However as someone suggested, the invalid input is still in the input buffer and causes the following if statement to be true and run as well which is undesirable:
This is not a suggestion, but an actual problem that needs correcting. You should reread dwks' post (and ignore the side discussion that MK and I are having, sorry).

If the input doesn't match the format string, scanf returns a result you don't want. We expressed this in the program as:

if ( scanf("%f%f%f", &a , &b , &c) != 3 )

but scanf doesn't discard input for you. If you don't, scanf will keep failing on the same piece of input. That's why the extra loop that dwks' put in his scanf example is important.

Quote:

It's a useful function, IMO, but there may be a reason that there are, in fact, other functions for input as well.
I would agree. But to be clear on this final point, I will take exceptions to solutions that take nothing away from a scanf solution. If you're going to recommend rolling your own with whatever, the examples better be able to run pretty clean. Yours didn't, that's all.
• 02-28-2009
dwks
Code:

```            if (discriminant<0 && scanf("%f %f %f", &a, &b, &c) == 3);                   {printf("There are no real roots to this quadratic equation. \n");}```
This is the wrong thing to do for a few reasons . . . first of all, you have an extra semicolon there which will make what you think is body of the if execute all of the time. Secondly, you'll be getting more numbers every time you call scanf(). You don't want the user to have to enter their three numbers more than once.

You really should read my previous example again, but maybe I can provide a more relevant one:
Code:

```printf("Enter the required a followed by b followed by c and the program will calculate the roots for you:\n"); /* try to read in three numbers */ while(scanf("%f%f%f", &a, &b, &c) != 3) {     /* scanf()'s attempt to read three numbers was unsuccessful */         /* clear the input buffer; i.e., remove all characters until a newline */     int c;     while((c = getchar()) != '\n' && c != EOF) {}     /* if the user has entered EOF (CTRL-Z on Windows), exit the program */     if(c == EOF) {  /* EOF = End Of Input */         printf("Error in input or end of input reached\n");         exit(1);     }     /* prompt again for another three numbers */     printf("Invalid input, please try again:\n"); }```