0

Sometimes I get the right answer, like when I enter 87 and 3 it gives me back 261, but when I exit the program and re-run it, sometimes it returns45481185383493847891312640.000000`, or some other crazy number.

#include <stdio.h>

int main() {
    float pts = 0;
    float avg;
    float grade;
    float total;
    int f = 1;

    while (f == 1) {
        printf("Choose a Course Grade, and the amount of points that the course is worth: \n"
               "Enter -1 at the beginning if you want to exit\n");
        scanf("%f %f", &grade, &avg);
        if (grade == -1) {
            break;
        }
        pts += avg;
        total += (avg * grade);
        printf("%f\n", total);
    }
    printf("%f\n", (total / pts));
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
ido91198
  • 87
  • 5
  • 4
    `total` is uninitialized. Also performing `==` on floats is a dangerous game. – Eugene Sh. Jul 09 '19 at 16:27
  • 1
    `total += (avg * grade)` <- this is undefined behavior when `total` is uninitialized – Morten Jensen Jul 09 '19 at 16:29
  • Thank you! I'll change it! And why is it dangerous to perform == on floats? – ido91198 Jul 09 '19 at 16:35
  • Because `float` representation is imprecise and may not have the *exact* same value as the one you are comparing to. – Eugene Sh. Jul 09 '19 at 16:36
  • Please read [this](https://stackoverflow.com/questions/4682889/is-floating-point-ever-ok) for more about comparing floating point values. There is a lot of information about it, very easy to find. In this case, `if(grade < 0)` is safer, *even though* `-1` entered will be an exact representation. It's a better catch. – Weather Vane Jul 09 '19 at 16:46
  • Thanks! I'll read! – ido91198 Jul 09 '19 at 16:47
  • @EugeneSh.: When the user enters “-1” for the `scanf` to `grade`, `grade` will have the value −1, and comparing it with `==` is not dangerous. – Eric Postpischil Jul 09 '19 at 17:18
  • @EricPostpischil Won't the RHS of `==` be converted to `double`? While LHS to `float` and then to `double`. – Eugene Sh. Jul 09 '19 at 17:19
  • @EugeneSh.: So? The result of converting a `float` value of −1 to `double` is −1. – Eric Postpischil Jul 09 '19 at 17:24
  • @EricPostpischil I am not talking about the specific value, but about general approach. This is why I said it is dangerous and not wrong in this case. In the previous comment I assumed you are pointing to the rule saying that conversion of the literal `1` to `double` will follow the same rules as the conversion performed by `scanf` – Eugene Sh. Jul 09 '19 at 17:26
  • @EugeneSh.: It is not dangerous. `==` is in fact one floating-point operation that is performed perfectly—it has no error. If the two operands are equal, it evaluates to true. Otherwise, it evaluates to false. And the statement that the `float` representation is imprecise is false. Per the IEEE-754 specification, and the C standard’s description of floating-point, a floating-point object represents one specific number (or NaN or infinity) exactly. It is not imprecise at all. The **operations**, not the **numbers**, introduce rounding. And there is not going to be any rounding error with −1. – Eric Postpischil Jul 09 '19 at 17:31
  • @EugeneSh.: Furthermore, your question about converting to `double` suggests you think that might cause some sort of error. But every value representable in `float` is representable in `double` (C 2018 6.2.5 10). So the conversion never rounds anything; the conversion of an actual `float` value (versus temporary values that C permits with excess precision) to `double` is always exact. – Eric Postpischil Jul 09 '19 at 17:33

1 Answers1

3

The program has undefined behavior because the local variable total is uninitialized.

Initialize it to 0 and test the return value of scanf() to avoid undefined behavior, which explains your observations.

Here is a corrected version:

#include <stdio.h>

int main() {
    float pts = 0.0;
    float total = 0.0;
    float avg;
    float grade;

    for (;;) {
        printf("Enter a Course Grade or -1 to exit: ");
        if (scanf("%f", &grade) != 1 || grade == -1)
            break;
        printf("Enter a the amount of points that the course is worth: ");
        if (scanf("%f", &avg) != 1)
            break
        pts += avg;
        total += avg * grade;
        printf("%f\n", total);
    }
    printf("%f\n", total / pts);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Better if you use a float literal, like `0.0F` to initialize `total`. Initializing floating point variables with integer literals is good just to impress students because C is capable of doing it. Something that has given far more problems than solved them. – Luis Colorado Jul 11 '19 at 19:48
  • @LuisColorado: you have a point, making floating point constants more explicit is better. On the same note, type `float` is not a good choice anyway, `double` would be much better suited for most floating point uses. – chqrlie Jul 11 '19 at 21:48