1

I am trying to write a simple program for a practice problem, written below:

(Sales-Commission Calculator) One large chemical company pays its salespeople on a com- mission basis. The salespeople receive $200 per week plus 9% of their gross sales for that week. For example, a salesperson who sells $5000 worth of chemicals in a week receives $200 plus 9% of $5000, or a total of $650. Develop a program that will input each salesperson’s gross sales for last week and will calculate and display that salesperson’s earnings. Process one salesperson's figures at a time.

I am trying to handle if the user inputs things other than numbers, e.g. strings/char. But, when I try running it and test it by inputting a string/char, it keeps on looping until VSC crashes.

My code:

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

int main(void){
    float sales = 0;
    float salary = 0;

    while (sales != -1)
    {
        printf("Enter sales in dollars (-1 to end): ");
        scanf("%f", &sales);

        while ((sales != -1) && !(sales >= 0))
        {
            puts("Input error, please try again");
            fflush(stdin);
            printf("Enter sales in dollars (-1 to end): ");
            scanf("%f", &sales);
        }

        if (sales != -1)
        {
            salary = 200 + (0.09 * sales);

            printf("Salary is: $%.2f\n", salary);
        }
    }

    return 0;
}

I used a similar approach in another program and it works just fine, so I don't know what the problem is here.

The code of the other program:

while(!(collected >= 0))
{
    fflush(stdin);
    puts("Input error, please try again.");
    printf("Enter total amount collected (-1 to quit): $");
    scanf("%f", &collected);
}

An explanation would be highly appreciated!

klutt
  • 30,332
  • 17
  • 55
  • 95

1 Answers1

2

scanf("%f", ...) will never accept anything that is not a properly formatted number, so if you enter a character all your scanf() calls will just see that there is a character to be consumed, but the format specifier does not allow it, and they will not read anything and return 0. This, plus your while, will cause an endless loop if anything that is not a valid number is entered.

You have to either read everything up to the end of the line, or skip unwanted characters when scanf returns 0 (meaning it was not able to read any value correctly). Also, check if scanf returns EOF, which means there was either an error or the end of file was reached.

In any case, fflush(stdin) is undefined behavior, never do it!

A correct way to do this would be:

#include <stdio.h>

int main(void) {
    float sales = 0;
    float salary;
    int res;

    do {
        printf("Enter sales in dollars (-1 to end): ");
        fflush(stdout);

        res = scanf("%f", &sales);

        if (res == EOF) {
            // Something bad happened.

            if (feof(stdin))
                fputs("End of input reached.\n", stderr);
            else
                perror("Error reading input");

            return 1;
        }

        if (sales != -1 && sales < 0) {
            // Perhaps it would be a better idea to say "invalid value" here?
            puts("Input error, please try again.");
            res = 0;
        }
        
        // Either the value was read correctly (res = 1) or it wasn't (res = 0).
        // In any case, consume the rest of the line.
        scanf("%*[^\n]");

    } while (res != 1 && sales != -1.0);

    if (sales != -1.0) {
        salary = 200 + (0.09 * sales);
        printf("Salary is: $%.2f\n", salary);
    }

    return 0;
}
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
  • The output loop on my terminal looks like this(for my original code): Enter sales in dollars (-1 to end): Salary is: $200.00 Enter sales in dollars (-1 to end): Salary is: $200.00 Why doesnt it run thought the nested while loop and only goes through the if selection? My intention was if the user inputs the wrong format, it would be caught by the while nested loop and they will be forced to fix it. – lowkeyhuman Oct 12 '20 at 11:00
  • @lowkeyhuman little logic mistake on my part, I've edited the code, check it out again. You do not need the nested loop, one loop will suffice. – Marco Bonelli Oct 12 '20 at 11:03
  • Nit - `%f` will skip over leading whitespace, the leading blank in the format string isn’t necessary. – John Bode Oct 12 '20 at 11:47