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");

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.

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.

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.

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:

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.

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 */