Loop showing menu never ends - c

I'm trying to write a simple menu in C.
This is my proposed code:
while (end == 0) {
printf("Main menu\n");
printf("=========\n");
printf("1) Option 1.\n");
printf("2) Option 2.\n");
printf("3) Option 3.\n");
printf("4) Option 4.\n");
printf("0) Exit");
printf("\n");
printf("Choose an option: ");
fgets(&menu_option,1,stdin);
switch (menu_option) {
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
}
}
However, when executing this code, the loop never ends.
What's wrong?
Thank you.
EDIT: when I say "the loop never ends", I want to say that I can't write any option because the menu appears again and again.

From fgets
The fgets() function shall read bytes from stream into the array pointed to by s, until n-1 bytes are read, or a is read and transferred to s, or an end-of-file condition is encountered. The string is then terminated with a null byte.
Since you give a length of 1, n-1 will be 0 and so your input is never stored in menu_option. Change it to a char array
char menu_option[10];
// ...
fgets(menu_option, sizeof(menu_option), stdin);
switch (menu_option[0]) {
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
}
Update:
It is necessary to use char arrays, because you need enough space to store the input. The minimum size for a buffer is two characters, e.g. char buf[2], because fgets stores your input plus a terminating NUL character.
The loop iterates twice or even more times, because when you input e.g. 1 return or 1 3 2 return, it will first return 1, then 3, 2 and finally return. If you want to read the whole line and use the first digit only, your buffer must be larger than just 2, like e.g. 10 or even 256.

fgets reads a string instead of character. The statement
fgets(&menu_option,1,stdin);
Will store a string to menu_option but to store a string you need a size at least 2 bytes.
char menu_option[2];
...
fgets(menu_option,2,stdin);
int c;
while((c = getchar()) != '\n' && c != EOF); // This will be needed to flush your input buffer
switch (menu_option[0]) {
...
...
}

From: http://www.cplusplus.com/reference/cstdio/fgets/
fgets
char * fgets ( char * str, int num, FILE * stream );
Get string from stream.
Reads characters from stream and stores them as a C
string into str until (num-1) characters have been read or either a
newline or the end-of-file is reached, whichever happens first.
A newline character makes fgets stop reading, but it is considered a
valid character by the function and included in the string copied to
str.
A terminating null character is automatically appended after the
characters copied to str.
Since you have specified 1 for the number, 0 bytes are read, and the only thing that happens is that a terminating null character is appended. The result is an infinite loop in which nothing is read.

Since in the comments you expressed dislike for using strings, here's alternative implementation with minimal changes to the question code:
while (end == 0) {
printf("...menu print snipped...\n");
int ch = getchar();
switch (ch) {
case EOF: // end of file or error, fall through to exit option
case '0': end = 1; break;
case '1': option1(); break;
case '2': option2(); break;
case '3': option3(); break;
case '4': option4();
// default: // add error message?
}
// ignore any extra chars in the same line
while ((ch = getchar() != '\n') {
// test for end of file and set end to true
if (ch == EOF) {
end = 1;
break;
}
}
}
Note the extra loop, which will read and discard rest of the input line. Without it, user can enter several options on one line, which is probably not desirable. Also note, if the option functions read more user input, consider how you handle long lines then. For example move the extra loop to be before switch (and add another variable to read discarded chars). Actually you should probably put the extra loop to it's own function discard_until_newline.

Related

scanf() not returning the proper value?

I have a function as part of a larger program to determine the quantity of products sold on each day of the previous week. Here is the function that performs the case switch:
unsigned int switchfn()
{
int productNumber; // product 1 through 5
// only while product 1 through 5 is being entered.
while ((scanf("%d", &productNumber)) != EOF) {
// gather product data
switch (productNumber) {
case '1': // product one
++productOne;
break;
case '2': // product two
++productTwo;
break;
case '3': // product three
++productThree;
break;
case '4': // product four
++productFour;
break;
case '5': // product five
++productFive;
break;
case '\n': // ignore new line
case '\t': // ignore tab
case ' ': // ignore space
break;
default: // catch all other characters
printf("%s", "No such product exists.");
puts(" Please enter a valid product number.");
break;
}
}
return 0;
}
However, when the program runs, it always jumps to the default, even when entering numbers 1 through 5. Is this an issue with what scanf() is returning?
You appear to be getting confused between integers and ASCII digits. You're performing formatted extraction, but inspecting productNumber as if it were the actual ASCII character found in the input.
Remember, '1' is actually 49.
Since you want to cover cases like '\n' too, read into a char with %c instead. Then the extraction operation won't perform the formatting conversion for you as it is now, and your character literal comparisons will be correct.
Case '1' - at this moment you are asking compiler to check did you enter a character '1' - his ASCII value is 49 and that's the reason why he is just skipping to default case. Try to input " %c"
scanf("%d", &productNumber) get productNumber is a interger.
But case '1' : '1' is a char and his ASCII value is 49 and so every time you input a interger, there is no match case just skipping to default case. u can input " %c" to get a char.
Since your scanf function is referencing an integer, you merely have to switch your cases to integers:
case 1:
//your logic
break;
case 2:
//your logic
break;

Switch Statement Not Executing Cases (c)

I made a switch statement, however, it only works with constants already set. If I try to use it with user input, only one of the cases work, every other one doesn't. Now no matter what I enter, it always uses the default case. I tried adding another getchar() to clear the \n character from the buffer but this isn't making a difference. Ill post the entire switch statement here :
char option=' ';
option=getchar();
switch(option){
//Parallel resistance calculations
case 'p':
CLEAR
//PResistance();
printf("RESISTANCE");
getchar();
break;
//Ohm's Law calculations
case 'o':
CLEAR
printf("OHM");
//Ohm();
break;
//Exits program
case 'q':
printf("Good bye! Stay safe in the laboratory! :)\nPress any key to exit");
getchar();
exit(0);
break;
//Error checking
default :
printf("Invalid input, Try again");
break;
}
}
while (option!='q');
I commented out the functions so I could use the print statements to test if its working.
Whenever you input a character or string from stdin in C, always make sure there is no \n in the input buffer. To do this, always getchar() after taking integer or float inputs.
In your case, maybe you've inputted an integer before inputting the character. So try to write a getchar() before taking the character input.

C while loop - code won't work

I've been writing a simple program to check if input letter is a vowel, and my code doesn't work.
The program should take characters as input one by one until % is entered, which will make it exit. It checks if input chars are vowels, and prints the result. Also it reports an error if input is not a letter.
The problem is, it breaks out of the loop on the second step.
Thank you for help, in advance.
PS Sorry, didn't write that there's no error message, it just breaks out of the loop.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main(void)
{
char processed='q';
while(processed != '%')
{
printf("Enter letter to check if it's a vowel, %% to quit.\n");
char input = getchar();
processed = tolower(input);
printf("%c\n", processed);
if (processed == '%')
break;
if (processed < 'a' || processed > 'z')
{
fprintf(stderr, "Input should be a letter\n");
exit(1);
}
switch(processed)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y':
printf ("Vowel\n");
break;
default:
printf ("Non-vowel\n");
}
}
exit(0);
}
Presumably you're entering a character and then hitting [ENTER]. So, in actuality you are entering two characters -- the letter you typed and a line feed (\n). The second time through the loop you get the line feed and find that it's not a letter, so you hit the error case. Perhaps you want to add something like:
if (processed == '\n') {
continue;
}
Someone else mentioned that you're hitting enter after each letter of input, and thus sending a newline ('\n') into your program. Since your program doesn't have a case to handle that, it isn't working right.
You could add code to handle the newline, but using scanf would be easier. Specifically, if you replaced
char indent = getchar();
with
char indent;
scanf("%c\n", &indent);
scanf() would handle the newline and just return back the letters you're interested in.
And you should check scanf()'s return value for errors, of course.

While scanf!=EOF or scanf==1?

Ceteris paribus (well formed data, good buffering practices and what not), is there a reason why I prefer to loop while the return of scanf is 1, rather than !EOF? I may have read this somewhere, or whatever, but I may have it wrong as well. What do other people think?
scanf returns the number of items succesfully converted ... or EOF on error. So code the condition the way it makes sense.
scanfresult = scanf(...);
while (scanfresult != EOF) /* while scanf didn't error */
while (scanfresult == 1) /* while scanf performed 1 assignment */
while (scanfresult > 2) /* while scanf performed 3 or more assignments */
Contrived example
scanfresult = scanf("%d", &a);
/* type "forty two" */
if (scanfresult != EOF) /* not scanf error; runs, but `a` hasn't been assigned */;
if (scanfresult != 1) /* `a` hasn't been assigned */;
Edit: added another more contrived example
int a[5], b[5];
printf("Enter up to 5 pairs of numbers\n");
scanfresult = scanf("%d%d%d%d%d%d%d%d%d%d", a+0,b+0,a+1,b+1,a+2,b+2,a+3,b+3,a+4,b+4);
switch (scanfresult) {
case EOF: assert(0 && "this didn't happen"); break;
case 1: case 3: case 5: case 7: case 9:
printf("I said **pairs of numbers**\n");
break;
case 0:
printf("What am I supposed to do with no numbers?\n");
break;
default:
pairs = scanfresult / 2;
dealwithpairs(a, b, pairs);
break;
}
Depends what you want to do with malformed input - if your scan pattern isn't matched, you can get 0 returned. So if you handle that case outside the loop (for example if you treat it the same as an input error), then compare with 1 (or however many items there are in your scanf call).
From http://www.cplusplus.com/reference/clibrary/cstdio/scanf/
On success, the function returns the
number of items succesfully 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.
The only way to be sure that you read the number of items intended is to compare the return value to that number.

C - Reading user input

I have a program where user input is required, a user types in a number 1-8 to determine how to sort some data, but if the user just hits enter a different function is performed. I get the general idea of how to do this and I thought what I had would work just fine but I'm having some issues when it comes to when the user just hits the enter key. Currently my code looks as follows:
//User input needed for sorting.
fputs("Enter an option (1-8 or Return): ", stdout);
fflush(stdout);
fgets(input, sizeof input, stdin);
printf("%s entered\n", input); //DEBUGGING PURPOSES
//If no option was entered:
if(input == "\n")
{
printf("Performing alternate function.");
}
//An option was entered.
else
{
//Convert input string to an integer value to compare in switch statment.
sscanf(input, "%d", &option);
//Determine how data will be sorted based on option entered.
switch(option)
{
case 1:
printf("Option 1.\n");
break;
case 2:
printf("Option 2.\n");
break;
case 3:
printf("Option 3.\n");
break;
case 4:
printf("Option 4.\n");
break;
case 5:
printf("Option 5.\n");
break;
case 6:
printf("Option 6.\n");
break;
case 7:
printf("Option 7.\n");
break;
case 8:
printf("Option 8.\n");
break;
default:
printf("Error! Invalid option selected!\n");
break;
}
}
Now I've changed the if statement to try input == "", input == " ", and input == "\n" but none of these seems to work. Any advice would be greatly appreciated. Currently from what I can see, the initial if statement fails and the code jumps to the else portion and then prints the default case.
Just to be clear the variables I declared for this code are as follows:
char input[2]; //Used to read user input.
int option = 0; //Convert user input to an integer (Used in switch statement).
The problem is in how you're doing the string comparison (if (input == "\n")). C doesn't have a "native" string type, so to compare strings, you need to use strcmp() instead of ==. Alternatively, you could just compare to the first character of the input: if (input[0] == '\n') .... Since you're then comparing char's instead of strings, the comparison doesn't require a function.
Try:
#include <string.h>
at the top and
if(strcmp(input, "\n") == 0)
in place if your if ( input == ... )
Basically, you have to use string comparison functions in C, you can't use comparison operators.
Try:
input[0] == '\n'
(or *input == '\n')
You need to use single quotes rather than double quotes
if(input == "\n")
compares the input address to the address of the string "\n",
What you want to do is to compare the first character of the input buffer
to the character literal \n like this
if(input[0] == '\n')
Note the use of single quotes around '\n'
You need to capture return code from sscanf, it will tell you how many of the field are "assigned", which in "Enter" key case, return code of 0
edit:
you should use strcmp when comparing string, not the operator "==".
The issue is with strings, you are comparing pointers, i.e. memory addresses. Since the input and "\n" aren't the same exact memory, it always fails (I assume input is a char *). Since you're looking for a single character, you can instead dereference input and compare to a char using single quotes instead of double.
(*input == '\n')
Should work as you intend.

Resources