1

I am making a program that inputs three numbers and then calculates a few different things (each thing has to be its own function). The program starts off telling the user their options and waiting for their input. After any of the cases execute the program will print the menu again except it will use the default case, then it will print the menu and ask for a input. Any help would be greatly appreciated.

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

void greeting() {
    printf("Welcome to Dr. Computer's Mathatorium \n"); // this is a seperate function just because
    printf("Remember to use capital letters when selecting \n");
}

//This getNum function is used to the get the number
int getNum () 
{
    int a;

    printf("Enter your first integer:"); //tells user to input number
    scanf("%i", &a); //input

    return a;
}

// gets the sum of the numbers
int getSum (int f, int g, int h) 
{
    return (f + g + h);
}

// gets the sum of the numbers
int getPro (int f, int g, int h) 
{
    return (f * g * h);
}

// gets the sum of the numbers
int getAvg (int f, int g, int h) 
{
    return (f * g * h)/3;
}

// gets the sum of the numbers
int getLow (int f, int g, int h) 
{
    return (f + g + h); //NEEDS ADJUSTING
}

main()
{
    int first, second, third, sum, pro, avg, low;

    char choice;
    greeting ();
    do {
        printf("Main Menu\n");
        printf("A) Get Three Integers\n");
        printf("B) Display the Sum\n");
        printf("C) Display the Product\n");
        printf("D) Display the Average\n");
        printf("E) Display the lowest\n");
        printf("F) Quit\n");
        scanf("%c", &choice);

        //here comes the switches to route the choices
        switch(choice){  
        case 'A':
            first = getNum ();
            second = getNum ();
            third = getNum ();
            printf("first is: %i\n", first);
            printf("second is: %i\n", second);
            printf("third is: %i\n", third);
            break;

        case 'B':
            sum = getSum (first, second, third);
            printf("sum is: %i\n", sum);
            break;

        case 'C':
            pro = getPro (first, second, third);
            printf("product is: %i\n", pro);
            break;

        case 'D':
            avg = getAvg (first, second, third);
            printf("average is: %i\n", avg);
            break;

        case 'E':
            avg = getAvg (first, second, third); //NOT DONE YET
            printf("average is: %i\n", avg); //REMEMBER TO FIX
            break;

        default: 
            printf("INVALID CHOICE!\n");
            break;    
        }
    } while (choice != 'F');

    return 0;
}
Jongware
  • 22,200
  • 8
  • 54
  • 100
user2603473
  • 25
  • 1
  • 5
  • 1
    Question is not much clear. Can you please re-frame your trouble? – Sanket Tarun Shah Sep 14 '14 at 09:33
  • `do{...}while()` actually executes the loop then checks for condition. May b ur looking for `while(){..}` – DOOM Sep 14 '14 at 09:35
  • 2
    When you enter "A" and press newline, two characters are sent from your terminal: 'A' and '\n' (newline). The newline probably causes the second execution of switch. Just ignore newlines. – Marian Sep 14 '14 at 09:38
  • The issue is not consuming the EOL which is interpreted as invalid input, then `default` then redisplay. But aside from being prompted for the "first" integer three times on `A`, it provides the correct sum at least. – ChiefTwoPencils Sep 14 '14 at 09:42
  • 1
    Really you should avoid using `scanf` entirely. http://www.c-faq.com/stdio/scanfprobs.html – jamesdlin Sep 14 '14 at 09:57
  • You should compile your code with all warnings and debug info (e.g. `gcc -Wall -g`) and **use the debugger** (e.g. `gdb`) perhaps to run it step by step and understand what is happening. Also you should use the return value of `scanf` (it gives the number of successfully scanned items). – Basile Starynkevitch Sep 14 '14 at 10:11
  • 3
    Please do not edit your question to add "Fixed" or "Solved". The Stack Overflow way is to *mark an answer as accepted* (if you found the answer yourself, you can even mark your own). Please take the [Friendly Introductory Welcome To Stack Overflow Tour](http://stackoverflow.com/tour). – Jongware Sep 14 '14 at 10:15
  • The trouble is at the `scanf` line, you are reading the character however the `` key that the user pressed after the letter is still hanging around in the buffer. Which causes the `scanf` in the next loop to not *block* and since this time it doesn't match any of the valid choices it executes the 'default' behavior – Ahmed Masud May 29 '18 at 03:38
  • Possible duplicate of [How to do scanf for single char in C](https://stackoverflow.com/questions/13542055/how-to-do-scanf-for-single-char-in-c) – Ahmed Masud May 29 '18 at 03:58
  • As I said this question has already been answered here https://stackoverflow.com/questions/13542055/how-to-do-scanf-for-single-char-in-c .... Just put a space before `%c` in your `scanf` ... So `scanf(" %c", &choice);` to fix your issue. Having said that, in real world using `scanf` is a bad idea, because it is really sucky for a variety of reasons. However this is an assignment :-) so I'll just show you the main method. The other part that's important is to have a `case 'F': break;` in your switch statement so that you don't treat `F` as an invalid input. – Ahmed Masud May 29 '18 at 04:00

2 Answers2

1

There are many ways to fix this problem. Here is one solution that works in this limited context - change line 58 to:

scanf(" %c", &choice);

I've added a space before the % specifier. This means "skip any whitespace characters in stdin, then read the next non-whitespace character and store that at the memory address of the 'choice' variable".

It is also worth pointing out that a choice of 'F' will cause the program to print "INVALID CHOICE!" before closing. This is because there is no switch-case for 'F' so it falls to the default, invalid case before exiting the do-while loop.


Why?

Let's do a desk check. Say you've got an input stream such as:

{ 'A', '\n', '1', '\n', '2', '\n', '3', '\n', 'B', '\n', 'F', '\n', '\0'  }

You will notice that each input is well formatted - only one character followed by a newline, and that the stream has a newline before the terminating character. If you want to handle unformatted input I would recommend against using scanf() to begin with, since scanf stands for scan formatted string.

The first reading of the input stream in the original poster's code is this statement on line 58:

scanf("%c", &choice);

This means "read the next character from stdin and store it at the memory address of the 'choice' variable".

After that line, choice='A' and your input stream looks like this:

{ '\n', '1', '\n', '2', '\n', '3', '\n', 'B', '\n', 'F', '\n', '\0' }

If we follow the code the switch statement stops at case 'A' and the next read is during the function call to getNum() on line 63. This jumps to line 15 where we see the statement:

scanf("%i", &a); //input

This means "read the next integer from stdin and store it at the memory address of the 'a' variable". And when I say "read the next integer" I mean "skip any whitespace characters, then read a '+' or '-' symbol if present, then keep reading characters until you find one that doesn't match the set {'0','1','2','3','4','5','6','7','8','9'}, then convert to an integer"[1].

If we follow that semi-complicated procedure we skip the '\n' because it is a whitespace character, read the '1', then stop and convert the '1' character into the numeric value 1 and store that in the variable a.

So now the input stream looks like this:

{ '\n', '2', '\n', '3', '\n', 'B', '\n', 'F', '\n', '\0' }

And the local variables in the main() function are:

choice = 'A'
first = 1

Next we see that getNum() is called two more times on lines 64 and 65. Keep following and you will have an input stream like this:

{ '\n', 'B', '\n', 'F', '\n', '\0' }

While the local variables in the main function are as follows:

choice = 'A'
first = 1
second = 2
third = 3

The next read is after we loop back to line 58:

scanf("%c", &choice);

If you remember, that means "read the next character from stdin and store it at the memory address of the 'choice' variable". The next character is '\n', so after this line the input stream looks like this:

{ 'B', '\n', 'F', '\n', '\0' }

And local variables to the main() function are as follows:

choice = '\n'
first = 1
second = 2
third = 3

Now we have a problem! If we follow the code, the switch statement stops at case default and the program prints "INVALID CHOICE!". Instead of reading the newline on line 58 we want to skip any whitespace and then read the first character. See above for one solution.

[1] ISO/IEC 9899-1990 §7.9.6.2 (pages 135-136)

Max
  • 87
  • 4
-1

Try this code, it's your program with a few changes:

#include <stdio.h>


void greeting() {

printf("Welcome to Dr. Computer's Mathatorium \n"); // this is a seperate function just because
printf("Remember to use capital letters when selecting \n");
}


int getNum () //This getNum function is used to the get the number
{
int a;

printf("Enter your first integer:"); //tells user to input number
scanf("%i", &a); //input

return a;
}
int getSum (int f, int g, int h) // gets the sum of the numbers
{ return (f + g + h);


}
int getPro (int f, int g, int h) // gets the sum of the numbers
{ return (f * g * h);


}
int getAvg (int f, int g, int h) // gets the sum of the numbers
{ return (f * g * h)/3;


}
int getLow (int f, int g, int h) // gets the sum of the numbers
{ return (f + g + h); //NEEDS ADJUSTING


}

int main(void)
{
   int first, second, third, sum, pro, avg;

char choice;
greeting ();
do {
printf("Main Menu\n");
printf("A) Get Three Integers\n");
printf("B) Display the Sum\n");
printf("C) Display the Product\n");
printf("D) Display the Average\n");
printf("E) Display the lowest\n");
printf("F) Quit\n");
fseek(stdin,0,SEEK_END); // change
choice = getc(stdin); // change
//scanf("%c", &choice);

//here comes the switches to route the choices
switch(choice){  
    case 'A':    
    case 'a': // change
        first = getNum ();
        second = getNum ();
        third = getNum ();
        printf("first is: %i\n", first);
        printf("second is: %i\n", second);
        printf("third is: %i\n", third);
        break;

    case 'B':
    case 'b': // change
        sum = getSum (first, second, third);
        printf("sum is: %i\n", sum);
        break;

    case 'C':
    case 'c': // change
        pro = getPro (first, second, third);
        printf("product is: %i\n", pro);
        break;

    case 'D':
    case 'd': // change
        avg = getAvg (first, second, third);
        printf("average is: %i\n", avg);
        break;

    case 'E':
    case 'e': // change
        avg = getAvg (first, second, third); //NOT DONE YET
        printf("average is: %i\n", avg); //REMEMBER TO FIX
         break;

    default: 
        printf("INVALID CHOICE!\n");
        break;

}
} while (choice != 'F' && choice != 'f'); // change

   return 0;
}
Avi
  • 1
  • 1
  • 2
    While your code may be exactly what the OP needed, it would be more helpful if you listed and described your changes separately. As it is, one needs a line-by-line comparison to *find* your changes; and then one does not know *why* you changed it. – Jongware Sep 14 '14 at 10:18
  • Please explain the solution – Ahmed Masud May 29 '18 at 03:35