1

So in this C code the program will give an error message that says "Invalid grade" and it asks the user to enter the grade again if the entered grade is >100 or <0, but this only happens once. If the user enters an invalid grade again the program returns black rather than giving the error message again and asking user to reenter the grade. How can I fix this?

#include <stdio.h>
#include <math.h>

int main()
{
    double grade;
    printf("Enter the student's grade: ");
    scanf("%lf",&grade);

    if (grade<0 || grade>100)
    {
        printf("Invalid grade\n");
        printf("Enter the student's grade: ");
        scanf("%lf", &grade);
    }

    if (grade>=90 && grade<=100)
        printf("A");

    if (grade>=80 && grade<=89)
        printf("B");

    if (grade>=70 && grade<=79)
        printf("C");

    if (grade>=60 && grade<=69)
        printf("D");

    if (grade<60 && grade>=0)
        printf("F");

    return 0;

}

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
OJScofield
  • 19
  • 3

4 Answers4

2

This type of user-input validation code is where a do-while loop is idiomatic:

int scanned;

do
{
    printf("Enter a grade between 0 and 100 (inclusive): ");
    scanned = scanf(" %lf", &grade);
}
while(scanned != 1 && (grade < 0.0 || grade > 100.0));

Also note:

  1. I check the return value of scanf to ensure that it's the same value as the number of format specifiers in the string. This tells me that scanf succeeded.

  2. I put a space before the format specifier in the scanf format string. This consumes all whitespace left in the buffer prior to the new input.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • This is the one answer that takes note of the important return value `scanf`, but trying this out I see a lot of errors (`&&` -> `||`) and infinite loops (EOF? non-number input?). – Neil Mar 19 '21 at 00:51
1

You don't need to combine conditions with && operator.

if (grade >= 90)
{
   printf("A");
}

else if (grade >= 80)
{
    printf("B");
}

else if (grade >= 70)
{
    printf("C");
}

else if (grade >= 60)
{
    printf("D");
}

else if (grade >= 0)
{
    printf("F");
}
1

Try this one:

#include <stdio.h>
#include <math.h>

int main()
{
    double grade;
    printf("Enter the student's grade: ");
    scanf("%lf",&grade);

   while (grade<0 || grade>100)
    {
        printf("Invalid grade\n");
        printf("Enter the student's grade: ");
        scanf("%lf", &grade);
    }

    if (grade>=90 && grade<=100)
        printf("A");

    if (grade>=80 && grade<=89)
        printf("B");

    if (grade>=70 && grade<=79)
        printf("C");

    if (grade>=60 && grade<=69)
       printf("D");

    if (grade<60 && grade>=0)
        printf("F");

    return 0;

}
H Hasan
  • 55
  • 1
  • 8
  • whatif uninitialized grade happened to be 1.0; and the user entered `psych` instead of a number? – mevets Mar 18 '21 at 22:17
1

This is hard to do with generality. scanf was not really meant for interactive programmes; see why not use scanf. The accepted answer of using a loop is good, and checking the return value is important. However, it fails for many edge cases; I've expended and covered some of them here as an addendum.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <math.h>

int main(void) {
    int scanned, garbage, is_infected;
    double grade;
    const double max_grade = 100;
input:
    printf("Enter a grade between 0 and %.0f (inclusive): ", max_grade);
    /* Ignore leading whitespace. */
    scanned = scanf(" %lf", &grade);
    /* Ignore up to EOL for future input. */
    is_infected = 0;
    while((garbage = getchar()) != '\n' && garbage != EOF)
        if(!isspace(garbage)) is_infected = 1;
    if(is_infected) { fprintf(stderr, "Non-numerical input.\n"); goto input; }
    /* `scanned` can be EOF, 0, or 1. */
    switch(scanned) {
    case EOF: /* EOF could mean different things. */
        if(ferror(stdin)) { /* It could mean an error. */
            /* ISO C doesn't strictly define whether bumped to `errno`. */
            if(!errno) errno = EILSEQ;
            perror("input");
        } else { /* Or it could mean EOF. */
            fprintf(stderr, "Premature EOF.\n");
        }
        return EXIT_FAILURE;
    case 1: /* Successfully matched a double. */
        /* `isnan` is C99; C90, `grade != grade` is true by IEEE754, which some
         compilers relax. */
        if(isnan(grade) || grade < 0.0 || grade > max_grade) {
            fprintf(stderr, "Out of range [0, %.0f].\n", max_grade);
            goto input;
        }
        grade = fabs(grade); /* For -0.0. */
        break;
    default: /* 0, unlikely (impossible?) because of clear of `stdin`. */
        fprintf(stderr, "No number.\n");
        goto input;
    }

    printf("number: %f\n", grade);
    return 0;
}
Neil
  • 1,767
  • 2
  • 16
  • 22
  • Note: I think this is easier with "%n", see [parsing input](https://stackoverflow.com/a/58405772/2472827). – Neil Jan 21 '23 at 22:47