Tanuj Khattar
Tanuj Khattar

Reputation: 11

C++ : One way jump to functions... any alternative?

I am a student and learning c++. Last year i made is simple project for my skul and now i realise that to make it user friendly, i made multiple calls from one function to another without thinking of the stack and the memory leak it would cause. Basically, Its a student database management system and I have made one function corresponding to one screen i.e. one function for menu, one for adddata, modify data and so on. The code is big so i have pasted a small portion . Just observe how I first called add1() from menu() and then again menu() from add1()...

 `//***************************STUDENT DATABASE***********************************

void add1(){

     system("CLS");
     char ch;
     int i=no; 
     do{   
     i++;  
     cout<<"\nName : ";
     cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
     getline (cin,s[i].name);      
     cout<<"\nClass : ";
     cin>>s[i].cl;
     cout<<"\nRollno : ";
     cin>>s[i].rollno;
     cout<<"\nMarks in";
     s[i].m.avg=0;
     for(int j=0;j<maxsb;j++)
     {
                            cout<<"\n"<<subject[j]<<": ";
                            cin>>s[i].m.s[j];
                            s[i].m.avg+=(s[i].m.s[j]/maxsb);
                            }
     no=i;
     cout<<"\nPress 'n' for next and 'b' to exit : "; 
     cin>>ch;
     cout<<"\n***********************************************************************";
     }while(ch=='n'); 
     menu(); //calling menu() again from this function...
}
                             //*************        
void menu(){
     system("CLS");
     int n,flag=0;
     do
     {
     cout<<"1.ADD DATA\n2.VIEW REPORT\n3.MODIFY DATA\n4.DELETE DATA\n5.SORT DATA\n6.GO BACK TO PREVIOUS MENU\n";
     cout<<"PLEASE ENTER YOUR CHOICE(enter corresponding integer): "; 
     cin>>n;
     switch(n)
     { case 2: report();break;
       case 1: add1();break;
       case 3: modify();break;
       case 4: del();break;
       case 5: sort();break;
       case 6: first(); 
       default:cout<<"PLEASE ENTER A VALID CHOICE";system("CLS");flag=1;
       }
       }
       while(flag==1);                              
     }
                              //**************

void first()
{
     system("CLS");
     int n,flag=0;
     cout<<"\t\t\tSoftware for Teachers";
     cout<<"\n\n1.Student Database\n\n2.Play Game\n\n3.Calculator";
     cout<<"\n\nEnter your choice: ";
     do{
     flag=0;
     cin>>n;
     switch(n)
     {
              case 1:{  if(flag2==0) 
                        {           setting();
                                    flag2=1;
                                    }
                        menu(); }
                   break;
              case 2: game();
                   break;
            //  case 3: calculator();
               //    break;
              default: cout<<"\nPlz enter a valid choice \n\n Enter your choice again:  ";flag=1;
              }
     }
     while(flag);
}

//******************************************************************************
int main()
{
    int temp;
    first();
    cin>>temp;
}
`

Such jumping from one function to another and then never returning back has been done several times in my code, which i now realize, kills the stack.. I have googled much and i know that firstly its not possible to do one way jump randomly from one function to another and combining everything in a single function and using goto to jump from one block to another isnt a very good idea(its actually worse!!). So, my question is, is there a better way i can achieve this task?? (this here means the thing m trying to do in above code i.e. the user friendliness of this program)

Thanks

Upvotes: 1

Views: 313

Answers (4)

Drop
Drop

Reputation: 13003

Did you ever played arcade games on consoles, such as Mario? In such games we have multi-level menus (menus with submenus; one menu per screen). Hope, that it is what you want to achieve.

In computer games, typically, we implement such menus (states) with a stack data structure (LIFO).

  • You wrap your menu screens (states) into objects. All resources initialized in constructor and all cleanup happens in destructor, so no leaks.

    class IState
    {
    public:
        virtual ~IState() {}
        virtual void Apply() = 0;
    };
    
    class MainMenuState : public IState
    {
    public:
        MainMenuState() { /*Here goes resources allocation*/ }
        virtual ~MainMenuState() {  /*Here goes resources freeing*/ }
        virtual void Apply() override { /*Here goes menu rendering*/ }
    };
    
    class SettingsMenuState : public IState
    {
    public:
        SettingsMenuState() { /*Here goes resources allocation*/ }
        virtual ~SettingsMenuState() {  /*Here goes resources freeing*/ }
        virtual void Apply() override { /*Here goes menu rendering*/ }
    };
    
  • You store states in stack

    std::stack<IState> states;
    
  • When user must see new menu you push state:

        states.push(MainMenuState()); // initial menu
    
        if (userWantsToSettings)
        {
            states.push(SettingsMenuState()); // second level
        }
    
  • When user want go back, you pop state

        if (userWantsGoBack)
        {
            states.pop();
        }
    
  • Sometimes (for games, it is once per frame, for console app it can be once user presses a button) you call Update(), to render topmost menu:

        void Update()
        {
            states.top().Apply();
        }
    

Refs:

What is the best way to make a main menu system?

How should I structure my menu / game loop?

Hope it helps. Happy coding! =)

Upvotes: 0

Shaggi
Shaggi

Reputation: 1161

Just enclose your menu() (either inside or outside the) function in a loop, and return normally from your add1 function.

void add1(){

    …..

    }while(ch=='n'); 
    return; <--------------
}

void menu(){
    while(true) <------------------
    {
    system("CLS");
    int n,flag=0;
    do
    {
    cout<<"1.ADD DATA\n2.VIEW REPORT\n3.MODIFY DATA\n4.DELETE DATA\n5.SORT DATA\n6.GO BACK TO PREVIOUS MENU\n";
    cout<<"PLEASE ENTER YOUR CHOICE(enter corresponding     integer): "; 
     cin>>n;
    switch(n)
   { case 2: report();break;
     case 1: add1();break;
     case 3: modify();break;
     case 4: del();break;
     case 5: sort();break;
     case 6: return; <-------------------
     default:cout<<"PLEASE ENTER A VALID CHOICE";system("CLS");flag=1;
      }
     }
     while(flag==1);                              
   }
}

Upvotes: 1

Felice Pollano
Felice Pollano

Reputation: 33252

You should just let the handlers functions ( ie add1() ) to return to the main, that will call menu() again in a loop until you ask for exit.

Upvotes: 0

Joni
Joni

Reputation: 111289

Instead of calling menu() or first() to return to the previous menu, use return. For example in the menu() function:

   case 6: return; 

This means that the control will return to the calling function right after the function call. For example when you return from add1 to menu the execution will continue in the loop that asks for choices.

Upvotes: 6

Related Questions