1

I'm struggling to come up with a solution for a problem that I set myself to complete, I have tried multiple different ways but I can't seem to get it to behave.

What I'm attempting to do is handle when non-numeric characters are input by a user in scanf. The end goal is to have the program ask the user for a value from a series, and keep asking until a float or int is entered, then finish the series.

Seeing as it's a short program, ill post the whole thing. Any help is much appreciated.

int main(void) {
    int numberOfValues, ctr, inputValidation, avg;
    float sum = 0;

    printf("\nHow many values are you averaging?: ");
    scanf("%d", &numberOfValues);

    float inputValue[numberOfValues];

    printf("\n");

    for (ctr = 0; ctr < numberOfValues; ctr = ctr + 1) {
        printf("\tPlease enter value %d: ", ctr + 1);
        inputValidation = scanf("%f", &inputValue[ctr]);
        if (inputValidation != 1) {
            printf("\tPlease enter value %d again: ", ctr + 1);
            scanf("%f", &inputValue[ctr]);
        } else {
            sum += inputValue[ctr];
        }
    }

    avg = sum / numberOfValues;

    printf("\nYour average is: %g", avg);

    return 0;
}
Edward Nunn
  • 113
  • 7

2 Answers2

1

You need to consume the "bad" data. Since scanf() could not match the format you requested, it will leave the data in the buffer.

Using getchar() as a way to do so:

            int gc;
            do {
                gc = getchar();
                if (gc == EOF) exit(EXIT_FAILURE);
            } while(gc != '\n');

Here is your program modified to do so. Disclaimer: the following program is merely helping with the specific question. It is incomplete and there are other challenges and scenarios to overcome. E.g. try to begin your input with a digit and add non-digit char(s) such as "4abc" and see what happens. More examples of issues in the comments.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int numberOfValues, ctr, avg;
    float sum = 0;

    printf("\nHow many values are you averaging?: ");
    scanf("%d", &numberOfValues);

    float inputValue[numberOfValues];

    printf("\n");

    for (ctr = 0; ctr < numberOfValues; ctr = ctr + 1)
    {
        printf("\tPlease enter value %d: ", ctr + 1);

        while (scanf("%f", &inputValue[ctr]) != 1) {
            int gc;
            do {
                gc = getchar();
                if (gc == EOF) exit(EXIT_FAILURE);
            } while(gc != '\n');
            printf("\tPlease enter value %d again: ", ctr + 1);
        }
        sum += inputValue[ctr];
    }

    avg = sum / numberOfValues;

    printf("\nYour average is: %d", avg);

    return 0;
}
niry
  • 3,238
  • 22
  • 34
  • 4
    `while (getchar() != '\n');` would enter an infinite loop on EOF or IO-error. – HAL9000 Jul 05 '21 at 18:35
  • 1
    @HAL9000 indeed. I've amended the program to check for EOF (both actual EOF and error apply). I've also added a disclaimer. – niry Jul 05 '21 at 22:25
  • 1
    You should also check the return value of `scanf("%d", &numberOfValues);` to avoid undefined behavior on invalid input. – chqrlie Jul 05 '21 at 23:18
  • `avg` should probably be a `float` too. – chqrlie Jul 05 '21 at 23:19
  • 1
    For improved average computation, accumulating the sum of integers as an integer makes sense -perhaps as a `long long` to avoid overflow. `long long sum = 0;` The average calculation and display deserve to be `double`. `double avg = 1.0 * sum / numberOfValues;`. Save `float` for special cases and use `double` for general FP. – chux - Reinstate Monica Jul 06 '21 at 03:06
  • @chqrlie good point, I did originally have it as a float but in my endless optimisation of the code I seemed to have put it back in the int declarations – Edward Nunn Jul 06 '21 at 15:43
1

You need to discard the 'bad' data before trying to call scanf again. There are a variety of ways to do that. You could discard everything up to the next newline (scanf("%*[^\n]") would do that), though you should probably also check for EOF somewhere. Or you could discard a single character and try again (but you probably don't want to prompt again, as you probably have multiple characters left in the input buffer.)

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226