EDIT_START: I want to thank all people for giving me such good answers! It's hard for me to choose any answer over another, because I see that all of your answers are valid and good in their own perspective. I want to clarify my own question. My question is not "How do I not use GOTO?", but my question is "How do I use GOTO in a better way?". This implicates that I want to use GOTO for program room/state transition at all costs. This is for educational purpose and for discovering the limits of C. I will give out a bounty as soon as possible to my question, to give back a reward. Anyway thank you all! I'll place a LABEL for ya all in my program ;-) EDIT_END:
I was discussing with someone about using GOTO at stackoverflow. May someone teach me some hidden tricks in using GOTO? Do you have some suggestions for improvement? You may enjoy my little adventure game, give it a try. ^^
PS play the game before you read the source, otherwise you get spoiled
#include <stdio.h>
#include <stdlib.h>
enum _directions{
DIR_0 = 0b0000,
DIR_E = 0b0001,
DIR_W = 0b0010,
DIR_WE = 0b0011,
DIR_S = 0b0100,
DIR_SE = 0b0101,
DIR_SW = 0b0110,
DIR_SWE = 0b0111,
DIR_N = 0b1000,
DIR_NE = 0b1001,
DIR_NW = 0b1010,
DIR_NWE = 0b1011,
DIR_NS = 0b1100,
DIR_NSE = 0b1101,
DIR_NSW = 0b1110,
DIR_NSWE = 0b1111
} DIRECTIONS;
void giveline(){
printf("--------------------------------------------------------------------------------\n");
}
void where(int room, unsigned char dir){
printf("\nYou are in room %i. Where do you want GOTO?\n", room);
if(dir & 8) printf("NORTH: W\n");
else printf(".\n");
if(dir & 4) printf("SOUTH: S\n");
else printf(".\n");
if(dir & 2) printf("WEST: A\n");
else printf(".\n");
if(dir & 1) printf("EAST: D\n");
else printf(".\n");
}
char getdir(){
char c = getchar();
switch(c){
case 'w' :
case 'W' :
return 'N';
case 's' :
case 'S' :
return 'S';
case 'a' :
case 'A' :
return 'W';
case 'd' :
case 'D' :
return 'E';
case '\e' :
return 0;
}
return -1;
}
int main(int argc, char *argv[]){
START:
printf("THE EVIL GOTO DUNGEON\n");
printf("---------------------\n");
printf("\nPress a direction key \"W, A, S, D\" followed with 'ENTER' for moving.\n\n");
char dir = -1;
ROOM1:
giveline();
printf("Somehow you've managed to wake up at this place. You see a LABEL on the wall.\n");
printf("\"Do you know what's more evil than an EVIL GOTO DUNGEON?\"\n");
printf("You're wondering what this cryptic message means.\n");
where(1, DIR_SE);
do{
dir = getdir();
if(dir == 'S') goto ROOM4;
if(dir == 'E') goto ROOM2;
}while(dir);
goto END;
ROOM2:
giveline();
printf("Besides another LABEL, this room is empty.\n");
printf("\"Let's play a game!\"\n");
where(2, DIR_W);
do{
dir = getdir();
if(dir == 'W') goto ROOM1;
}while(dir);
goto END;
ROOM3:
giveline();
printf("Man, dead ends are boring.\n");
printf("Why can't I escape this nightmare?\n");
where(3, DIR_S);
do{
dir = getdir();
if(dir == 'S') goto ROOM6;
}while(dir);
goto END;
ROOM4:
giveline();
printf("Is this a real place, or just fantasy?\n");
printf("\"All good things come in three GOTOs.\"\n");
where(4, DIR_NSE);
do{
dir = getdir();
if(dir == 'N') goto ROOM1;
if(dir == 'S') goto ROOM7;
if(dir == 'E') goto ROOM5;
}while(dir);
goto END;
ROOM5:
giveline();
printf("This is a big river crossing. I guess I need to JUMP.\n");
where(5, DIR_SWE);
do{
dir = getdir();
if(dir == 'S') goto ROOM8;
if(dir == 'W') goto ROOM4;
if(dir == 'E') goto ROOM6;
}while(dir);
goto END;
ROOM6:
giveline();
printf("This place doesn't look very promising.\n");
where(6, DIR_NSW);
do{
dir = getdir();
if(dir == 'N') goto ROOM3;
if(dir == 'S') goto ROOM9;
if(dir == 'W') goto ROOM5;
}while(dir);
goto END;
ROOM7:
giveline();
printf("\"Give a man a LOOP and you feed him FOR a WHILE;\n");
printf(" teach a man a GOTO and you feed him for a RUNTIME.\"\n");
where(7, DIR_NE);
do{
dir = getdir();
if(dir == 'N') goto ROOM4;
if(dir == 'E') goto ROOM8;
}while(dir);
goto END;
ROOM8:
giveline();
printf("This looks like an endless LOOP of rooms.\n");
where(8, DIR_NW);
do{
dir = getdir();
if(dir == 'N') goto ROOM5;
if(dir == 'W') goto ROOM7;
}while(dir);
goto END;
ROOM9:
giveline();
printf("You've found your old friend Domino. He doesn't looks scared, like you do.\n");
printf("\n\"Listen my friend,\n");
printf(" If you want to escape this place, you need to find the ESCAPE KEY.\"\n");
printf("\nWhat does this mean?\n");
where(9, DIR_N);
do{
dir = getdir();
if(dir == 'N') goto ROOM6;
}while(dir);
goto END;
printf("You never saw me.\n");
END:
giveline();
printf("The End\n");
return 0;
}
goto
use, I think it's missed the mark. \$\endgroup\$goto
-ing to code in another function isn't unpredictable, it's explicitly illegal. Labels have function scope, so they aren't visible outside the function where they're defined (just like local variables). If you want to jump between functions you'll have to usesetjmp()
/longjmp()
, but those are very good ways to screw up your stack and crash your program in new and interesting ways. \$\endgroup\$goto
in C, but it is not a good general-purpose mechanism for branching. Consider that in contrast, Java reservedgoto
as a language keyword, but never implemented it, and it isn't particularly missed there. What relevant features does Java have that C does not? Mostly it's labeledbreak
andcontinue
statements and exceptions. Good uses ofgoto
in C are pretty much all for situations that would most likely be addressed by one of those features instead in Java. \$\endgroup\$