Switch statement is skipped after two iterations of while loop - c

I am writing a state machine for an Arduino project to parse an input string from Serial1 input. I have a switch statement in a while loop that advances the state:
char * tok = strtok(instr, " \r\n"); //instr is the input string
int state = 0;
int targx = 0, targy = 0;
while (tok)
{
// State machine:
// 0: start parsing
// 1: N2 command, parse prediction
// 2: Correct prediction, parse targx
// 3: Parse targy
// 4: Target parsing complete
// 1000: Wrong prediction / unknown command
switch (state)
{
case 0:
if (strcmp(tok, "N2") == 0) state = 1;
else if (strcmp(tok, "PANGAIN") == 0) state = 5;
else if (strcmp(tok, "TILTGAIN") == 0) state = 7;
else state = 1000;
break;
case 1:
//Look for a person
int i = strlen(tok) - 1;
while(i >= 0 && tok[i] != ':') {i--;}
if (i >= 0) tok[i] = '\0';
Serial.print("Here's what it saw: ");
Serial.print(tok);
Serial.print("\n");
if (strcmp(tok, "person") == 0)
{
state = 2;
Serial.println(state);
}
else state = 1000;
break;
case 2:
Serial.println("Inside case 2");
targx = atoi(tok);
Serial.print("Targx = ");
Serial.print(targx, DEC);
Serial.println("");
state = 3;
break;
case 3:
targy = atoi(tok);
Serial.print("Targy = ");
Serial.print(targy, DEC);
Serial.println("");
state = 4;
break;
default:
break;
}
// Move to the next token:
tok = strtok(0, " \r\n");
Serial.println(tok);
}
The problem I'm having so far is it will get to case 1 and correctly identify that "person" is in the token and set the state to 2 but on every iteration of the while loop after that, it just skips the switch statement entirely. Here's what the output looks like for one input string:
Input String: N2 person:66 -1297 -538 2431 1331
> person:66
> Here's what it saw: person
> 2
> -1297
> -538
> 2431
> 1331
Can anyone tell me why the switch statement is being bypassed entirely after case 1 is hit? Any and all help is appreciated!

Your if else statement in case 1 is not correct.
The first if should be like this
if (i >= 0) {tok[i] = '\0';}
You are missing the brackets.
And the else statement should also be included in brackets like this.
if (strcmp(tok, "person") == 0)
{
state = 2;
Serial.println(state);
}
else
{
state = 1000;
}
Or if it is just one line of code like yours, you could write it in a separate line.
if (strcmp(tok, "person") == 0)
{
state = 2;
Serial.println(state);
}
else
state = 1000;
Otherwise it will assign value 1000 to state, that's why the for loop would skip all the switch cases.
My English is not very good. Hope you understand it.

Related

Using arrays to compare char

I'm coding this pattern game, but I am having difficulties in storing the previous input of the users "uno" and "dos" to a array so it can be compared, if same it will ask for another input which has not been picked. Example of This
Round 1:
Player 1 Inputs : -> A
Player 2 Inputs : -> B
Valid
Round 2:
Player 1 Inputs : -> L
Player 2 Inputs : -> V
Valid
Round 3:
Player 1 Inputs : -> A (Invalid Already been used)
enter char again
That above is an example i am trying to achieve. I will post the code below. I would appreciate the help very much.
#include <stdio.h>
#include <string.h>
#define SWITCH(_g0,_g1) \
(_g0 << 8) | (_g1 << 0)
#define CASE(_g0,_g1) \
case SWITCH(_g0,_g1)
intgetval(const char *prompt)
{
char *cp;
char buf[100];
int val;
while (1) {
printf("%s: ",prompt);
fflush(stdout);
cp = fgets(buf,sizeof(buf),stdin);
// handle end of file
if (cp == NULL) {
val = -1;
break;
// get the first char on the line
val = buf[0];
if (val != '\n')
break;
}
return val;
}
int main ()
{
int i = 0;
int roundCount = 1;
int pos = 0;
int over = 0;
int f = 1;
char G[9];
char uno,dos;
printf("Game Start!\n");
do {
printf("Round %d!\n", roundCount++);
printf("Input selection upon prompt.\n");
printf("Player 1: ");
scanf(" %c", &uno );
printf("Player 2: ");
scanf(" %c", &dos);
if()
//printf("DEBUG: %2.2X %2.2X\n",G[0],G[1]);
switch (SWITCH(uno,dos)) {
CASE('L','V'):
CASE('V','S'):
CASE('S','P'):
CASE('P','R'):
CASE('R','L'):
CASE('R','S'):
CASE('P','V'):
CASE('S','L'):
CASE('V','R'):
CASE('L','P'):
f++;
pos--;
printf("Uno Wins! Pos[%d]\n\n", pos);
break;
CASE('R','P'):
CASE('L','R'):
CASE('R','V'):
CASE('P','S'):
CASE('P','L'):
CASE('S','R'):
CASE('S','V'):
CASE('L','S'):
CASE('V','P'):
CASE('V','L'):
f++;
pos++;
printf("Dos Wins Pos[%d]!\n\n", pos);
break;
CASE('R','R'):
CASE('P','P'):
CASE('S','S'):
CASE('L','L'):
CASE('V','V'):
f++;
pos = pos;
break;
}
if (pos == -3 || pos == 3) {
printf("Game over\n");
break;
}
if (f == 5 && pos != -3 && pos != 3) {
switch (SWITCH(uno,dos)) {
CASE('L','V'):
CASE('V','S'):
CASE('S','P'):
CASE('P','R'):
CASE('R','L'):
CASE('R','S'):
CASE('P','V'):
CASE('S','L'):
CASE('V','R'):
CASE('L','P'):
printf("Uno:Wins!\n");
break;
CASE('R','P'):
CASE('L','R'):
CASE('R','V'):
CASE('P','S'):
CASE('P','L'):
CASE('S','R'):
CASE('S','V'):
CASE('L','S'):
CASE('V','P'):
CASE('V','L'):
printf("Dos Win!\n");
break;
}
}
} while (f < 5);
return 0;
}
im trying to implement a for loop for this but it wouldn't work , i am not getting the result that i want, adding this code. I would appreciate it if you would rewrite the code with this loop or if there is any other way please tell me how.
for ( i = 0; i < sizeof(useduno); i++)
{
if (uno == useduno[i]) // where useduno is the array, where uno is to be stored, so it cannot be used again
{
printf("You already used the letter. Use another letter: ");
scanf(" %c", &uno);
}
}

How to change if else statement to switch?

I don't understand/know how to change my if else statements to become switch statement with cases. Please help! I just need to change my if else statements to a switch and my assignment will be complete! Its fully running and functioning!
This C program provides a main function that supports a bash-like history
capability; The main objective for the circular buffer is to repeatedly
display a prompt to the user, and each prompt assigns an input number starting
at 1. Each line inputted into the circular buffer is stored until it gets overwritten,
the buffer only allows up to 5 lines of stored input, FIFO(First in, first out).
Giving the user 4 command options:
!x: With x meaning the line number selected, and the exclamation point("!") meaning
repeat the (absolute) input line numbered x. This only works if this line is one of
the saved commands. This command will display the original input line as well as
storing a copy. If the argument x is invalid, an error message will be displayed.
exit(case sensitive): Terminates the program.
history(case sensitive): Prints the saved commands
parse(case sensitive): Tokenize input line number x, This input line shouldn't be
stored in the buffer, but instead display each word on a seperate line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CIRCULAR_HISTORY_BUFFER 5
#define CHARACTER_LENGTH 128
void CircularHistoryBuffer()
{
char memory[CIRCULAR_HISTORY_BUFFER][CHARACTER_LENGTH];
char command_line[CHARACTER_LENGTH];
int data, n, i;
int number = 0;
while(1)
{
printf("%d>", number + 1);
fgets(command_line, CHARACTER_LENGTH - 1, stdin);
for(i = 0; i < CHARACTER_LENGTH; i++)
{
if(command_line[i] == '\n')
{
command_line[i] = '\0';
break;
}
}
if(command_line[0] == '!')
{
n = atoi(command_line + 1);
if(n < number - CIRCULAR_HISTORY_BUFFER + 1 || n > number || n <= 0)
{
printf( "%d: Not found\n", n);
}
else
{
data = (n - 1) % CIRCULAR_HISTORY_BUFFER;
printf("%s\n", memory[data]);
strcpy(memory[number % CIRCULAR_HISTORY_BUFFER], memory[data]);
number++;
}
}
else if(strcmp(command_line, "exit") == 0)
{
exit(0);
}
else if(strcmp(command_line, "history") == 0)
{
if(number <= CIRCULAR_HISTORY_BUFFER)
{
for(i = 0; i < number; i++)
{
printf("%d\t%s\n", i + 1, memory[i]);
}
}
else
{
n = number - CIRCULAR_HISTORY_BUFFER + 1;
data = number % CIRCULAR_HISTORY_BUFFER;
for(i = data; i < CIRCULAR_HISTORY_BUFFER; i++)
{
printf("%d\t%s\n", n++, memory[i]);
}
for(i = 0; i < data; i++)
{
printf("%d\t%s\n", n++, memory[i]);
}
}
}
else if(strncmp(command_line, "parse", 5) == 0)
{
n = atoi(command_line + 5);
if(n < number - CIRCULAR_HISTORY_BUFFER + 1 || n > number || n <= 0)
{
printf("%d: event not found\n", n);
}
else
{
data = (n - 1) % CIRCULAR_HISTORY_BUFFER;
for(i = 0; i < strlen(memory[data]); i++)
{
if(memory[data][i] == ' ')
{
printf("\n");
}
else
{
printf("%c", memory[data][i]);
}
}
printf("\n");
}
}
else
{
strcpy(memory[number % CIRCULAR_HISTORY_BUFFER], command_line);
number++;
}
}
}
int main()
{
CircularHistoryBuffer();
return 0;
}
In this case it doesn't make much sense to use a switch statement, since you are looking at doing several string comparisons.
What you could do instead is a table look-up, based on a table sorted in alphabetic order:
const char* STR_TABLE[] = // must be sorted in alphabetic order
{
"exit",
"history",
"parse",
...
};
const size_t STR_TABLE_SIZE = sizeof(STR_TABLE) / sizeof(STR_TABLE[0]);
You can then search through the table for the correct string. The naive implementation being a for loop:
for(size_t i=0; i<STR_TABLE_SIZE; i++)
{
if(strcmp(STR_TABLE[i], user_input)==0)
{
// found, do something
break;
}
}
This is the best option when the number of strings in the table are limited. For larger tables, you would use binary search instead. Something like this:
int strcmp_wrapper (const void* obj1, const void* obj2)
{
return strcmp(obj1, *(const char**)obj2);
}
const char** result = bsearch(user_input,
STR_TABLE,
STR_TABLE_SIZE,
sizeof(const char*),
strcmp_wrapper);
if(result != NULL)
{
printf("User picked option %s at index %d.", *result, (int)(result - STR_TABLE));
}
switch-statement will works only with integer values.
There is switch-statement uses:
switch(a)
{
case '1': doSomething(); break; // if you forget break operator, than secondcasealso will invoke and so one
case '2': doSomethingElse(); break;
default: doSomethingElse2();
}
You can use switch-statement if you need work with integer values/constants from specific range.
currently your code is like :
if(command_line[0] == '!')
{
<recall>
}
else if(strcmp(command_line, "exit") == 0)
{
<exit>
}
else if(strcmp(command_line, "history") == 0)
{
<historic>
}
else if(strncmp(command_line, "parse", 5) == 0)
{
<parse>
}
else
{
<other>
}
to use a switch will give something like that :
switch (command_line[0]) {
case '!':
<recall>
break;
case 'e':
if(strcmp(command_line + 1, "xit") == 0)
{
<exit>
}
else
{
<other>
}
break
case 'h':
if(strcmp(command_line + 1, "istory") == 0)
{
<historic>
}
else
{
<other>
}
break
case 'p':
if(strncmp(command_line + 1, "arse", 4) == 0)
{
<parse>
break;
}
// no fallthrough
default:
{
<other>
}
}
This is less readable, facilitates the introduction of a bugs if it has to be modified, and has no benefic effect on the speed if this what you expected
For me don't do that ... but ask yourself about the strcmp but strncmp in one case

Switch vs if ... else if ... else

I have a question. I'm studying for my exam and I don't know how to do answer this. Basically I have to change the instructions if...else if... else, to a instruction switch in order that the output of the program stays the same.
void main()
{
int x;
x = 1;
for (int i = 1; i < 10; ++i) {
if (i <= 3)
do {
x += i;
if (x >= 4)
break;
} while (i % 2 == 0);
else if ((i > 3) && (i < 5))
x += 2;
else
continue;
}
while (x > 0) {
printf(" x=%d ", x);
x -= 1;
}
system("pause");
}
Am I allowed to do a switch inside of the for loop?
Of course you can. A for loop controls the execution of a statement and a switch block is a statement.
Given that i is in the inclusive range of 1 to 9, you can replace the if block with
switch (i){
case 1: case 2: case 3:
// that replaces 'if (i <= 3)'
// ToDo - the code here
break; // to obviate follow-through.
case 4:
// that replaces 'if ((i > 3) && (i < 5))'
// ToDo - the code here
break;
default:
// that replaces 'else'
continue; // note that this is for the for loop, not the switch
}
Note that the behaviour of if (x >= 4) break; is not changed by this refactoring.
I'm not convinced however that replacing the if block with a switch is the right thing to do here: the boundaries i <= 3 and i >= 5 are less naturally handled with a switch; perhaps changing the type of i to unsigned and handling case 0: explicitly would alleviate this somewhat.
Something like this should work
void main()
{
int x;
x = 1;
for (int i = 1; i < 10; ++i) {
switch (i) {
case 1:
case 2:
case 3:
do {
x += i;
if (x >= 4)
break;
} while (i % 2 == 0);
break;
case 4:
x += 2;
break;
default:
continue;
break;
}
}
while (x > 0) {
printf(" x=%d ", x);
x -= 1;
}
system("pause");
}
You can have the switch statement inside the loops.
IMO the switch is more readable than the long if else sequences. Performance is almost the same.
Some compilers (gcc for example) have switch extensions making the range checks in the switch statements shorter.
switch(age)
{
case 0 ... 12:
printf("Child\n");
break;
case 13 ... 19:
printf("Teenager\n");
break;
case 20 ... 200:
printf("Adult\n");
break;
default:
printf("Immortal\n");
break;
}
It is not portable of course.

End a loop if the user select a specific function

Hi I need little help with a problem!
I have a main class which contains a loop.
Inside this loop the user can call different functions that do different things but I want that if the user select a certain function it displays a message and the loop ends.
This is my code:
#include <stdio.h>
void rest_at_inn();
void train();
void battle_demon_lord();
void Quit_Game();
int main() {
//Declare variable and pointer
float days_remaining = 8;
int current_hp = 10;
int hp_remaining = 10;
int MAX = 10;
int experience = 0;
int selection;
//Loops a menu that asks the user to make a selectio and repet it until either days or HP are less or equal to zero
do {
printf("Days remaining: %f, HP: %d, EXP: %d\n\n", days_remaining, hp_remaining, experience);
printf("1 - Rest at Inn\n");
printf("2 - Train\n");
printf("3 - Fight the Demon Lord\n");
printf("4 - Quit Game\n\n");
printf("Select: \n");
scanf("%d", &selection);
printf("\n");
//Execute the selection
switch (selection) {
case 1:
rest_at_inn(&days_remaining, &hp_remaining, &MAX);
break;
case 2:
train(&days_remaining, &hp_remaining, &experience);
break;
case 3:
battle_demon_lord(&current_hp);
break;
case 4:
Quit_Game();
break;
}
} while (days_remaining > 0 && current_hp > 0);
return 0;
}
//This function reduces the days by 1 and resets the HP to 10
void rest_at_inn(float *days_remaining, int *hp_remaining, int *MAX) {
*hp_remaining = 10;
*days_remaining -= 1;
if (*days_remaining > 0)
printf("You rested up the at the inn\n\n");
else /*(*days_remaining<=0)*/
printf("Game Over");
}
//This function reduces the days by 0.5 and the HP by 2 and adds 10 to the experience
void train(float *days_remaining, int *hp_remaining, int *experience) {
*experience += 10;
*hp_remaining = *hp_remaining - 2;
*days_remaining = *days_remaining - 0.5;
printf("You did some training!\n\n");
}
//This function sets the HP to 0 and prints a string
void battle_demon_lord(int *current_hp) {
*current_hp = 0;
printf("He's too strong!\n\n");
printf("Game Over!");
}
// This function prints a string
void Quit_Game() {
printf("Good bye!\n\n");
}
I think it should be a parameter in the do_while but nothing has worked for me.
You need to add an exit condition for when the user selects 4.
You can do this:
} while (days_remaining>0 && current_hp>0 && selection != 4);
Or this:
case 4 :
Quit_Game();
return 0;
Or this:
void Quit_Game() {
printf ("Good bye!\n\n");
exit(0);
}
If the switch is the last statement of your loop, add a mustQuit flag variable before the do of your do / while loop, and set it to zero. When end-user chooses the quit option, set mustQuit to 1. Add the !mustQuit condition to your loop.
int mustQuit = 0;
do {
... // some statements here
switch (selection) {
...
case 4 :
mustQuit = 1;
Quit_Game();
break;
}
} while (!mustQuit && days_remaining > 0 && current_hp > 0);
If you have more statements after switch, an alternative with a conditional break in the middle may be more optimal:
do {
int mustQuit = 0;
... // some statements here
switch (selection) {
...
case 4 :
mustQuit = 1;
Quit_Game();
break; // this breaks the switch
}
if (mustQuit) {
break; // this breaks the loop
}
... // More statements here
} while (days_remaining > 0 && current_hp > 0);
I expect you want to escape the loop in case 4:
Try to use goto
case 4 :
Quit_Game();
goto out;
break;
}
} while (days_remaining>0 && current_hp>0);
out:
return 0;
(1) If you want to just get out of the do-while loop you can add a boolean variable so when it enter the last option it'll be false, like so:
bool quit = false;
(...)
case 4 :
quit = true;
printf("Good bye!\n\n");
break;
and add the value at the condition of the do-while:
while (days_remaining>0 && current_hp>0 && !quit);
So, it'll get out of the do-while loop and continue the code.
(2) If you want to finish the program, add a return 0 and forget about the boolean value, like this:
case 4 :
printf("Good bye!\n\n");
return 0;
REMEMBER: If you are doing it on a C based code, it wont support the reserved words like, true and false. You must use 0 for false and other number for true, preferably 1.

Are there any problems with my card game code?

//Usage: public Static void play()
//Desc: Play the game of OneCard. The game has 2 players. the user and the
// computer.
// The user is dealt 1 card, and so is the computer. The user has the
// option to change the card once. The winner is the player with the
// higher rank card (Ace>King>Queen>...>3>2). The suit is irrelevant.
//Input: The user enters a character (Y/N) signaling whether the user wants
// to change the card.
//Output: The user's card, followed by a message asking if the user wants
// to change the card, followed optionally the user's new card,
// followed by the computer's card, followed by the result of the game,
// followed by a message asking the user if the user wants to play
// again.
import java.util.Scanner;
class OneCard
{
public static void play()
{
Scanner f = new Scanner(System.in);
DeckOfCards d = new DeckOfCards();
String meatbag = d.deal();
String CPU = d.deal();
System.out.printf("Your card: %s " , meatbag);
System.out.print("Change card: (y/n)");
char ch = f.nextLine().charAt(0);
if (ch == 'y' || ch == 'y') meatbag = d.deal();
else ;
findRank(meatbag);
findRank(CPU);
whoWon(meatbag, CPU);
}
public static int findRank(String s)
{
int rank_num= 0;
switch(s)
{
case "Two": rank_num = 2;
break;
case "Three": rank_num = 3;
break;
case "Four": rank_num = 4;
break;
case "Five": rank_num = 5;
break;
case "Six": rank_num = 6;
break;
case "Seven": rank_num = 7;
break;
case "Eight": rank_num = 8;
break;
case "Nine": rank_num = 9;
break;
case "Ten": rank_num = 10;
break;
case "Jack": rank_num = 11;
break;
case "Queen": rank_num = 12;
break;
case "King": rank_num = 13;
break;
case "Ace": rank_num = 14;
break;
}
return rank_num;
}
public static void whoWon(String s1, String s2)
{
System.out.printf("Your card: %s " , s1);
System.out.printf("Dealer's card: %s ", s2);
if(findRank(s1)> findRank(s2)) System.out.println("You won.");
else if (findRank(s1) < findRank(s2)) System.out.println("Dealer won.");
else System.out.println("Draw.");
}
}
I am not sure if I actually made a logical mistake when writing the methods findRank and whoWon. You can assume that class DeckOfCards and method DeckOfCards.deal have been made previous to this code.
There seems to be no logic mistake,
just some stuff you could remove like:
else ;
findRank(meatbag);
findRank(CPU);
Also you might want to change the line
if (ch == 'y' || ch == 'y') meatbag = d.deal();
into
if (ch == 'y' || ch == 'Y') meatbag = d.deal();

Resources