3

When the program first starts I can select any option from the main menu successfully. However, when I select the go back to main menu option from any of the submenus it'll go back to the main menu but no matter what option I press again afterwards it will continue to loop that menu. Only allowing me to select the go back to main menu option. How do I reset the selection to where it won't continue to loop? I have shortened the code as best as possible so that it can still compile but also demonstrate the error. Thank you in advance.

#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

tlbiro
  • 63
  • 8
  • 2
    Just as a side note: It is unsafe to use `scanf` without checking the return value. See this page for further information: [A beginners' guide away from scanf()](http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html) – Andreas Wenzel Aug 14 '21 at 02:06
  • 2
    Your posted code does not compile. You are using the functions `mainMenu` and `FishermanMenu` before declaring them (prototype declaration missing) and in the function definition of these two functions, you are specifying only the name of the parameter, but not the type of the parameter. Also, although you seem to be attempting to make these functions take one parameter, you are calling these two functions without any parameters. – Andreas Wenzel Aug 14 '21 at 02:20
  • Thank you Andreas. I am reading this now. It's not compiling? I just copy and pasted it into code blocks and it ran fine for me, minus the errors of course. Ok I will add that as well and see if that helps. Thank you very much! – tlbiro Aug 14 '21 at 02:22
  • I appreciate the work that went into making the code a complete and minimal example. Are you compiling on a C89 compiler? Implicit `int` was too confusing. – Neil Aug 14 '21 at 02:27
  • No problem. It's a GNU GCC compiler. I literally have no idea what I am doing. I added the menus to the prototype @AndreasWenzel but they aren't returning anything when I select one of the options from the menu. – tlbiro Aug 14 '21 at 02:31
  • Mine it refuses to compile unless `-ansi -Wno-implicit-function-declaration`. – Neil Aug 14 '21 at 02:39
  • `int mainMenu();` is not a function prototype, as this declaration does not specify the number and types of the function parameters. If you want to declare that the function takes no parameters, you must write `int mainMenu( void );`. However, this contradicts the function definition, where you seem to be attempting to specify that the function takes one parameter. – Andreas Wenzel Aug 14 '21 at 02:42
  • That's odd. I get a ton of implicit declarations but it still compiles and runs for me. – tlbiro Aug 14 '21 at 02:42
  • 1
    Since C99, implicit declarations are no longer permissive. See [this question](https://stackoverflow.com/q/9182763/12149471) for further information. The gcc compiler still accepts them by default, though. If you compile with `-std=c18 -pedantic-errors`, it doesn't accept them. – Andreas Wenzel Aug 14 '21 at 02:48
  • I just need to figure out how to return an option from the submenu to be able to access the main menu again and select a different menu if needed. When accessing `int FishermanMenu();` it doesn't return any option I select now after I declared it as a prototype. I need it to return a value so that I can access other menu options. – tlbiro Aug 14 '21 at 02:49
  • You should first decide whether your functions `mainMenu` and `FishermanMenu` should take a function argument or not, and change your code accordingly. You are calling these functions as if they did not take any arguments, but the functions are implemented as if they take one argument. This causes undefined behavior. Maybe you want to remove the function arguments and make them local variables instead? – Andreas Wenzel Aug 14 '21 at 02:59
  • I changed it to where it's not passing any parameters. and added a local variable in the functions to be returned to main but the switch case doesn't acknowledge my selection. – tlbiro Aug 14 '21 at 03:11

3 Answers3

1

This is relying on a feature called implicit function declarations; this is considered harmful and was removed in C99. One might rearrange the menus to be on top, or prototype the functions before calling them,

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

and change the implicit int parameter to a local variable that is returned,

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

EDIT

Instead of figuring out the mess of switches that is only going to get worse to debug, let me suggest a change in application structure. This code could be a state machine without many changes, just return the next state from the function.

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

Then one returns the state from the menu,

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

To repeat less, instead of a while() {} consider a do {} while() on menus that display the information up front.

Neil
  • 1,767
  • 2
  • 16
  • 22
  • Ok I did that and I can access the sub menu of `FishermanMenu(void)` but when I select the go back to main menu option it ends the program. How can I get it to return the correct value or access the correct function selected? – tlbiro Aug 14 '21 at 03:17
  • `1,1,3` works as expected; I see `1,2` quits. I think this is another problem, though. – Neil Aug 14 '21 at 03:22
  • There's a lot of problems I'm sure I just can't figure out where they're happening at. `1,1` work but when I select `3` to go back to main menu it ends the program. I need it to return to main menu with a reset value. – tlbiro Aug 14 '21 at 03:28
  • You have an unusual series of nested `switch` statements that is suspicious. – Neil Aug 14 '21 at 03:30
  • Yeah I think I have this whole thing messed up and this is only the start of the program. I'm also looking for the best way to return a variable back to the switch. It makes sense when I think about what I need it to do but when I put it in the compiler it always backfires. – tlbiro Aug 14 '21 at 03:36
  • 1
    I don't think a `do {} while` loop is sufficient in this case. In my solution, in order to keep OP's error message on bad input, I was forced to change the loop to an infinite loop. As far as I can tell, using a `do {} while` is only possible if you remove that error message (unless you move the `printf` call into the `while` condition and use the comma operator, which would be very ugly). – Andreas Wenzel Aug 16 '21 at 03:57
  • @AndreasWenzel I like the comma, but very good point. – Neil Aug 16 '21 at 21:38
1

I figured it out. My professor was able to help me as he responded to my email later than usual. My problem was I needed to add a while loop for the entire set of menus with MOption = mainMenu(); and assign each menu option to their respective functions. Thank you all who responded I greatly appreciate your time! Here is the updated code:

#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 options\n");
                        }//end switch(FManOption)
                    }//end while(FManOption != 3)
                    break;
        }
    }
}

int mainMenu(MOption)
{
    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", &MOption);
    if(MOption > 5 || MOption < 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", &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 fisherman\n");
    printf("2 - Search fisherman\n");
    printf("3 - Go back to main menu\n");
    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 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", &FManOption);
        }
        while(FManOption > 5 || FManOption < 1);
    return FManOption; /* finally return the final correct option */
}//end Fisherman Menu
tlbiro
  • 63
  • 8
  • 2
    One thing that I don't like about `scanf` is that if you enter bad input such as `"12dfghoh"`, then the first call to `scanf` will succeed with the value `12`, but all subsequent calls to `scanf` will fail (unless you discard the bad input manually). In my answer, I have therefore rewritten your entire program to use `fgets` instead of `scanf`. – Andreas Wenzel Aug 14 '21 at 20:30
1

The problem is that you get stuck in this while loop forever:

while (FManOption != 3)

This loop only makes sense when you are inside the "Fisherman" sub-menu, but you should leave this loop and return the program to its previous state after the user selects "Go back to main menu".

Instead of attempting to write your code in such a way that the state of the program (e.g. whether the user is currently in the main menu or a sub-menu) is implied by the control flow of the program, it is often easier to store the program state explicitly in a variable, for example like this:

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

It is also worth noting that your functions mainMenu and FishermanMenu contain unnecessary code duplicaton. You can simplify the function mainMenu the following way:

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

However, it is important to always check whether the function scanf succeeded before attempting to use the result of scanf. This can be accomplished by checking the return value of scanf. Also, after using scanf, it is important to discard the input from the rest of the line. Otherwise, if the user for example enters "12dfghoh", then all subsequent calls to scanf will fail, because it won't be able to remove dfghoh from the input stream when trying to read a number.

Therefore, here is the code in which I check the return value of scanf and also discard all remaining input in the line:

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

On the other hand, for line-based input, it would probably be better to use fgets instead of scanf, because then you don't have to deal with removing bad input from the input stream. See this link for further information:

A beginners' guide away from scanf()

Using the fgets function, the function mainMenu would look like this:

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

However, you cannot simply replace the function mainMenu in your code with my code above, because mixing scanf and fgets in your code will not work very well. This is because scanf will not read one line at a time from the input stream, but will only extract as much as it needs to read the number and will leave the rest of the line, including the newline character, in the buffer. Therefore, if you use fgets immediately after scanf, fgets will read the remainder of the line that scanf did not extract, which will be often a string containing nothing else than the newline character.

Therefore, if you decide to use fgets (which I recommend), then you should use it everywhere in your program and not mix it with scanf, for example like this:

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

In the above code, I created a new function get_int_from_user, which performs extensive input validation.

Another problem is that it is not meaningful for the menu handling functions mainMenu and FishermanMenu to simply pass the number that the user entered back to the main function. It would be more meaningful for these functions to interpret and handle the input themselves.

As already suggested in the other answer, you could change the functions mainMenu and FishermanMenu to instead return the new state of the program back to main, as that would be the only information main needs, assuming that the input is interpreted and handled by the functions mainMenu and FishermanMenu.

In that case, the code of your program would instead look like this:

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

On second thought, I'm not sure if my previous advice was correct. Because you seem to have a strict menu hierarchy, it may be simpler in your case not to store the state of the program in a separate variable, but to instead let the menu state be implied by the control flow of the program. In that case, your program would look like this:

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

However, even if this solution is simpler and cleaner, it is not as flexible as the previous solution. If you later decide to loosen the strictness of the menu hierarchy (for example by allowing to directly jump from one menu to another menu in a completely different place in the menu hierarchy), then things would get messy very quickly.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • Wow thank you Andreas. This helps a lot and I appreciate you taking the time to write all of that code. I will try and implement this and see if I can get it to work with the rest of the program as well. This program I am working on for class also implements structures and passing pointers and my biggest difficulty is understanding how pointers are passed and how to pass from one function to another without causing infinite loops or errors. – tlbiro Aug 15 '21 at 18:48
  • @tlbiro: I have now added an alternative solution to the bottom of my answer, which is the cleaner solution when the menu hierarchy is strict (which seems to be the case with you). But the disadvantage of that solution is that if you later decide to loosen the menu hierarchy, then this solution will not work very well. The previous solution would be better in that case, as it is more flexible. – Andreas Wenzel Aug 16 '21 at 01:15
  • Sorry I thought I did accept one but guess I didn't click it at all. Thank you for the alternative solution! I was able to resolve my issue but of course as I expected I ran into another one. I will post that issue in a separate question. Thank you again! – tlbiro Aug 16 '21 at 02:55
  • @tlbiro: Actually, I have now edited my answer to include a third alternative. After posting your new question, feel free to post a link to it as a comment to my post. That way, I will get notified of your new question. – Andreas Wenzel Aug 16 '21 at 03:28
  • @tlbiro: Even if your issue is resolved, I do suggest that you read my updated answer, because I also write about problems in the general structure in your program, and present different alternatives on how to restructure your program. – Andreas Wenzel Aug 16 '21 at 03:40
  • I read your answer but I am not sure what enum is or what it means as we have not been taught this in our class yet to my knowledge. Our professor wants us to only use methods we have learned so far in class. Hence the reason my code is such a mess. I am trying my best to understand how everything should flow together, but there are other aspects to this program that I have not posted due to the length of the code. – tlbiro Aug 16 '21 at 13:42
  • 1
    @tlbiro: See [this documentation](https://en.cppreference.com/w/c/language/enum) for what `enum` does. Basically, the compiler assigns a unique value to every member of the `enum` construct. `MENUSTATE_MAIN` will be automatically assigned the value `0`, `MENUSTATE_FISHERMAN` will automatically be assigned the value `1`, etc. Although you could simply write `0` and `1` instead of using these `enum` identifiers, your code is a lot easier to read if you use them, as the meaning of the value is immediately apparent. – Andreas Wenzel Aug 16 '21 at 17:27
  • @tlbiro: If you don't want to use an `enum`, then I recommend that you pay special attention to the last solution of my answer, as that one does not use `enum`. – Andreas Wenzel Aug 16 '21 at 17:32
  • A lot of times it is convenient to break in the middle, for that, you can't go wrong with `break`. Repeated code causes maintenance issues, something this answer is careful to avoid. – Neil Aug 16 '21 at 21:34