c语言 - 返回主菜单保持循环菜单



当程序第一次启动时,我可以成功地从主菜单中选择任何选项。但是,当我从任何子菜单中选择返回主菜单选项时,它将返回主菜单,但无论之后我再次按哪个选项,它都会继续循环该菜单。只允许我选择返回主菜单选项。如何将选择重置为不会继续循环的位置?我已经尽可能地缩短了代码,以便它仍然可以编译,但也演示错误。提前谢谢你。

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main()
{
//declare all working variables: mOption, FManOption, COption...etc...
int MOption = 0;
int FManOption = 0;
int FOption = 0;
int COption = 0;
int userChoice = 0;
//declarations for all arrays of struct
//declare a pointer to an array of struct using malloc() for fisherman, fish, catch
//process:
printf("Please select 1 to start the program or 0 to quit: ");
scanf("%d", &userChoice);
while(userChoice != 1 && userChoice != 0)
{
printf("Invalid selection! Please type a 1 or a 0: ");
scanf("%d", &userChoice);
}//end (userChoice != 1 && userChoice != 0)
if(userChoice != 1)
printf("Thank you for wasting my time! Have a great day!");
else
{
MOption = mainMenu();

switch(MOption)
{
case 1: FManOption = FishermanMenu();
while(FManOption != 3)
{
switch(FManOption)
{
case 1: getFisherman();//get a fisherman
//count fisherman
break;
case 2: //prompt for a ssn, validate, search
//if found display everything about this fisherman
break;
case 3: FManOption = mainMenu();
//reset FManOption
break;
default: printf("nInvalid selection! Please select from one of the menu optionsn");
}//end switch(FManOption)
}//end while(FManOption != 3)
break;
}
}
}
int mainMenu()
{
int Option;
printf("n-------Welcome to the Fishing Tournament Main Menu!-------n");
printf("1 - Fisherman menun");
printf("2 - Fish menun");
printf("3 - Tournament(Catch) menun");
printf("4 - Close Tournament (determine winner)n");
printf("5 - Quit Programnn");
printf("Please select a menu option: ");
scanf("%d", &Option);
if(Option > 5 || Option < 1)
do /* check scanf() return value for input errors */
{
printf("nInvalid selection! Please select from one of the menu optionsn");
printf("1 - Fisherman menun");
printf("2 - Fish menun");
printf("3 - Tournament(Catch) menun");
printf("4 - Close Tournament (determine winner)n");
printf("5 - Quit Programnn");
printf("Please select a menu option: ");
scanf("%d", &Option);
}
while(Option > 5 || Option < 1);
return Option; /* finally return the final correct option */
}//end main menu
int FishermanMenu()
{
int ManOption;
printf("n-------Fisherman Menu-------n");
printf("1 - Register fishermann");
printf("2 - Search fishermann");
printf("3 - Go back to main menun");
printf("Please select a menu option: ");
scanf("%d", &ManOption);
if(ManOption > 5 || ManOption < 1)
do /* check scanf() return value for input errors */
{
printf("nInvalid selection! Please select from one of the menu optionsn");/* handle input error */
printf("1 - Register fishermann");
printf("2 - Search fishermann");
printf("3 - Go back to main menun");
printf("Please select a menu option: ");
scanf("%d", &ManOption);
}
while(ManOption > 5 || ManOption < 1);
return ManOption; /* finally return the final correct option */
}//end Fisherman Menu

问题是你永远陷入了这个while循环中:

while (FManOption != 3)

此循环仅在"Fisherman"子菜单内时才有意义,但您应该离开此循环并在用户选择"返回主菜单"后将程序返回到其先前状态。

与其尝试以程序的控制流暗示程序的状态(例如,用户当前是否在主菜单或子菜单中)的方式编写代码,通常更容易将程序状态显式存储在变量中,例如:

enum menu_state
{
MENUSTATE_MAIN,
MENUSTATE_FISHERMAN,
MENUSTATE_FISH,
MENUSTATE_TOURNAMENT_CATCH,
MENUSTATE_CLOSE_TOURNAMENT
};
int main( void )
{
[...]
if (userChoice != 1)
printf("Thank you for wasting my time! Have a great day!");
else
{
enum menu_state ms = MENUSTATE_MAIN;
for (;;) //infinite loop, equivalent to while(true)
{
switch ( ms )
{
case MENUSTATE_MAIN:
switch ( mainMenu() )
{
case 1:
printf( "opening fisherman menun" );
ms = MENUSTATE_FISHERMAN;
break;
case 2:
printf( "opening fish menun" );
ms = MENUSTATE_FISH;
break;
case 3:
printf( "opening tournament(catch) menun" );
ms = MENUSTATE_TOURNAMENT_CATCH;
break;
case 4:
printf( "opening close tournament menun" );
ms = MENUSTATE_CLOSE_TOURNAMENT;
break;
case 5:
//quit program
exit( EXIT_SUCCESS );
default:
fprintf( stderr, "unexpected errorn" );
exit( EXIT_FAILURE );
}
break;
case MENUSTATE_FISHERMAN:
switch ( FishermanMenu() )
{
case 1:
printf( "Register fisherman not yet implemented.n" );
break;
case 2:
printf( "Search fisherman not yet implemented.n" );
break;
case 3:
//change program state back to main menu
ms = MENUSTATE_MAIN;
break;
default:
fprintf( stderr, "unexpected errorn" );
exit( EXIT_FAILURE );
}
break;
case MENUSTATE_FISH:
printf( "Fish menu not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
case MENUSTATE_TOURNAMENT_CATCH:
printf( "Tournament(catch) menu not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
case MENUSTATE_CLOSE_TOURNAMENT:
printf( "Close tournament not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
default:
fprintf( stderr, "unexpected errorn" );
exit( EXIT_FAILURE );
}
}
}
}

还值得注意的是,您的函数mainMenuFishermanMenu包含不必要的代码重复。您可以通过以下方式简化函数mainMenu

int mainMenu( void )
{
for (;;) //repeat forever, until input is valid
{
int option;
printf("n-------Welcome to the Fishing Tournament Main Menu!-------n");
printf("1 - Fisherman menun");
printf("2 - Fish menun");
printf("3 - Tournament(Catch) menun");
printf("4 - Close Tournament (determine winner)n");
printf("5 - Quit Programnn");
printf("Please select a menu option: ");
scanf("%d", &option);
if ( 1 <= option && option <= 5 )
return option;
printf("nInvalid selection! Please select from one of the menu optionsn");
}
}

但是,在尝试使用scanf的结果之前,请务必始终检查函数是否scanf成功。这可以通过检查scanf的返回值来实现。此外,在使用scanf后,丢弃行其余部分的输入很重要。否则,例如,如果用户输入"12dfghoh",则所有后续对scanf的调用都将失败,因为它在尝试读取号码时无法从输入流中删除dfghoh

因此,这是我检查scanf的返回值并丢弃该行中所有剩余输入的代码:

int mainMenu( void )
{
for (;;) //repeat forever, until input is valid
{
int option, c;
printf("n-------Welcome to the Fishing Tournament Main Menu!-------n");
printf("1 - Fisherman menun");
printf("2 - Fish menun");
printf("3 - Tournament(Catch) menun");
printf("4 - Close Tournament (determine winner)n");
printf("5 - Quit Programnn");
printf("Please select a menu option: ");
if (
scanf("%d", &option) == 1 && //make sure scanf succeeded
1 <= option && option <= 5
)
{
return option;
}
printf("nInvalid selection! Please select from one of the menu optionsn");
//discard remainder of line, which may contain bad input
//and prevent the next call of scanf to succeed
do
{
c = getchar();
}
while ( c != EOF && c != 'n' );
}
}

另一方面,对于基于行的输入,最好使用fgets而不是scanf,因为这样您就不必处理从输入流中删除错误的输入。有关详细信息,请参阅此链接:

远离scanf()的初学者指南

使用fgets函数,函数mainMenu如下所示:

//NOTE: the following header must be added
#include <ctype.h>
int mainMenu( void )
{
for (;;) //repeat forever, until input is valid
{
char buffer[1024], *p;
long option;
printf("n-------Welcome to the Fishing Tournament Main Menu!-------n");
printf("1 - Fisherman menun");
printf("2 - Fish menun");
printf("3 - Tournament(Catch) menun");
printf("4 - Close Tournament (determine winner)n");
printf("5 - Quit Programnn");
printf("Please select a menu option: ");
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
printf( "unexpected input error!n" );
//since this type of error is probably not recoverable,
//don't try again, but instead exit program
exit( EXIT_FAILURE );
}
option = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "error converting string to numbern" );
continue;
}
//make sure remainder of line contains only whitespace,
//so that input such as "12dfghoh" gets rejected
for ( ; *p != ''; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "unexpected input encountered!n" );
continue;
}
}
//make sure input is in the desired range
if ( option < 1 || option > 5 )
{
printf( "input must be between 1 and 5n" );
continue;
}
return option;
}
}

但是,您不能简单地将代码中的函数mainMenu替换为我上面的代码,因为在代码中混合scanffgets不会很好地工作。这是因为scanf不会一次从输入流中读取一行,而只会提取读取数字所需的数量,并将行的其余部分(包括换行符)保留在缓冲区中。因此,如果在scanf之后立即使用fgetsfgets将读取scanf未提取的行的其余部分,这些剩余部分通常是除了换行符之外不包含任何其他内容的字符串。

因此,如果您决定使用fgets(我推荐),那么您应该在程序的任何地方使用它,而不是将其与scanf混合,例如:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int mainMenu(void);
int FishermanMenu(void);
int get_int_from_user( const char *prompt );
enum menu_state
{
MENUSTATE_MAIN,
MENUSTATE_FISHERMAN,
MENUSTATE_FISH,
MENUSTATE_TOURNAMENT_CATCH,
MENUSTATE_CLOSE_TOURNAMENT
};
int main( void )
{
int user_choice;
for (;;) //loop forever until input is valid
{
user_choice = get_int_from_user(
"Please select 1 to start the program or 0 to quit: "
);
if ( user_choice == 0 )
{
printf("Thank you for wasting my time! Have a great day!");
exit( EXIT_SUCCESS );
}
if ( user_choice == 1 )
{
//input is valid, so break infinite loop
break;
}
printf( "Invalid selection!n" );
}
enum menu_state ms = MENUSTATE_MAIN;
for (;;) //main program loop
{
switch ( ms )
{
case MENUSTATE_MAIN:
switch ( mainMenu() )
{
case 1:
printf( "opening fisherman menun" );
ms = MENUSTATE_FISHERMAN;
break;
case 2:
printf( "opening fish menun" );
ms = MENUSTATE_FISH;
break;
case 3:
printf( "opening tournament(catch) menun" );
ms = MENUSTATE_TOURNAMENT_CATCH;
break;
case 4:
printf( "opening close tournament menun" );
ms = MENUSTATE_CLOSE_TOURNAMENT;
break;
case 5:
//quit program
exit( EXIT_SUCCESS );
default:
fprintf( stderr, "unexpected errorn" );
exit( EXIT_FAILURE );
}
break;
case MENUSTATE_FISHERMAN:
switch ( FishermanMenu() )
{
case 1:
printf( "Register fisherman not yet implemented.n" );
break;
case 2:
printf( "Search fisherman not yet implemented.n" );
break;
case 3:
//change program state back to main menu
ms = MENUSTATE_MAIN;
break;
default:
fprintf( stderr, "unexpected errorn" );
exit( EXIT_FAILURE );
}
break;
case MENUSTATE_FISH:
printf( "Fish menu not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
case MENUSTATE_TOURNAMENT_CATCH:
printf( "Tournament(catch) menu not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
case MENUSTATE_CLOSE_TOURNAMENT:
printf( "Close tournament not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
default:
fprintf( stderr, "unexpected errorn" );
exit( EXIT_FAILURE );
}
}
}
int mainMenu( void )
{
for (;;) //repeat forever, until input is in desired range
{
int option;
option = get_int_from_user(
"n-------Welcome to the Fishing Tournament Main Menu!-------n"
"1 - Fisherman menun"
"2 - Fish menun"
"3 - Tournament(Catch) menun"
"4 - Close Tournament (determine winner)n"
"5 - Quit Programnn"
"Please select a menu option: "
);
//make sure input is in the desired range
if ( option < 1 || option > 5 )
{
printf( "input must be between 1 and 5n" );
continue;
}
return option;
}
}
int FishermanMenu()
{
for (;;) //repeat forever, until input is in desired range
{
int option;
option = get_int_from_user(
"n-------Fisherman Menu-------n"
"1 - Register fishermann"
"2 - Search fishermann"
"3 - Go back to main menun"
"Please select a menu option: "
);
//make sure input is in the desired range
if ( option < 1 || option > 3 )
{
printf( "input must be between 1 and 3n" );
continue;
}
return option;
}
}
int get_int_from_user( const char *prompt )
{
for (;;) //loop forever until user enters a valid number
{
char buffer[1024], *p;
long l;
puts( prompt );
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "unrecoverable error reading from inputn" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, 'n' ) == NULL )
{
int c;
printf("line input was too long!n");
//discard remainder of line
do
{
c = getchar();
if ( c == EOF)
{
fprintf( stderr, "unrecoverable error reading from inputn" );
exit( EXIT_FAILURE );
}
} while ( c != 'n' );
continue;
}
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "error converting string to numbern" );
continue;
}
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "number out of range errorn" );
continue;
}
//make sure remainder of line contains only whitespace,
//so that input such as "12dfghoh" gets rejected
for ( ; *p != ''; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "unexpected input encountered!n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto next_outer_loop_iteration;
}
}
return l;
next_outer_loop_iteration:
continue;
}
}

在上面的代码中,我创建了一个新的函数get_int_from_user,它执行广泛的输入验证。

另一个问题是,菜单处理功能mainMenuFishermanMenu简单地将用户输入的数字传递回main函数是没有意义的。这些函数本身解释和处理输入会更有意义。

正如在另一个答案中已经建议的那样,您可以更改函数mainMenuFishermanMenu,而是将程序的新状态返回到main,因为这将是main需要的唯一信息,假设输入由函数mainMenuFishermanMenu解释和处理。

在这种情况下,程序的代码将如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int mainMenu(void);
enum menu_state FishermanMenu(void);
enum menu_state get_int_from_user( const char *prompt );
enum menu_state
{
MENUSTATE_MAIN,
MENUSTATE_FISHERMAN,
MENUSTATE_FISH,
MENUSTATE_TOURNAMENT_CATCH,
MENUSTATE_CLOSE_TOURNAMENT,
MENUSTATE_QUIT
};
int main( void )
{
int user_choice;
for (;;) //loop forever until input is valid
{
user_choice = get_int_from_user(
"Please select 1 to start the program or 0 to quit: "
);
if ( user_choice == 0 )
{
printf("Thank you for wasting my time! Have a great day!");
exit( EXIT_SUCCESS );
}
if ( user_choice == 1 )
{
//input is valid, so break infinite loop
break;
}
printf( "Invalid selection!n" );
}
enum menu_state ms = MENUSTATE_MAIN;
for (;;) //main program loop
{
switch ( ms )
{
case MENUSTATE_MAIN:
ms = mainMenu();
break;
case MENUSTATE_FISHERMAN:
ms = FishermanMenu();
break;
case MENUSTATE_FISH:
printf( "Fish menu not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
case MENUSTATE_TOURNAMENT_CATCH:
printf( "Tournament(catch) menu not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
case MENUSTATE_CLOSE_TOURNAMENT:
printf( "Close tournament not yet implemented, returning to main menu.n" );
ms = MENUSTATE_MAIN;
break;
case MENUSTATE_QUIT:
return;
default:
fprintf( stderr, "unexpected errorn" );
exit( EXIT_FAILURE );
}
}
}
enum menu_state mainMenu( void )
{
for (;;) //repeat forever, until input is in desired range
{
int option;
option = get_int_from_user(
"n-------Welcome to the Fishing Tournament Main Menu!-------n"
"1 - Fisherman menun"
"2 - Fish menun"
"3 - Tournament(Catch) menun"
"4 - Close Tournament (determine winner)n"
"5 - Quit Programnn"
"Please select a menu option: "
);
switch (option)
{
case 1:
printf( "opening fisherman menun" );
return MENUSTATE_FISHERMAN;
case 2:
printf( "opening fish menun" );
return MENUSTATE_FISH;
case 3:
printf( "opening tournament(catch) menun" );
return MENUSTATE_TOURNAMENT_CATCH;
case 4:
printf( "opening close tournament menun" );
return MENUSTATE_CLOSE_TOURNAMENT;
case 5:
printf( "quitting programn" );
return MENUSTATE_QUIT;
default:
printf( "input must be between 1 and 5n" );
continue;
}
}
}
enum menu_state FishermanMenu()
{
for (;;) //repeat forever, until input is in desired range
{
int option;
option = get_int_from_user(
"n-------Fisherman Menu-------n"
"1 - Register fishermann"
"2 - Search fishermann"
"3 - Go back to main menun"
"Please select a menu option: "
);
switch ( option )
{
case 1:
printf( "Register fisherman not yet implemented.n" );
return MENUSTATE_FISHERMAN;
case 2:
printf( "Search fisherman not yet implemented.n" );
return MENUSTATE_FISHERMAN;
case 3:
//change program state back to main menu
return MENUSTATE_MAIN;
break;
default:
printf("input must be between 1 and 3n");
continue;
}
}
}
int get_int_from_user( const char *prompt )
{
for (;;) //loop forever until user enters a valid number
{
char buffer[1024], *p;
long l;
puts( prompt );
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "unrecoverable error reading from inputn" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, 'n' ) == NULL )
{
int c;
printf("line input was too long!n");
//discard remainder of line
do
{
c = getchar();
if ( c == EOF)
{
fprintf( stderr, "unrecoverable error reading from inputn" );
exit( EXIT_FAILURE );
}
} while ( c != 'n' );
continue;
}
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "error converting string to numbern" );
continue;
}
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "number out of range errorn" );
continue;
}
//make sure remainder of line contains only whitespace,
//so that input such as "12dfghoh" gets rejected
for ( ; *p != ''; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "unexpected input encountered!n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto next_outer_loop_iteration;
}
}
return l;
next_outer_loop_iteration:
continue;
}
}

再三考虑,我不确定我之前的建议是否正确。由于您似乎具有严格的菜单层次结构,因此在您的情况下,不将程序的状态存储在单独的变量中,而是让菜单状态由程序的控制流隐含可能更简单。在这种情况下,您的程序将如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
void MainMenu( void );
void FishermanMenu( void );
void FishMenu( void );
void TournamentCatchMenu( void );
void CloseTournamentMenu( void );
int get_int_from_user( const char *prompt );
int main(void)
{
int user_choice;
for (;;) //loop forever until input is valid
{
user_choice = get_int_from_user(
"Please select 1 to start the program or 0 to quit: "
);
if (user_choice == 0)
{
printf("Thank you for wasting my time! Have a great day!");
exit(EXIT_SUCCESS);
}
if (user_choice == 1)
{
//input is valid, so break infinite loop
break;
}
printf("Invalid selection!n");
}
MainMenu();
}
void MainMenu(void)
{
for (;;) //repeat forever, until input is in desired range
{
int option;
option = get_int_from_user(
"n-------Welcome to the Fishing Tournament Main Menu!-------n"
"1 - Fisherman menun"
"2 - Fish menun"
"3 - Tournament(Catch) menun"
"4 - Close Tournament (determine winner)n"
"5 - Quit Programnn"
"Please select a menu option: "
);
switch (option)
{
case 1:
FishermanMenu();
break;
case 2:
FishMenu();
break;
case 3:
TournamentCatchMenu();
break;
case 4:
CloseTournamentMenu();
break;
case 5: 
return;
default:
printf( "input must be between 1 and 5n" );
continue;
}
}
}
void FishermanMenu()
{
for (;;) //repeat forever, until input is in desired range
{
int option;
option = get_int_from_user(
"n-------Fisherman Menu-------n"
"1 - Register fishermann"
"2 - Search fishermann"
"3 - Go back to main menun"
"Please select a menu option: "
);
switch (option)
{
case 1:
printf( "Register fisherman not yet implemented.n" );
break;
case 2:
printf( "Search fisherman not yet implemented.n" );
break;
case 3:
printf( "Returning to main menu.n" );
return;
default:
printf( "input must be between 1 and 5n" );
continue;
}
}
}
void FishMenu()
{
printf( "Fish Menu not yet implemented, please select another menu item.n" );
}
void TournamentCatchMenu()
{
printf( "Tournament(Catch) Menu not yet implemented, please select another menu item.n" );
}
void CloseTournamentMenu()
{
printf( "Close Tournament Menu not yet implemented, please select another menu item.n" );
}
int get_int_from_user( const char *prompt )
{
for (;;) //loop forever until user enters a valid number
{
char buffer[1024], *p;
long l;
puts( prompt );
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "unrecoverable error reading from inputn" );
exit( EXIT_FAILURE );
}
//make sure that entire line was read in (i.e. that
//the buffer was not too small)
if ( strchr( buffer, 'n' ) == NULL )
{
int c;
printf("line input was too long!n");
//discard remainder of line
do
{
c = getchar();
if ( c == EOF)
{
fprintf( stderr, "unrecoverable error reading from inputn" );
exit( EXIT_FAILURE );
}
} while ( c != 'n' );
continue;
}
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "error converting string to numbern" );
continue;
}
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "number out of range errorn" );
continue;
}
//make sure remainder of line contains only whitespace,
//so that input such as "12dfghoh" gets rejected
for ( ; *p != ''; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "unexpected input encountered!n" );
//cannot use `continue` here, because that would go to
//the next iteration of the innermost loop, but we
//want to go to the next iteration of the outer loop
goto next_outer_loop_iteration;
}
}
return l;
next_outer_loop_iteration:
continue;
}
}

但是,即使此解决方案更简单,更干净,也不像以前的解决方案那样灵活。如果您后来决定放松菜单层次结构的严格性(例如,允许在菜单层次结构中完全不同的位置直接从一个菜单跳转到另一个菜单),那么事情很快就会变得混乱。

我想通了。我的教授能够帮助我,因为他比平时晚了回复我的电子邮件。我的问题是我需要为整组菜单添加一个 while 循环MOption = mainMenu();并将每个菜单选项分配给它们各自的功能。谢谢所有回复的人,非常感谢您的时间!以下是更新的代码:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main()
{
//declare all working variables: mOption, FManOption, COption...etc...
int MOption = 0;
int FManOption = 0;
int FOption = 0;
int COption = 0;
int userChoice = 0;
//declarations for all arrays of struct
//declare a pointer to an array of struct using malloc() for fisherman, fish, catch
//process:
printf("Please select 1 to start the program or 0 to quit: ");
scanf("%d", &userChoice);
while(userChoice != 1 && userChoice != 0)
{
printf("Invalid selection! Please type a 1 or a 0: ");
scanf("%d", &userChoice);
}//end (userChoice != 1 && userChoice != 0)
if(userChoice != 1)
{
printf("Thank you for wasting my time! Have a great day!n");
return 0;
}
while(MOption != 5)
{
MOption = mainMenu();
switch(MOption)
{
case 1: FManOption = FishermanMenu();
while(FManOption != 3)
{
switch(FManOption)
{
case 1: //get a fisherman
//count fisherman
break;
case 2: //prompt for a ssn, validate, search
//if found display everything about this fisherman
break;
case 3: FManOption = mainMenu();
//reset FManOption
break;
default: printf("nInvalid selection! Please select from one of the menu optionsn");
}//end switch(FManOption)
}//end while(FManOption != 3)
break;
}
}
}
int mainMenu(MOption)
{
printf("n-------Welcome to the Fishing Tournament Main Menu!-------n");
printf("1 - Fisherman menun");
printf("2 - Fish menun");
printf("3 - Tournament(Catch) menun");
printf("4 - Close Tournament (determine winner)n");
printf("5 - Quit Programnn");
printf("Please select a menu option: ");
scanf("%d", &MOption);
if(MOption > 5 || MOption < 1)
do /* check scanf() return value for input errors */
{
printf("nInvalid selection! Please select from one of the menu optionsn");
printf("1 - Fisherman menun");
printf("2 - Fish menun");
printf("3 - Tournament(Catch) menun");
printf("4 - Close Tournament (determine winner)n");
printf("5 - Quit Programnn");
printf("Please select a menu option: ");
scanf("%d", &MOption);
}
while(MOption > 5 || MOption < 1);
return MOption; /* finally return the final correct option */
}//end main menu
int FishermanMenu(FManOption)
{
printf("n-------Fisherman Menu-------n");
printf("1 - Register fishermann");
printf("2 - Search fishermann");
printf("3 - Go back to main menun");
printf("Please select a menu option: ");
scanf("%d", &FManOption);
if(FManOption > 5 || FManOption < 1)
do /* check scanf() return value for input errors */
{
printf("nInvalid selection! Please select from one of the menu optionsn");/* handle input error */
printf("1 - Register fishermann");
printf("2 - Search fishermann");
printf("3 - Go back to main menun");
printf("Please select a menu option: ");
scanf("%d", &FManOption);
}
while(FManOption > 5 || FManOption < 1);
return FManOption; /* finally return the final correct option */
}//end Fisherman Menu

这依赖于称为隐式函数声明的功能; 这被认为是有害的,并在C99中删除。人们可能会将菜单重新排列到顶部,或者在调用函数之前对函数进行原型设计,

int mainMenu(void);
int FishermanMenu(void);

并将隐式int参数更改为返回的局部变量,

int mainMenu(void) {
int MOption;
...
}
int FishermanMenu(void) {
int FManOption;
...
}

编辑

与其弄清楚只会变得难以调试的混乱开关,不如让我建议更改应用程序结构。这段代码可以是没有太多更改的状态机,只需从函数返回下一个状态即可。

enum states {
START, MAIN, FISHPERSON, REGISTER, SEARCH, FISH, CATCH, CLOSE, END
};
enum states StartMenu(void);
enum states MainMenu(void);
enum states FishermanMenu(void);
/* ... */
typedef enum states (*state_function)(void);
static const state_function states[] = { StartMenu, MainMenu,
FishermanMenu, /*...*/0, 0, 0, 0, 0, /* END is actually 0 == NULL */0 };
int main(void)
{
enum states state = START;
while(states[state]) state = states[state]();
return 0;
}

然后从菜单中返回状态,

enum states StartMenu(void) {
int userChoice = 0;
//process:
printf("Please select 1 to start the program or 0 to quit: ");
scanf("%d", &userChoice);
while(userChoice != 1 && userChoice != 0)
{
printf("Invalid selection! Please type a 1 or a 0: ");
scanf("%d", &userChoice);
}//end (userChoice != 1 && userChoice != 0)
if(userChoice != 1) {
printf("Thank you for wasting my time! Have a great day!");
return END;
} else {
return MAIN;
}
}

要减少重复,请考虑在预先显示信息的菜单上do {} while(),而不是while() {}

最新更新