返回主菜单不断循环菜单

2024-02-08

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

#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 options\n");
                        }//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 menu\n");
    printf("2 - Fish menu\n");
    printf("3 - Tournament(Catch) menu\n");
    printf("4 - Close Tournament (determine winner)\n");
    printf("5 - Quit Program\n\n");
    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 options\n");
            printf("1 - Fisherman menu\n");
            printf("2 - Fish menu\n");
            printf("3 - Tournament(Catch) menu\n");
            printf("4 - Close Tournament (determine winner)\n");
            printf("5 - Quit Program\n\n");
            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 fisherman\n");
    printf("2 - Search fisherman\n");
    printf("3 - Go back to main menu\n");
    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 options\n");/* handle input error */
            printf("1 - Register fisherman\n");
            printf("2 - Search fisherman\n");
            printf("3 - Go back to main menu\n");
            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 menu\n" );
                            ms = MENUSTATE_FISHERMAN;
                            break;
                        case 2:
                            printf( "opening fish menu\n" );
                            ms = MENUSTATE_FISH;
                            break;
                        case 3:
                            printf( "opening tournament(catch) menu\n" );
                            ms = MENUSTATE_TOURNAMENT_CATCH;
                            break;
                        case 4:
                            printf( "opening close tournament menu\n" );
                            ms = MENUSTATE_CLOSE_TOURNAMENT;
                            break;
                        case 5:
                            //quit program
                            exit( EXIT_SUCCESS );
                        default:
                            fprintf( stderr, "unexpected error\n" );
                            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 error\n" );
                            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 error\n" );
                    exit( EXIT_FAILURE );
            }
        }
    }
}

还值得注意的是,你的功能mainMenu and FishermanMenu包含不必要的代码重复。您可以简化功能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 menu\n");
        printf("2 - Fish menu\n");
        printf("3 - Tournament(Catch) menu\n");
        printf("4 - Close Tournament (determine winner)\n");
        printf("5 - Quit Program\n\n");
        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 options\n");
    }
}

然而,重要的是要始终检查该功能是否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 menu\n");
        printf("2 - Fish menu\n");
        printf("3 - Tournament(Catch) menu\n");
        printf("4 - Close Tournament (determine winner)\n");
        printf("5 - Quit Program\n\n");
        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 options\n");

        //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 https://en.cppreference.com/w/c/io/fgets代替scanf,因为这样您就不必处理从输入流中删除错误输入的问题。请参阅此链接了解更多信息:

远离 scanf() 的初学者指南 http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html

使用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 menu\n");
        printf("2 - Fish menu\n");
        printf("3 - Tournament(Catch) menu\n");
        printf("4 - Close Tournament (determine winner)\n");
        printf("5 - Quit Program\n\n");
        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 number\n" );
            continue;
        }

        //make sure remainder of line contains only whitespace,
        //so that input such as "12dfghoh" gets rejected
        for ( ; *p != '\0'; 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 5\n" );
            continue;
        }

        return option;
    }
}

但是,您不能简单地替换该功能mainMenu在你的代码和我上面的代码中,因为混合scanf and fgets在你的代码中不会很好地工作。这是因为scanf不会一次从输入流中读取一行,而只会提取读取数字所需的内容,并将该行的其余部分(包括换行符)保留在缓冲区中。因此,如果您使用fgets之后立马scanf, fgets将读取该行的其余部分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 menu\n" );
                        ms = MENUSTATE_FISHERMAN;
                        break;
                    case 2:
                        printf( "opening fish menu\n" );
                        ms = MENUSTATE_FISH;
                        break;
                    case 3:
                        printf( "opening tournament(catch) menu\n" );
                        ms = MENUSTATE_TOURNAMENT_CATCH;
                        break;
                    case 4:
                        printf( "opening close tournament menu\n" );
                        ms = MENUSTATE_CLOSE_TOURNAMENT;
                        break;
                    case 5:
                        //quit program
                        exit( EXIT_SUCCESS );
                    default:
                        fprintf( stderr, "unexpected error\n" );
                        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 error\n" );
                        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 error\n" );
                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 menu\n"
            "2 - Fish menu\n"
            "3 - Tournament(Catch) menu\n"
            "4 - Close Tournament (determine winner)\n"
            "5 - Quit Program\n\n"

            "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 5\n" );
            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 fisherman\n"
            "2 - Search fisherman\n"
            "3 - Go back to main menu\n"
            "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 3\n" );
            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 input\n" );
            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 input\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        errno = 0;
        l = strtol( buffer, &p, 10 );

        if ( p == buffer )
        {
            printf( "error converting string to number\n" );
            continue;
        }

        if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
        {
            printf( "number out of range error\n" );
            continue;
        }

        //make sure remainder of line contains only whitespace,
        //so that input such as "12dfghoh" gets rejected
        for ( ; *p != '\0'; 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,它执行广泛的输入验证。

另一个问题是它对于菜单处理函数没有意义mainMenu and FishermanMenu只需将用户输入的号码传递回main功能。对于这些函数来说,自己解释和处理输入会更有意义。

正如其他答案中已经建议的,您可以更改功能mainMenu and FishermanMenu相反,将程序的新状态返回到main,因为这将是唯一的信息main需要,假设输入由函数解释和处理mainMenu and FishermanMenu.

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

#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 error\n" );
                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 menu\n"
            "2 - Fish menu\n"
            "3 - Tournament(Catch) menu\n"
            "4 - Close Tournament (determine winner)\n"
            "5 - Quit Program\n\n"

            "Please select a menu option: "
        );

        switch (option)
        {
            case 1:
                printf( "opening fisherman menu\n" );
                return MENUSTATE_FISHERMAN;
            case 2:
                printf( "opening fish menu\n" );
                return MENUSTATE_FISH;
            case 3:
                printf( "opening tournament(catch) menu\n" );
                return MENUSTATE_TOURNAMENT_CATCH;
            case 4:
                printf( "opening close tournament menu\n" );
                return MENUSTATE_CLOSE_TOURNAMENT;
            case 5:
                printf( "quitting program\n" );
                return MENUSTATE_QUIT;
            default:
                printf( "input must be between 1 and 5\n" );
                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 fisherman\n"
            "2 - Search fisherman\n"
            "3 - Go back to main menu\n"
            "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 3\n");
                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 input\n" );
            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 input\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        errno = 0;
        l = strtol( buffer, &p, 10 );

        if ( p == buffer )
        {
            printf( "error converting string to number\n" );
            continue;
        }

        if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
        {
            printf( "number out of range error\n" );
            continue;
        }

        //make sure remainder of line contains only whitespace,
        //so that input such as "12dfghoh" gets rejected
        for ( ; *p != '\0'; 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 menu\n"
            "2 - Fish menu\n"
            "3 - Tournament(Catch) menu\n"
            "4 - Close Tournament (determine winner)\n"
            "5 - Quit Program\n\n"

            "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 5\n" );
                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 fisherman\n"
            "2 - Search fisherman\n"
            "3 - Go back to main menu\n"
            "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 5\n" );
                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 input\n" );
            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 input\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        errno = 0;
        l = strtol( buffer, &p, 10 );

        if ( p == buffer )
        {
            printf( "error converting string to number\n" );
            continue;
        }

        if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
        {
            printf( "number out of range error\n" );
            continue;
        }

        //make sure remainder of line contains only whitespace,
        //so that input such as "12dfghoh" gets rejected
        for ( ; *p != '\0'; 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;
    }
}

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

返回主菜单不断循环菜单 的相关文章

随机推荐

  • 从 VIM 插件中检测文件类型?

    我有一个 vim 插件 它定义了一堆键映射 我试图弄清楚如何根据文件类型更改键映射的定义 例如 如果文件是 py 则将键映射到 X 如果文件是 php 则将键映射到 Y Thanks 是的 一种方法是使用 autocmd 调用设置地图的自定
  • 使用 DDD 创建子实体的正确方法

    我对 DDD 世界相当陌生 在阅读了几本有关它的书籍 其中包括 Evans DDD 后 我无法在互联网上找到我的问题的答案 使用 DDD 创建子实体的正确方法是什么 你看 互联网上的许多信息都在某种简单的层面上运作 但细节是魔鬼 为了简单起
  • iOS地理围栏中区域可以设置的最大和最小半径是多少

    我当时正在 iOS 中进行地理围栏工作 我实际上想在地图上设置不同的区域 每个区域的半径不同 我实际上想知道 iOS 地理围栏中区域的最小和最大半径 Thanks 在 iOS 中 没有指定最小半径 苹果表示 具体的阈值距离由硬件和当前可用的
  • laravel dusk TeaDown() 必须与 Illuminate\Foundation\Testing\TestCase::tearDown() 兼容

    public function tearDown this gt browse function Browser browser browser gt click navbarDropdown gt click dropdown item
  • 这些嵌套向量是如何连接的?

    我编写了一段代码 它创建了一个向量 记分板 其中包含 3 个大小为 3 的独立向量 所有向量都包含符号 在所有索引 0 2 处 当我现在执行 向量集 时在记分牌的第一个向量上 要将其第一个元素更改为 X 向量 2 和 3 也会更改 这是如何
  • 防止在 Javascript 中自动创建全局变量

    我刚刚花了一些时间调试一个问题 归根结底是忘记使用var关键字位于新变量标识符前面 因此 Javascript 会自动在全局范围内创建该变量 有什么方法可以防止这种情况发生 或者更改默认行为 而不使用像 JSLint 这样的验证器 在编写和
  • 如何仅在第一次启动时显示视图?

    我使用 Xcode 4 5 和故事板构建了一个应用程序 第一次启动应用程序时 我希望初始视图控制器出现 并附带必须接受才能继续的条款和条件 之后 我希望应用程序启动并跳过第一个视图控制器并转到第二个视图控制器 我知道我必须使用 NSUser
  • Android 4.3 BTLE作为服务器:如何启动广告?

    我正在尝试使用 4 3 中的新 BTLE API 在 Nexus 7 上实现 BTLE 服务器 我遇到了几个问题 首先 SDK 中没有示例 唯一的例子是针对客户的 其次 文档实际上告诉你做错误的事情 它指出 人们必须使用BluetoothA
  • 如何检测 MemoryMappedFile 是否正在使用

    在 C 4 0 中 MemoryMappedFile有几种工厂方法 CreateFromFile CreateNew CreateOrOpen or OpenExisting 我需要打开MemoryMappedFile如果存在 则从文件创建
  • Gitlab docker 和 external_url

    你好 我使用 docker 安装了最新的 gitlab 我使用 p 10080 80 和 10022 22 启动容器 我可以浏览 gitlab 并执行我需要的操作 我什至可以分别使用端口 10080 和 10022 git 克隆 http
  • 如何在android webview中启用默认突出显示菜单?

    如何在 android webview 中启用默认文本突出显示菜单 例如 复制 粘贴 搜索 共享 在 Android 1 5 2 3 上工作 您可以使用emulateShiftHeld 自 2 2 起公开 但现在已弃用 此方法将您的 Web
  • 使用 'hd' 参数限制 Google OAuth 访问一个域 (Django / python-social-auth)

    我正在构建一个内部网络应用程序供我的公司使用 并希望使用我们的 Google Apps 域来管理来自我们公司域用户名的访问 本问题的其余部分为 example com 我在用着 Django 1 9 5 python social auth
  • 如何在日期字段上显示日期选择器日历

    这是关于如何使用 jQuerydate picker在 django 支持的站点中 models py is from django db import models class holidaytime models Model holid
  • 对数组使用限制?

    有没有办法告诉 C99 编译器我访问给定数组的唯一方法是使用 myarray index 说这样的话 int heavy calcualtions float restrict range1 float restrict range2 fl
  • 为 iPhone 本地化货币

    我希望我的 iPhone 应用程序允许用户使用适当的符号 等 输入 显示和存储货币金额 NSNumberFormatter 会做我需要的一切吗 当用户切换其区域设置并且这些金额 美元 日元等 存储为 NSDecimalNumbers 时会发
  • Java 中 HTML 字符编码的转换

    我们正在尝试下载网页源代码 但是由于字符编码的原因 我们无法正确看到某些特定字符 例如 我们尝试了以下代码来转换字符串 text 变量 的编码 byte xyz text getBytes text new String xyz windo
  • React:搜索和过滤功能存在问题

    我正在开发一个组件 它应该能够 按输入搜索 使用输入字段 在触发 onBlur 事件后将调用一个函数 之后onBlur事件开始寻找 方法将运行 按所选流派过滤 用户可以从其他组件中从流派列表中选择流派 之后onClick事件启动过滤器 方法
  • 使用 Facebook 图表来获取粉丝页面的粉丝?

    我有一个粉丝页面 位于http www facebook com shop4tronix http www facebook com shop4tronix 我可以通过以下方式访问此页面上的信息 http graph facebook co
  • 文本区域 onresize 不起作用

    根据w3schools
  • 返回主菜单不断循环菜单

    当程序第一次启动时 我可以成功地从主菜单中选择任何选项 但是 当我从任何子菜单中选择 返回主菜单 选项时 它都会返回主菜单 但无论我之后再次按哪个选项 它都会继续循环该菜单 只允许我选择返回主菜单选项 如何将选择重置到不会继续循环的位置 我