I've been looking at this issue for a while now and I know it's super basic but can't for the life of me work out where it's going wrong.
Basic menu system in C, takes in an integer and returns the appropriate result:
The menu displays fine, it takes the input fine but it doesn't seem to trigger the switch ie. if I hit option 1, it doesn't display the message.
int main(void) {
#define LSIZE 5
int selection[LSIZE];
do {
printf("\n Welcome to Menu");
printf("1) option 1\n");
printf("2) option 2\n");
printf("3) QUIT \n");
while (fgets(selection, LSIZE, stdin) != NULL) {
puts(selection);
}
if(scanf("%i", &selection) != 1) {
printf("\nInvalid input\n");
return EXIT;
} else {
switch(*selection) {
case '1':
printf("Selected option 1\n");
break;
case '2':
printf("Selected option 2\n");
break;
default:
printf("invalid option, try again \n");
}
}
} while (*selection != '3');
exit();
}
int selection[LSIZE];
...
while (fgets(selection, LSIZE, stdin) != NULL) {
puts(selection);
}
...
if(scanf("%i", &selection) != 1) {
This is very confused. You've declared selection as an array of int, but you're reading a string into it as though it were an array of char, and then you're trying to read a single decimal integer into it, but you're passing the address of the array, not a single int element.
Let's simplify it a bit and only worry about reading the menu option. We'll read it as an int, so we'd change our code as follows:
int selection;
do
{
// print menu options
if ( scanf( "%d", &selection ) != 1 )
// handle bad input
else
{
switch( selection )
{
case 1 : // not '1'
// handle option 1
break;
case 2:
// handle option 2
break;
default:
break;
}
} while ( selection != 3 );
etc. This should get you past your initial hurdles.
This is what I ended up doing:
int main(void) {
int selection;
do {
printf("\n Welcome to Menu");
printf("1) option 1\n");
printf("2) option 2\n");
printf("3) QUIT \n");
if(scanf("%d", &selection) != 1) {
printf("\nInvalid input\n");
return EXIT;
} else {
switch(selection) {
case 1:
printf("Selected option 1\n");
break;
case 2:
printf("Selected option 2\n");
break;
default:
printf("invalid option, try again \n");
}
}
} while (*selection != '3');
exit();
}
I want to make a game where any action can be bound to any input, be it from a keyboard, mouse, controller. Think of scrollwheel bound to jump.
To do this I must be able to present the current bindings in a human readable fashion to the user in a UI, such as "Jump: spacebar" and "shoot: left mouse button".
Currently, in my input routine, I am converting a SDL_KeyboardEvent to a human readable string with SDL_GetKeyName(event.key.keysym.sym).
I'm looking for a way to convert the following events into human readable text:
SDL_JoyAxisEvent
SDL_JoyBallEvent
SDL_JoyButtonEvent
SDL_JoyDeviceEvent
SDL_JoyHatEvent
SDL_MouseButtonEvent
SDL_MouseMotionEvent
SDL_MouseWheelEvent
I would expect the function to output something like "scrollup" or "X button" or "move up" or "left mouse button" or "select button". Currently I am manually implementing this, but it just seems so cumbersome. I've already looked at the docs but I couldn't find anything.
Sidenote: the documentation does not reveal whether a string from SDL_GetKeyName needs to be freed or not. I'm currently not freeing it.
My code currently:
SDL_WaitEvent(&event);
switch (event.type)
{
case SDL_QUIT:
quit = 1;
break;
case SDL_KEYDOWN:{
const char* a = SDL_GetKeyName(event.key.keysym.sym);
printf("Pressed down: %s\n", a);
break;
}
case SDL_KEYUP:{
const char* a = SDL_GetKeyName(event.key.keysym.sym);
printf("Released: %s\n", a);
break;
}
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN:
{
switch (event.button.button)
{
case SDL_BUTTON_LEFT:{
printf("LMB");
break;
}
case SDL_BUTTON_RIGHT:{
printf("RMB");
break;
}
case SDL_BUTTON_MIDDLE:{
printf("MMB");
break;
}
case SDL_BUTTON_X1:{
printf("X1");
break;
}
case SDL_BUTTON_X2:{
printf("X2");
break;
}
}
if (event.type == SDL_MOUSEBUTTONDOWN){
printf(" was clicked!\n");
} else {
printf(" was released!\n");
}
break;
}
case SDL_MOUSEMOTION:{
printf("Mouse moved to (%d, %d)\n", event.motion.x, event.motion.y);
break;
}
case SDL_MOUSEWHEEL:{
printf("Scrolled ");
if(event.wheel.y > 0){
printf("up\n");
}else if(event.wheel.y < 0){
printf("down\n");
}
if(event.wheel.x > 0){
printf("right\n");
}else if(event.wheel.x < 0){
printf("left\n");
}
break;
}
default:{
printf("Unsupported input method\n");
}
}
While making a asteroid shooter, I came around using _kbhit() and kbhit(). I'm no expert, but here is the problem I think I'm having:
int run = 1;
int main() {
while(run){
if(GetUserInput() == 2)
printf("W");
if(GetUserInput() == 1)
printf("S");
Sleep(50);
}
}
int GetUserInput(){
if(kbhit()){
char c = _getch();
if(c == 's')
return 2;
if(c == 'w')
return 1;
}
else
return 0;*
}
So, what I think is happening, it does the first check on GetUserInput(), and because of the nature of getch(), the keyboard is read from the buffer and discarded? Anyways, I store the value in c and should return appropriately. But it only does the first check. Is it because there is no more input on the buffer after the first check (in the main() function)?
Your problem is that you're trying to read once for every key you're interested in with this code:
if(GetUserInput() == 2)
printf("W");
if(GetUserInput() == 1)
printf("S");
For example, I press 'S', you read the key, check if the return value is 2 and it is not. Then you try to read another key, but I haven't pressed one, so the second check for 'S' also fails.
To fix this you need to perform all of your tests on the value you get from GetUserInput().
int val = GetUserInput();
if(val == 2)
printf("W");
else if(val == 1)
printf("S");
You don't need to use else if, but once you've found a match it makes no sense to keep checking if all of your checks are mutually exclusive. You might consider using a switch statement and an enum instead of hardcoded magic values, or even return the key value directly if one is pressed and a sentinel value like 0 that won't match any of the keys you're interested in.
Here is a complete example that works for me:
#include <conio.h>
#include <stdio.h>
int GetUserInput()
{
if (_kbhit())
{
char c = _getch();
switch (c)
{
case 's':
case 'S':
return 2;
case 'w':
case 'W':
return 1;
case 'x':
case 'X':
return -1;
}
}
return 0;
}
int main()
{
for (;;)
{
int c = GetUserInput();
switch (c)
{
case 1:
printf("W");
break;
case 2:
printf("S");
break;
case -1:
return 0;
}
}
return 0;
}
I have the following code, where I expect the user to give eiher 's' or 'f' (case insensitive) as input:
/* ... snip ... */
char acc_type;
printf("\n\nENTER HERE\t : ");
scanf("%c",&acc_type);
switch (acc_type)
{
case 's':
case 'S':
printf("\n SAVING ACCOUNT");
break;
case 'f':
case 'F':
printf("\n FIXED ACCOUNT");
break;
default:
printf("\n INVALID INPUT!!! TRY AGAIN");
}
/* ... snip ... */
However, the default action doesn't allow me to repeat the whole switch statement. How can I ask for input in his scenario again if the input wasn't valid?
You need a loop, essentially (in pseudo-code):
good_input = 0;
while(good_input == 0) {
... prompt for input ...
if (input == good) {
good_input = 1;
}
}
Until something valid is entered, good_input stays 0 and the while() loop continues to prompt for input. Once something good is entered, that flag changes and the code continues on to the next section.
Put the part you want to repeat in a loop, like this:
bool inputOK = false;
do {
printf("\n\nType S to SAVING ACCOUNT");
printf("\nType F to FIX ACCOUNT");
printf("\n\nENTER HERE\t : ");
scanf("%c",&acc_type);
switch (acc_type)
{
case 's':
case 'S':
printf("\n SAVING ACCOUNT");
inputOK = true;
break;
case 'f':
case 'F':
printf("\n FIXED ACCOUNT");
inputOK = true;
break;
default:
printf("\n INVALID INPUT!!! TRY AGAIN");
break; // Note: it's wise to use break in EVERY case
}
} while (inputOK == false);
I am working on a game and I ran my code and got the error "case label does not reduce to an integer constant." I think I know what this means, but how do I fix it? Here is my code:
#include<stdio.h>
#include<stdlib.h
int player_cash[3] = {50};
char job[][20] {
'A',
'B',
'C',
"Donate",
"Go to work",
"Exit"
};
int jobs;
int main()
{
while(player_cash[0] > 0) {
printf("Please type A, B, C, Donate, Go to work, or Exit\n");
switch(jobs) {
case 'A':
player_cash[0]-=5;
player_cash[1]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'B':
player_cash[0]-=5;
player_cash[2]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'C':
player_cash[0]-=5;
player_cash[3]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case "Donate":
player_cash[0]-=15; //Error here
player_cash[1]+=5;
player_cash[2]+=5;
player_cash[3]+=5;
printf("Cash donated\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case "Go to work":
player_cash[0]+=10; //Error here
printf("Work done\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case "Exit":
printf("Thanks for playing!\n\n"); //Error here
break;
default:
printf("Does not compute");
continue;
}
}
getchar();
return 0;
}
So, what I want the user to do is type in one of the options, and do the action that corresponds with it. How do I fix this?
You can't use strings as case expressions:
case "Donate":
Only integral expressions can be used, so e.g. case 'A': is OK.
Conceptually you have problems: jobs is an int, and you're testing for strings. If you want to allow the user to enter strings (more than a single character), you'll need to keep a string variable, and use something like fgets to get a full line of input.
Some of your case labels are characters (type char, indicated with 's). Those are integer constants.
Other labels are string literals (indicated with ") which have an effective type of const char *.1 Those are not integer constants and can not be used in this way.
1 For historical reasons they can often be used as if they were char *, but don't try to change them. Or else.
You cant compare string with c. "hello" == "hello" wont work as intend. switch only do simple c comparison on basic types.
switch(jobs) {
case 'A':
player_cash[0]-=5;
player_cash[1]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'B':
player_cash[0]-=5;
player_cash[2]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'C':
player_cash[0]-=5;
player_cash[3]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'D':
player_cash[0]-=15; //Error here
player_cash[1]+=5;
player_cash[2]+=5;
player_cash[3]+=5;
printf("Cash donated\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'G':
player_cash[0]+=10; //Error here
printf("Work done\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case 'E':
printf("Thanks for playing!\n\n"); //Error here
break;
default:
printf("Does not compute");
continue;
}
as you only read a character in getch(), you can compare this value. (but ask the user to input only one letter because he input "Donate", getch() will first read D, return, then read o, etc..)
Your job array had inconsistent initializers (mixed char and const char *)
You can't use string literals as case labels, as the char pointers are not compile time constants. Use integers:
enum jobType
{
jobA,
jobB,
jobC,
jobDonate,
jobGoToWork,
jobExit,
/* marker */
jobInvalid
};
enum jobType typeOfJob(const char* const name)
{
int i;
for (i=jobA; i!=jobInvalid; ++i)
if (0 == strcmp(jobNames[i], name))
return i;
return i;
}
Also, the player_cash was 1 element short (and was written out of bounds at index [3])
Code sample also shows how to avoid general gets badness, do some basic line-end trimming and do case insenstive comparison (stricmp on windows, IIRC): http://liveworkspace.org/code/227015a4e51126d55ca4eb1eea739b02
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int player_cash[4] = {50};
enum jobType
{
jobA,
jobB,
jobC,
jobDonate,
jobGoToWork,
jobExit,
/* marker */
jobInvalid
};
const char jobNames[][20] =
{
"A",
"B",
"C",
"Donate",
"Go to work",
"Exit"
};
enum jobType typeOfJob(const char* const name)
{
int i;
for (i=jobA; i!=jobInvalid; ++i)
#ifdef CASE_SENSITIVE
if (0 == strcmp(jobNames[i], name))
#else
if (0 == strcasecmp(jobNames[i], name))
#endif
return i;
return i;
}
const char* safer_gets()
{
static char input[1024];
char *p;
const char* t;
const char trimAt[] = "\r\n\t ";
fgets(input, sizeof(input), stdin);
for (t=trimAt; *t; ++t)
while(p = strrchr(input, *t))
*p = 0;
return input;
}
int main()
{
const char* input;
while(player_cash[0] > 0)
{
printf("Please type A, B, C, Donate, Go to work, or Exit\n");
input = safer_gets();
switch(typeOfJob(input))
{
case jobA:
player_cash[0]-=5;
player_cash[1]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobB:
player_cash[0]-=5;
player_cash[2]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobC:
player_cash[0]-=5;
player_cash[3]+=5;
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobDonate:
player_cash[0]-=15;
player_cash[1]+=5;
player_cash[2]+=5;
player_cash[3]+=5;
printf("Cash donated\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobGoToWork:
player_cash[0]+=10;
printf("Work done\n\n");
printf("Cash=%i\n\n", player_cash[0]);
continue;
case jobExit:
printf("Thanks for playing!\n\n");
break;
default:
printf("Does not compute");
continue;
}
}
getchar();
return 0;
}