It’s fun supplying your own scores for a semester, which really helps boost your GPA! Still, the challenge for this Month’s Exercise was to input — and validate — a series of grades to calculate your GPA for five courses.

I went through two drafts of my solution. The first had an input routine, *get_grade()*, obtain the input from 0 through 100, validate and return that value. The *main()* function translated the value returned, calculated the GPA value, stored it in an array, then generated the average. This solution worked, but it was clunky.

My second draft has the *get_grade()* function accept and validate input, and return the GPA value directly, not the 0 to 100 grade. This way, the *main()* function can process everything, both collecting input and calculating the average, in a single loop. Here’s my solution:

#include <stdio.h> #include <stdlib.h> #define SIZE 12 #define CLASSES 5 float get_grade(void) { char input[SIZE]; float grade; char *p; /* obtain input */ fgets(input,SIZE,stdin); /* convert to float */ grade = strtod(input,&p); /* validate */ if( p==input ) { puts("Inavlid input"); exit(1); } /* confirm range */ if( grade<0 || grade>100 ) { puts("Input out of range"); exit(1); } /* return GPA value */ if( grade > 89 ) return(4.0); if( grade > 79 ) return(3.0); if( grade > 69 ) return(2.0); if( grade > 59 ) return(1.0); return(0.0); } int main() { float gpa,average; int x; /* obtain input */ gpa = 0.0; for( x=0; x<CLASSES; x++) { printf("Enter grade (0 to 100) for class #%d: ",x+1); gpa += get_grade(); } average = gpa/(float)CLASSES; /* output results */ printf("Your semester GPA is %.1f\n",average); return(0); }

(GitHub)

The *get_grade()* function uses *fgets()* to obtain input. The *strtod()* function converts input to a decimal value, with the *if* statement (at Line 18) checking for invalid input.

At Line 24, the *if* statement checks the input range: `if( grade<0 || grade>100 )`

The program exits on any invalid input. One improvement you could make would be to have it prompt again, which you can code on your own.

Starting at Line 31, a series of *if* tests return the proper GPA value, with the final *return* statement tossing back zero for values below 60.

In the *main()* function, a *for* loop both gathers input and totals the GPA values returned in the `gpa`

variable. Line 55 calculates the average, dividing `gpa`

by the number of `CLASSES`

, which must be typecast to a *float*: `average = gpa/(float)CLASSES;`

Line 58 outputs the result.

Here’s a sample run:

`Enter grade (0 to 100) for class #1: 99`

Enter grade (0 to 100) for class #2: 98

Enter grade (0 to 100) for class #3: 89

Enter grade (0 to 100) for class #4: 75

Enter grade (0 to 100) for class #5: 100

Your semester GPA is 3.4

And you see that my GPA has improved from when I ran the code in the original Exercise post!

I hope you devised a solution that’s clever and tidy and generates accurate output. The key is to use the *strtod()* functione to evaluate input. Refer to the Lesson on *strtol()* for details on how the function validates input. Otherwise, if whatever crazy method you devised to calculate GPA works, congratulations!

When you posted this exercise I scribbled down a formula to calculate the grade from the percentage:

floor((percentage / 10) – 5)

but for 100% it gives 5 so needs and extra check afterwards to subtract 1 in this case. I can’t think of a way of eliminating this problem. (Unless you want to assume nobody ever gets 100%…!)

Here are some examples:

floor((100 / 10) – 5) = 5 <= NEED TO SUBTRACT 1

floor((90 / 10) – 5) = 4

floor((89 / 10) – 5) = 3

floor((80 / 10) – 5) = 3

floor((79 / 10) – 5) = 2

floor((70 / 10) – 5) = 2

floor((69 / 10) – 5) = 1

floor((60 / 10) – 5) = 1

floor((59 / 10) – 5) = 0

I’ve had issues similar to that in my code – all the time, in fact. When it arises, I have to test for the condition specifically and then make a fix. I believe something similar happened in last month’s Exercise, where I had to account for day-of-the-month overflow. Anyhoo.