character comparison using switch - c

I'm comparing strings character by character.
Here's a part of my code that's causing problems:
switch(line[1]) {
case 'u':
switch(line[2]) {
case 't':
switch(line[3]) {
case 't':
switch(line[4]) {
case 'o':
switch(line[5]) {
case 'n':
switch(line[6]) {
case 's':
printf("buttons\n");
case ' ':
printf("not buttons\n");
break;
}
break;
}
break;
}
break;
}
break;
}
}
For line[6], if an s character exists it should print out "buttons", if there's a space, it should print out "not buttons"
If I have a config file that contains:
buttons 13
button 3
buttons 3
I get:
buttons
not buttons
buttons
not buttons
If I have:
buttons 3
I get:
buttons
not buttons
I get a "buttons" and "not buttons" for every buttons entry and get nothing for the "button 3" entry
thanks

You will always get not buttons when there is buttons because you are not breaking after case 's'.Therefore it won't stop when an line[6] is s.
And you used all these nested switches just to compare a string.Better use strcmp to check if its buttons or button.

Instead of complicating nested switch, use this
FILE * fi; // input file handle
char line[9], c;
while (feof(fi) == 0) {
// Read only required chars
fgets(line, 8, fi);
line[8] = '\0';
while ((c = getc(fi)) != '\n' && c != EOF);
// Simplified comparison
if (strncmp(line, "button", 6) == 0) {
if (line[6] == 's') printf("buttons\n");
else if (line[6] == ' ') printf("not buttons\n");
}
}

Here's a simpler, cleaner version of the code:
if (strncmp(line, "button", 6)==0)
{
if (line[6]=='s')
printf("buttons");
else printf("button");
}

Related

SDL_GetKeyName but for mouse and joystick input

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");
}
}

Is there a way I can shorten this if statment?

I have this really large if statement and it does not look pleasing to the eye as well as not being as efficient as possible.
I'm making a program that (depending on the users input) runs a certain block of code, for example if the user inputs 'a' the program runs a code that adds something to a file etc. By the way this is in a do-while statement(I don't know if this is relevant though).
else if(ansr != 'a' && ansr != 'A' && ansr != 'r' && ansr != 'R' && ansr != 's' && ansr != 'S' && ansr != 'e' && ansr != 'E')
{
printf("Invalid input!\n");
}
As you can see this is a really long if statement and I would like it to be shorter. Thank you
Um, what an example, whatever.
Why don't you use strchr? strchr returns the pointer to a character in a string (if found), NULL otherwise.
else if (strchr("aArRsSeE", ansr) == NULL)
{
printf("Invalid input!\n");
}
I would go with:
switch(tolower(ansr)) {
case 'a':
case 'r':
case 's':
case 'e':
do_stuff();
break;
/* other cases here */
}
Or you can use more library functions such as:
if (strchr("ares", tolower(ansr)) {
do_stuff();
}
strchr function is searching for a given character in the given string and returns NULL if it is not there (or pointer to first occurrence of it, but it is not the use-case which we are interested in here)
This is assuming ansr is in the range of unsigned char or EOF. Otherwise the behavior of tolower is undefined.
To answer your question, I would personally use a switch statement. It is easy to use and easy to read. Another thing which would make your code slightly more readable is using toupper.
Here is an example:
#include <stdio.h>
#include <ctype.h>
int main ()
{
char inp = 'i';
char ansr = toupper(inp);
switch(ansr) {
case 'A' :
// Do something
break;
case 'R' :
// Do something
break;
case 'S' :
// Do something
break;
case 'E' :
// Do something
break;
default :
printf("Invalid input!\n");
}
return 0;
}
It looks like you're trying to write an else if case to catch input characters that you do not support. The else case is perfect for that kind of situation:
...
char input;
//get your input
if (input == 'A' || input == 'a')
DoA();
else if (input == 'R' || input == 'r')
DoR();
else if (input == 'S' || input == 's')
DoS();
else if (input == 'E' || input == 'e')
DoE();
else
DoInvalidInput();
Or if you use tolower() you can put that in a switch statement:
char lowerChar = tolower((unsigned char)input);
switch (lowerChar)
{
case 'a': DoA(); break;
case 'r': DoR(); break;
case 's': DoS(); break;
case 'e': DoE(); break;
default: DoInvalidInput(); break;
}
Depending on if the case of the ansr is important, converting to lowercase before the if statement would half the amount of checks needed.

How do I restrict user from inputting non-numeric characters?

Hi please take a look on this code:
while (cont == 1) {
...
scanf_s("%d", &input);
if (0 < input <= 5){
switch (input) {
case 1:
printf("1");
break;
case 2:
printf("2");
break;
case 3:
printf("3");
break;
case 4:
printf("4");
break;
case 5:
cont = 0;
break;
default:
printf("Wrong input !");
break;
}
}else{
printf("Error, Not a number !");
}
}
If I input something that is not a number, it results in an infinite loop. How do I restrict char inputs?
You can use this:
if(scanf_s("%d", &input) != 1) {
printf("Wrong input !");
break;
}
You should ALWAYS check the return value of scanf_s anyway.
After the scanf_s() fails, you need to read at least one character (the character that it failed on); usually, it makes most sense to discard the rest of the line that the user entered:
while (cont == 1) {
int rc;
...
if ((rc = scanf_s("%d", &input)) < 0)
{
printf("EOF detected\n");
break;
}
if (rc == 0)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
printf("Error, Not a number!\n");
continue;
}
if (0 < input <= 5){
switch (input) {
case 1:
case 2:
case 3:
case 4:
printf("%d", input);
break;
case 5:
cont = 0;
break;
default:
printf("Wrong input (1-5 required)!\n");
break;
}
}
}
If EOF is detected in the 'gobble' loop, you could detect EOF there and repeat the print and break the loop immediately. OTOH, the next scanf_s() should also report EOF, so it isn't 100% necessary. It depends a little on where the prompting occurs; if you get EOF, you probably shouldn't prompt again, so maybe the test after the inner while loop should be:
if (c == EOF)
{
printf("EOF detected\n");
break;
}
else
{
printf("Error, not a number\n");
continue;
}
You can play with variants of the 'gobble' loop that read up to a newline or a digit, and use ungetch(c, stdin); to return the digit to the input stream for the next call to scanf_s() to process — you probably wouldn't prompt for more input if you're going to process the already entered digit (that would confuse).
There are endless other games you can play. One option to consider is limiting the number of failed inputs before you give up — if the user hasn't entered a valid number in 10 tries, they probably aren't going to.
Note how the error processing tells the user what the valid range of numbers is; that helps them get it right. Also notice that the messages have a newline at the end; that's generally a good idea. In contexts outside interactive I/O, the newline can help ensure that the output appears when it is printed, not some arbitrary time later when some other print adds a newline, or the output buffer fills up and the pending data is flushed after all.

kbhit and multiple calls on function

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;
}

How to catch Tab keystroke in input? (ncurses)

I'm using ncurses and I'm getting input string with getstr(). I want to make something like autocompletion by Tab keystroke. However, I don't see a way to catch Tab with getstr(). I tried this:
char input = 0;
while (input != '\n')
switch (input = getch())
{
case '\t':
printw("Got Tab\n");
break;
default:
addch(input);
break;
}
But in this case I have to write my own handlings for Backspace, Delete etc., what is undesirable and essentialy is reinventing of wheel.
Maybe try:
switch (input = getch())
{
case KEY_STAB:
printw("Got Tab\n");
break;
default:
addch(input);
break;
}
Complete list of keys
This one works fine for me:
#include <cstdio>
#include <conio.h>
int main() {
char input = 0;
while (input != '\n') {
input = getch();
switch (input)
{
case '\t':
printf("T");
break;
case '\b':
printf("\b \b");
break;
default:
printf("%c", input);
break;
}
}
}
using the latest g++

Resources