Menu prints twice and default runs even when case doesn't match - c

I am trying to show the user a menu and allow them to pick from the options. It's in a while loop because it has to iterate until option "e" is picked to exit the program. I included the "default" option as a fail-safe for if the user inputs a value that is not accepted. The default case always runs no matter what I do and the menu always appears twice after the initial run of the code.
I have tried changing "getchar()" to the scanf and it still produces the same duplicated output. I have also tried doing away with the switch entirely, but I get the same result using if/then statements. I have attached my full code and any help is appreciated thank you!!
#include <stdio.h>
#include <stdlib.h>
// function for the menu
char menu() {
printf("Please select from the following menu: \n");
// setting up the menu from here
printf("a. input the data files location \n");
printf("b. enter the time interval \n");
printf("c. process and display the US Life Expectancy Data \n");
printf("d. process and display the Statistics of All Data \n");
printf("e. exit the program \n");
}
char options(char choice) {
switch (choice) {
case 'a':
printf("choice a\n");
break;
case 'b':
printf("choice b\n");
break;
case 'c':
printf("choice c\n");
break;
case 'd':
printf("choice d\n");
break;
case 'e':
break;
default: // default when none of the cases are matched
printf("Invalid input\n");
break;
}
}
// main function
int main(void) {
char choice;
do {
menu();
while ((choice = getchar()) == "\n") {};
if (choice == EOF) {
exit(1);
}
options(choice);
} while (choice != 'e');
}

The problem is that your code doesn't handle newlines. In other words when you type a followed by ENTER, your code actually receives two characters. The 'a' and a '\n'. Therefore the menu will be printed twice and you get an "invalid input".
A quick fix could be:
choice = getchar(); --> while ((choice = getchar()) == '\n') {};
That said, you should change choice to be an int and also do:
int choice;
....
....
while ((choice = getchar()) == '\n') {};
if (choice == EOF)
{
// Fatal input error
exit(1);
}
Finally, it's a bad idea to have choice as a global. Instead put it in main and pass it as an argument to the function options. But don't pass it to menu. So do:
char options() { --> char options(int choice) {
and
int main(void) {
int choice;
do {
menu();
while ((choice = getchar()) == '\n') {}; // ignore newlines
if (choice == EOF)
{
// Fatal input error
exit(1);
}
options(choice);
} while (choice != 'e');
}

Related

Switch default is not showing when it should

In my C program which is using switch I have problem with my int variable.
My code is:
while(1) {
printf("0. END\n1. TRANSLATE\n2. TEST FROM LESSON\n3. RANDOM"
" WORDS TEST\n4. SHOW DICTIONARY\n5. ADD WORD\n"
"6. DELETE WORD\nYOUR CHOICE: ");
scanf("%d",&option);
fflush(stdin);
printf("\n");
switch(option) {
case 0: {
exit(0);
break;
}
case 1: {
system("cls");
translate();
printf("\n");
break;
}
case 2: {
system("cls");
lessons();
printf("\n");
break;
}
case 3: {
randomFromLessons();
printf("\n");
break;
}
case 4: {
system("cls");
allWords();
printf("\n");
break;
}
case 5: {
system("cls");
addWord();
break;
}
case 6: {
system("cls");
deleteWord();
printf("\n");
break;
}
default: {
printf("---------------\n");
printf("WRONG VALUE.\n");
printf("---------------\n\n");
}
}
}
When I type 'd' into option var. it shows default, which is what I want, BUT when I press number 1 which starts method named "translate()" and then get back into main menu and press 'd' again it gets me back into "translate()" instead of showing the default.
When I use char instead of int, there is no problem.
So, what exactly is the problem? What keeps happening? What am I doing wrong? Isn't using char in switch the best option overall then?
If you wish to allow text input, you should read the input as a string with fgets and then convert to integers as needed.
If you only wish to accept numbers, you should check the result of scanf to see if it succeeded - in this case it will return 1 when successful, in case it managed to read 1 parameter. If not successful, it won't overwrite option but keep the previous value - that's why you get the behavior you describe.
Furthermore fflush(stdin); is undefined behavior since fflush was never meant to be used on input streams. To just discard the line feed character from stdin you can add single getchar().
So you could fix the code into something like this:
int result;
while(1)
{
result = scanf("%d",&option);
getchar();
if(result == 1)
break;
else
printf("some error message\n");
}
switch(option)
...

How to loop a menu which the option variable is int when the user inserts a text?

I am kind of a beginner and have a little problem when trying to loop a menu.
Let's take this for example:
int option = 0;
do {
printf("Menu\n");
printf("[1] Insert\n");
printf("[2] List\n");
printf("[0] Exit\n");
printf("\nOption: ");
scanf("%i",&option);
switch(option)
{
case 1: {
// code
break; }
case 2: {
// code
break; }
default: {
// error
}
}
} while(option != 0);
This will work for numbers, yet, as the option is an integer, if the user types a text, such as "a" or "owkefok" or even "ewf432k", the program will just break;
How do I give an error such as if(containstcharacters) then(error) while repeating the menu? Is it possible without changing the option to char?
You can check for return value of scanf(). Like this :
int num;
if(scanf("%d%c", &num) != 1)
printf("failure\n");
else
printf("valid integer followed by enter key\n");
On success, the function returns the number of items successfully read. This count can match the expected number of readings or fewer, even zero, if a matching failure happens. In the case of an input failure before any data could be successfully read, EOF is returned.
In simple words, if it can read your user input it will return the number of item it could read successfully.
So in your case the code will be :
int option = 0;
do {
printf("Menu\n");
printf("[1] Insert\n");
printf("[2] List\n");
printf("[0] Exit\n");
printf("\nOption: ");
scanf("%i",&option);
int check = scanf("%d%c", &num);
if(check!=1) {
//error
}else{
switch(option)
{
case 1: {
// code
break; }
case 2: {
// code
break; }
default: {
// error
}
}
} while(option != 0);
}
Instead of
scanf("%i",&option);
use e.g.
char str_option[100];
scanf("%s", &str_option);
so you will read into a string instead to an int. Then you may extract the first character of it and convert it to its numerical value (in spite it doesn't need be a digit) by the well-known trick
option = str_option[0] - '0' // Converts '0' to 0, '1' to 1, and so on
Then you need not change the rest of your code except for inserting in your switch statement:
case 0 : break; // To not fall into "default:" for error-handling
(By the way you need not use { } in the individual cases of the switch statement as all commands are executed regardless of them until they meet break; .)

Having problems with creating menu in C using do..while and if..else statement

I am new in this world of programming. I am learning programming at my school. My teacher recently ask the class to create a menu with limited selection that will end with a sentinel value.
So here's my coding:
#include <stdio.h>
void menu(void);
void choice1();
void choice2();
void choice3();
char choice;
int main() {
do {
menu();
if (choice =='1')
choice1();
else if (choice =='2')
choice2();
else if (choice =='3')
choice3();
else if (choice =='4')
break;
else
printf("Invalid character.");
} while (choice != '4');
return 0;
}
void menu(void) {
printf("\nMenu:\n\n");
printf("1) Choice 1.\n");
printf("2) Choice 2.\n");
printf("3) Choice 3.\n");
printf("Choose any of the above, or enter 4 to quit.\n\n");
scanf("%c", &choice);
}
void choice1() {
printf("\nChoice 1\n");
}
void choice2() {
printf("\nChoice 2\n");
}
void choice3() {
printf("\nChoice 3\n");
}
When I try to run it, by putting the number 1, 2, 3, the output came out but after that the function menu() and also the line "Invalid character." came out. As for as the other character, the menu() and the "Invalid character" came out twice. Number 4 does end the program. Is there any improvement that I can make to make sure the menu() and the line "Invalid character." does not come out unnecessarily?
In line-buffered input, the newline character lingers in the buffer after you read a single character for 'choice' and hence you get Invalid character. unintentionally.
You are required clear the buffer after reading the choice
scanf("%c", &choice);
while(getchar()!='\n')
/* Wasting the buffer
* Hence ensuring that the character you enter
* is indeed considered for 'choice'
*/
;; // Do nothing in particular
As a side note, your program looks like a typical use-case for the switch-case command and maybe your teacher expects you to use it.
Considering the scenario mentioned by #chqrlie in [ this ] comment, the workaround is to add after
scanf("%c", &choice);
the below lines
int c;
while ((c = getchar()) != EOF && c != '\n')
;; //Wasting the buffer
The problem is simple: the terminal is line buffered: you must press enter for the input to become available to your program, the first scanf("%c", &choice) retrieves the character typed and the second call retrieves the linefeed ('\n') that was generated by the enter key.
There are multiple ways to avoid this problem. You can add a space in the scanf format before the %c: scanf(" %c", &choice); or you can read characters after the first until you get a '\n'.
Note that you must check the return value of scanf to avoid undefined behavior if the user enters an end of file. It is also advisable to avoid global variables: the function menu() should return the choice specified. Using a switch statement is also more idiomatic for this.
Here is a corrected version:
#include <stdio.h>
int menu(void);
void choice1(void);
void choice2(void);
void choice3(void);
int main(void) {
int ch;
for (;;) {
switch (ch = menu()) {
case '1': choice1(); continue;
case '2': choice2(); continue;
case '3': choice3(); continue;
case '4':
case EOF: break;
default: printf("Invalid character %c\n", ch); continue;
}
break;
}
return 0;
}
int menu(void) {
char choice;
printf("\nMenu:\n\n");
printf("1) Choice 1.\n");
printf("2) Choice 2.\n");
printf("3) Choice 3.\n");
printf("Choose any of the above, or enter 4 to quit.\n\n");
if (scanf(" %c", &choice) == 1)
return choice;
else
return EOF;
}
void choice1(void) {
printf("\nChoice 1\n");
}
void choice2(void) {
printf("\nChoice 2\n");
}
void choice3(void) {
printf("\nChoice 3\n");
}
As already mentioned in other answers the problem is the newline character.
When you press 1 followed by enter, you'll get two chars, i.e. 1 and \n. So your loop runs twice and prints Invalid character when \n is processed.
Here is an alternative solution for your problem. Just add a space before %c.
scanf(" %c", &choice);
This works because the space will match any number of white-space characters and thereby match the \n and remove it.
From the man page:
A sequence of white-space characters (space, tab, newline,
etc.......). This directive matches any amount of
white space, including none, in the input.
Additional comments
You should always check the value returned by scanf to make sure you read the correct number of values.
if (scanf(" %c", &choice) != 1)
{
// Add error handling ....
// For instance you could terminate the program like
exit(1);
}
In your program choice is a global variable. In general global variables should be avoid if possible. In your case you could make choice a local variable in main and let menu return a char. Like:
// char choice; Remove global variable
int main() {
char choice; // Add local variable
do {
choice = menu(); // Assign to local variable
.....
}
char menu(void) { // Make the function return a char
char choice; // Add local variable
printf("\nMenu:\n\n");
printf("1) Choice 1.\n");
printf("2) Choice 2.\n");
printf("3) Choice 3.\n");
printf("Choose any of the above, or enter 4 to quit.\n\n");
if (scanf("%c", &choice) != 1) exit(1); // Assign to local variable
// On failure -> exit
return choice; // Return value of local variable
}
You can write scanf(" %c",&choice); (with whitespace) instead of scanf("%c",&choice);
When I try to run it, by putting the number 1, 2, 3, the output came
out but after that the function menu() and also the line "Invalid
character." came out.
It's happening because of the new line character you press after each number. It's itself a character and loop is iterated one more time for this. As it is an invalid character, that's why "Invalid character." is showing.
Try using getchar() after scanf().
Edit: fixed my previous while loop which may exit incorrectedly:
#include <stdio.h>
int main() {
int choice;
printf("Menu:\n\n");
printf("1) Choice 1.\n");
printf("2) Choice 2.\n");
printf("2) Choice 3.\n");
printf("Choose any of the above, or enter 4 to quit.\n\n");
while (1) {
char c = scanf("%d",&choice);
if (c == EOF || choice == 4) break;
if (choice == 1 || choice == 2 || choice == 3) {
printf("Choice %d.\n", choice);
} else {
printf("Invalid character.\n");
}
}
return 0;
}
You can use function if you want, but not necessary in this case. You need to understand how many times your loop actually runs and compare it to that you expect.
My previous code:
#include <stdio.h>
int main() {
int choice;
printf("Menu:\n\n");
printf("1) Choice 1.\n");
printf("2) Choice 2.\n");
printf("2) Choice 3.\n");
printf("Choose any of the above, or enter 4 to quit.\n\n");
while (scanf("%d", &choice) && choice != 4) {
if (choice == 1 || choice == 2 || choice == 3) {
printf("Choice %d.\n", choice);
} else {
printf("Invalid character.\n");
}
}
return 0;
}

C: Problems with using getchar and switch case to get user input for a main menu

I know there are many threads similar to this one, however, those threads didn't really help me out. I am new to C, so I might be just making a silly mistake, but I don't know what I'm doing wrong.
I am trying to create a main menu like this:
Main menu:
1. Play
2. Reset
3. Display
When users press 1, I want it to print play game, when 2 is pressed, I want it to print Reset, and so on.
However, with my code, when user presses 1, it prints "play game", and when users presses 2 or 3, it doesn't print anything.
int main(){
int input;
/*Displays the menu to user*/
printf("Main menu\n");
printf("1.Play\n");
printf("2.Reset\n");
printf("3.Display\n");
printf("please enter something:\n");
input=getchar();
switch(input){
case'1':
printf("play game\n");
break;
case'2':
printf("reset\n");
break;
case'3':
printf("Display\n");
break;
default:
printf("invalid\n");
break;
}
{
getchar();
while(input != '3');
}
return EXIT_SUCCESS;
}
So I know I might be making a silly mistake, but I just can't figure what I am doing wrong. I have also looked at other threads and none them have helped me.
I think you are looking for do-while loop. You want to nest your switch inside this do-while to repeatedly execute it.
Also, note the extra getchar() call to consume the Enter that was typed after the number.
#include <stdio.h>
#include <stdlib.h>
int main(){
int input;
/*Displays the menu to user*/
printf("Main menu\n");
printf("1.Play\n");
printf("2.Reset\n");
printf("3.Display\n");
printf("please enter something:\n");
do{
input=getchar();
getchar();
switch(input){
case'1':
printf("play game\n");
break;
case'2':
printf("reset\n");
break;
case'3':
printf("Display\n");
break;
default:
printf("invalid\n");
break;
}
} while(input != '3');
return EXIT_SUCCESS;
}

switch case not working properly in C

In my program there is a minor problem.
When I press 2 or 3 or 4 it will display the properly but after that when I
press the a or b or c etc., it will display previous one result instead of print the Invalid option.
How can I fix this?
#include <stdio.h>
#include <string.h>
typedef struct vehicle
{
char name[100];
char lice_no[25];
int vehicle_type;
char cmpny_name[100];
int menu_year;
}record;
int main(void)
{
int i,choice;
FILE *fp1,*fp2;
char oname[100];
record det,det1;
int recsize;
char c;
fp1 = fopen("record.dat" , "r+");
if(fp1 == NULL)
{
fp1 = fopen("record.dat" , "w+");
if(fp1 == NULL)
{
printf("error in opening file : \n");
return -1;
}
}
recsize = sizeof(det);
do
{
printf("\t\"enter the choice\"\n");
printf("1 : adding the record\n");
printf("2 : delete the record\n");
printf("3 : editing the record\n");
printf("4 : display the record\n");
printf("5 : exit the program\n");
fflush(stdin);
scanf("%d" , &choice);
scanf("%c" , &c);
switch(choice)
{
case 1 :
{
printf("In this add logic\n")
break;
}
case 2 :
{
printf("In this case delete logic\n");
break;
}
case 3 :
{
printf("In this case edit logic\n");
break;
}
case 4 :
{
printf("display logic\n");
break;
}
case 5 :
{
printf("exit logic\n");
break;
}
default :
{
printf("\"Invalid option\"\n");
break;
}
}
}
while(1);
return 0;
}
It looks like you are getting the numbers into Choice, and the chars into c.
but you are only using the Choice var in the switch, you are never checking the C var.
So essentially, if you hit a letter it is storing it in the C var, and then using the old value in Choice again.
Hmm, one of the things wrong in your codes is the:
scanf("%c" , &c);
because, the scanf function requires the user to press the enter key before it could store the character to its respective variable.
So if the compiler reads the line:
scanf("%c" , &c);
it reads your input, PLUS, the ENTER.
Thus forcing the scanf function to store your input, PLUS, the ENTER, into your character variable.
It would be better if you would use getche() or getch() instead of using scanf() function, and please do not ever use:
scanf("%c" , &c);
because it would generate an error.
Sample of usage of getche() or getch() function:
c=getche(); //waits for a keypress and stores it on a variable
c=getch(); //waits for a keypress and stores it on a variable
the difference between the two is that the getche() displays your keypress while the getch() does not.
Note: Do not forget to put
#include<conio.h>
Added info:
If you still want to go on using the scanf() function just make sure that you declare your favorite variable as:
char c[20];
then you may use:
scanf("%s", &c);
but your variable, can only hold up to 19 characters, as how we declared on your character array.
And the summary is do not use:
scanf("%c", &c);
because, it can affect your other scanf() functions. :)
SOLUTION(Spoiler Warning):
#include <stdio.h>
#include <string.h>
#include <conio.h>
typedef struct vehicle
{
char name[100];
char lice_no[25];
int vehicle_type;
char cmpny_name[100];
int menu_year;
}record;
int main(void)
{
int i; //removed choice from int
FILE *fp1,*fp2;
char oname[100];
record det,det1;
char choice; //made the variable choice a character
int recsize;
char c;
fp1 = fopen("record.dat" , "r+");
if(fp1 == NULL)
{
fp1 = fopen("record.dat" , "w+");
if(fp1 == NULL)
{
printf("error in opening file : \n");
return -1;
}
}
recsize = sizeof(det);
do
{
printf("\t\"enter the choice\"\n");
printf("1 : adding the record\n");
printf("2 : delete the record\n");
printf("3 : editing the record\n");
printf("4 : display the record\n");
printf("5 : exit the program\n");
fflush(stdin);
choice = getche(); // or getch()
switch(choice) //changed the target character
{
case '1' : //changed the case from 1 to '1'
{
printf("In this add logic\n");
break;
}
case '2' : //changed the case from 2 to '2'
{
printf("In this case delete logic\n");
break;
}
case '3' : //changed the case from 3 to '3'
{
printf("In this case edit logic\n");
break;
}
case '4' : //changed the case from 4 to '4'
{
printf("display logic\n");
break;
}
case '5' : //changed the case from 5 to '5'
{
printf("exit logic\n");
break;
}
default :
{
printf("\"Invalid option\"\n");
break;
}
}
}
while(1);
return 0;
}
You can also use switch to compare characters. Just change the values
case 1:
to
case '1':
scanf returns you a value, which you don't check.
When used with %d specifier - it should parse an integer. Since you enter a non-integer value - scanf returns you an error code, and choice is unchanged
It's because in c when you are reading characters as integers (scanf("%d" , &choice);) it takes the ascii code of the characters for example a = 97, b = 98 c = 99 d = 100 if you want to read a as 1 b as 2 etc you will have to add some extra code that tells the programme if the number is equal to the ascii code of a b c d or e subtract it with 96 so you get 1,2,3..

Resources