Stephen Cadiz Stephen Cadiz - 1 month ago 13
C Question

Trying to avoid infinite loop if input is not an integer

UPDATE BELOW

I need to test if an input is an integer, and if it is then continue doing something.

If the input is not an integer I need to print an error message and quit.

The method I'm using is

scanf
will return the number of read items, in my case I want it to return 1. So I test if
scanf
returns 1, and execute the rest of my code.

But, for some reason when
scanf
doesn't return
1
I run into an infinite loop

Code:

/*
* Read in a number of values to read and then print the average
* of those values.
*/

#include <stdio.h>
#include "tfdef.h"
#define DEBUGGING 1;

int main() {
int expected;
int count;
double sum;
int value;
int flag;

while (flag = scanf("%d", &expected) != EOF) {
#ifdef DEBUGGING
printf("flag: %d expected: %d\n", flag, expected);
#endif

if (flag == 1) {
sum = 0;
for (count = 0; count < expected; count++) {
scanf("%d", &value);
sum += value;
}
printf("Average of %d values is %.2f\n",
count, count != 0 ? sum / count : 0.0);
} else {
printf("Error! Can't read number of expected values.\n");
}
}
}


UPDATE

The following code seems to work except the case where the initial input is a number followed by letters. For example
Input: eeee33333
Printed: "Error! Can't read number of expected values.

Input: 333eeee
Printed: Debug1 flag:1 expected: 333

Code



#include <stdio.h>
#include "tfdef.h"
#define DEBUGGING 1;


int main()
{
int expected;
int count;
double sum;
int value;
int flag;




while (flag = scanf("%d", &expected))
{
#ifdef DEBUGGING
printf("Debug1 flag: %d expected: %d\n", flag, expected);
#endif
if (flag == EOF)
{
#ifdef DEBUGGING
printf("Debug2 flag: %d expected: %d\n", flag, expected);
#endif
return 0;

}
while(getchar()!='\n');

if(flag == 1)
{
sum = 0;
for (count = 0; count < expected; count++)
{
scanf("%d", &value);
sum += value;
}
printf("Average of %d values is %.2f\n",
count, count != 0 ? sum / count : 0.0);
}

}
printf("Error! Can't read number of expected values.\n");

}



Answer

The best solution for this problem is to read the input with fgets() and parse it with sscanf(), but the reason you get an infinite loop is this: your test is incorrect:

while (flag = scanf("%d", &expected) != EOF)

flag receives the result of the comparison between the return value of scanf and EOF... You probably meant to write this instead:

while ((flag = scanf("%d", &expected)) != EOF)

But if the user types something that cannot be parsed as an int, such input lingers in the stdin buffer and scanf() will keep attempting to parse it in vain.

Try this approach:

#include <stdio.h>

int getnumber(int *valp) {
    char line[80];
    char last;

    while (fgets(line, sizeof line, stdin)) {
        flag = sscanf(line, "%d %c", &expected, &last);
        if (flag < 1) {
            printf("Input is not a number: %s", line);
            continue;
        }
        if (flag > 1) {
            printf("Extra characters after number input: %s", line);
            continue;
        }
        return 0;
    }
    return EOF;
}

int main(void) {
    int expected;
    int count;
    double sum;
    int value;

    while (getnumber(&expected) != EOF) {
        sum = 0;
        for (count = 0; count < expected; count++) {
            if (getnumber(&value) == EOF) {
                printf("Error! Can't read number of expected values.\n");
                break;
            }
            sum += value;
        }
        printf("Average of %d values is %.2f\n",
               count, count != 0 ? sum / count : 0.0);
    }
    return 0;
}