1

我是一名学生,正在学习 C++。去年我为我的 skul 做了一个简单的项目,现在我意识到为了让它对用户友好,我从一个函数到另一个函数进行了多次调用,而不考虑堆栈和它会导致的内存泄漏。基本上,它是一个学生数据库管理系统,我做了一个功能对应一个屏幕,即一个菜单功能,一个添加数据,修改数据等。代码很大,所以我粘贴了一小部分。只需观察我如何首先从 menu() 调用 add1(),然后再从 add1() 调用 menu() ...

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

这种从一个函数跳转到另一个函数然后再不返回的情况在我的代码中已经完成了好几次,我现在意识到,这会杀死堆栈。我用谷歌搜索了很多,我知道首先它不可能以一种方式随机跳转一个函数到另一个函数并将所有内容组合在一个函数中并使用 goto 从一个块跳转到另一个块不是一个好主意(实际上更糟!)。所以,我的问题是,有没有更好的方法可以完成这项任务?(这意味着我在上面的代码中试图做的事情,即这个程序的用户友好性)

谢谢

4

4 回答 4

6

不要调用menu()first()返回上一个菜单,而是使用return。例如在 menu()函数中:

   case 6: return; 

这意味着控件将在函数调用后立即返回到调用函数。例如,当您从执行返回时,add1menu在要求选择的循环中继续。

于 2013-10-07T10:23:50.917 回答
1

只需将您的 menu()(在内部或外部)函数包含在一个循环中,然后从您的 add1 函数正常返回。

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);                              
   }
}
于 2013-10-07T10:28:08.147 回答
0

您应该让处理程序函数(即add1())返回到主函数,它将menu()在循环中再次调用,直到您要求退出。

于 2013-10-07T10:24:15.240 回答
0

你有没有在主机上玩过街机游戏,比如马里奥?在此类游戏中,我们有多级菜单(带有子菜单的菜单;每个屏幕一个菜单)。希望,这是您想要实现的目标。

在计算机游戏中,通常我们使用堆栈数据结构 (LIFO) 来实现此类菜单(状态)。

  • 您将菜单屏幕(状态)包装到对象中。在构造函数中初始化的所有资源和所有清理都发生在析构函数中,因此没有泄漏。

    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*/ }
    };
    
  • 您将状态存储在堆栈中

    std::stack<IState> states;
    
  • 当用户必须看到新菜单时,您推送状态:

        states.push(MainMenuState()); // initial menu
    
        if (userWantsToSettings)
        {
            states.push(SettingsMenuState()); // second level
        }
    
  • 当用户想要返回时,您会弹出状态

        if (userWantsGoBack)
        {
            states.pop();
        }
    
  • 有时(对于游戏,它是每帧一次,对于控制台应用程序,它可以是一旦用户按下按钮)你调用Update(),以呈现最顶层的菜单:

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

参考:

制作主菜单系统的最佳方法是什么?

我应该如何构建我的菜单/游戏循环?

希望能帮助到你。快乐编码!=)

于 2013-10-07T10:52:44.527 回答