1

私は学生で、C++ を学んでいます。昨年私が作成した skul の単純なプロジェクトは、ユーザーフレンドリーにするために、スタックとそれが引き起こすメモリリークを考えずに、ある関数から別の関数への複数の呼び出しを行ったことに気付きました。基本的に、これは学生データベース管理システムであり、1 つの画面に対応する 1 つの関数 (メニュー用の関数、データの追加用の関数、データの変更用の関数など) を作成しました。コードが大きいので一部を貼り付けました。最初に 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 を使用してあるブロックから別のブロックにジャンプすることは、あまり良い考えではありません (実際にはもっと悪いことです!!)。だから、私の質問は、このタスクを達成するためのより良い方法はありますか?? (これは、上記のコードで m がやろうとしていること、つまりこのプログラムの使いやすさを意味します)

ありがとう

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

ハンドラー関数 (ie add1()) をメインに戻すだけmenu()で、終了を要求するまでループで再度呼び出されるようにする必要があります。

于 2013-10-07T10:24:15.240 に答える
0

マリオなどのコンソールでアーケード ゲームをプレイしたことはありますか? このようなゲームでは、マルチレベル メニュー (サブメニューを含むメニュー。画面ごとに 1 つのメニュー) があります。それがあなたが達成したいことであることを願っています。

通常、コンピュータ ゲームでは、このようなメニュー (状態) をスタック データ構造 (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();
        }
    
  • 場合によっては (ゲームの場合はフレームごとに 1 回、コンソール アプリの場合はユーザーがボタンを押すと 1 回) Update()、 を呼び出して最上位のメニューをレンダリングします。

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

参照:

メイン メニュー システムを作成する最良の方法は何ですか?

メニュー/ゲームループをどのように構成すればよいですか?

それが役に立てば幸い。ハッピーコーディング!=)

于 2013-10-07T10:52:44.527 に答える