0

これは私が立ち往生しているラボの課題です。

この文法を受け入れる必要があります(ab)*b。これは基本的に、任意の数の「ab」と b で終わることを意味します。

私はこのコードを書きましたが、どういうわけか、最初の 2 文字だけをチェックします。

#include <iostream.h>
#include <conio.h>
#include <string.h>

enum track {true, false};

void main()

{
    clrscr();
    char*str;
    enum track track_pos, track_pos_2;
    cout<<"enter the string: ";
    cin>>str;
    int len=strlen(str);
    cout<<"length of the string is "<<len;
    getch();
    int i;
    for(i=0;i<len; i++)
    {
        ++str;
        cout<<"loop"<<i;
        if(*str=='a' && i%2==0)
        {
            cout<<"\nchecking a...";
            track_pos=true;
            cout<<"\na.check";
            ++str;
            if (*str=='b')
                {
                cout<<"\nchecking b...";
                track_pos=true;
                cout<<"\nb.check";
            }
            else{
                track_pos=false;
                cout<<"\nb.uncheck";
            }
        }

    }

    if(*str=='b')
        track_pos_2=true;
    else
        track_pos_2=false;

    if(track_pos==true && track_pos_2==true)
        cout<<"\nThe string is accpeted.";
    else
        cout<<"\nThe string is rejected.";

    getch();
    cout<<"\n\nDo you want to continue (Y/N)? ";
    char ch;
    cin>>ch;
    if(ch=='y' || ch=='Y')
        main();

}
4

4 に答える 4

12

私はこれを後悔するつもりですが、この質問を見るたびに、あなたのコードに何か問題があることがわかります. これが行ごとです。私はおそらく多くを逃した。

このヘッダーの正しい名前は「iostream.h」ではなく「iostream」です。「.h」バージョンは非推奨です。同様に、最新の C++ では "string.h" ではなく "string" を使用し、最新の STL 文字列クラスを使用します。

#include <iostream.h>
#include <conio.h>
#include <string.h>

指摘されたように、これをしないでください。bool標準タイプと反対の値を持つように標準タイプを再定義しました。これが合法であることも知りません。

enum track {true, false};

main関数の戻り値はintではなくvoidです。

void main()    
{
    clrscr();

バッファオーバーフローとは何か知っていますか? ここでは、メモリを割り当てずにポインタとして定義strし、後でメモリの未定義ビットに書き込みます。これは未定義の動作であり、ほぼ確実にクラッシュします。strとして定義することをお勧めしますstd::string- これにより、バッファオーバーフローがうまく回避され、プログラムで使用できる多くの便利なメソッドがあります。

    char*str;
    enum track track_pos, track_pos_2;
    cout<<"enter the string: ";

これがバッファ オーバーフローです。あなたは、メモリのどの領域を知っている人に書いています。

    cin>>str;

strだったらstd::string- あなたはそうするでしょうsize_t len=str.length()

    int len=strlen(str);
    cout<<"length of the string is "<<len;

このようなコンソール IO 関数と iostreams 関数を混在させることは、おそらく良い考えではありません。問題を引き起こす可能性のあるバッファリングの問題がいくつかあります。

    getch();

i再度使用しないため、ループの本体で宣言します。そのようです:

    for (int i=0; i<len; i++) etc...

    int i;
    for(i=0;i<len; i++)
    {

poiter 算術を使用する代わりに、現在の文字のインデックスを追跡しているため、それを使用して配列としてi扱います。この方法では、すべての方法で同期strを維持する必要はありません。ちなみに、これがあなたが報告しているバグの原因です。stri

        ++str;
        cout<<"loop"<<i;

これを次のように変更する必要があります。

        if (str[i]=='a' && i%2==0)

(ちなみに、ポインター演算バージョンとは異なり、これstrは であっても機能します)。std::string

        if(*str=='a' && i%2==0)
        {

文字列が一致しないことがわかった場合は、文字列の最後に進む意味がありません。

                cout<<"\nchecking a...";

私はこのようなステータス フラグは好みません。これらのフラグが急増しているため、コードの一部が理解しにくく、適切な動作を追跡できません。名前track_posはニーモニックではないため、コードを詳しく調べないと意味を理解するのが難しくなります。

for ループの本体内のコードをリファクタリングして関数を呼び出すことをお勧めします。この関数の目的は、単に「ab」の単一のグループに一致させることです。この関数は、一致する場合は true を返し、一致する場合は false を返します。しなかった。

                track_pos=true;
                cout<<"\na.check";

前述のバッファ オーバーフローを扱っているため、未定義のメモリを反復していることに注意してください。また、ここではインクリメントしていないことに注意してくださいi

                ++str;
                if (*str=='b')
                        {
                        cout<<"\nchecking b...";
                        track_pos=true;
                        cout<<"\nb.check";
                }
                else{
                        track_pos=false;
                        cout<<"\nb.uncheck";
                }
        }

    }

ここに到達すると、for ループによると、文字列全体を反復処理したため、文字列の末尾を過ぎて (バッファ オーバーフローを無視しても) 調べる必要があるため、このテストが成功する可能性はありません。要するに、for ループが行き過ぎているに違いありません。

    if(*str=='b')
        track_pos_2=true;
    else
        track_pos_2=false;

    if(track_pos==true && track_pos_2==true)

スペルミスについて言及する必要がありますか?

        cout<<"\nThe string is accpeted.";
    else
        cout<<"\nThe string is rejected.";

    getch();
    cout<<"\n\nDo you want to continue (Y/N)? ";
    char ch;
    cin>>ch;

コードを適切なサブルーチンにリファクタリングすると、プログラムの構造が自動的に処理されることがわかります。再帰呼び出しmainは厳密には違法ではないことに注意してください。ただし、これは一種の奇妙であり、プログラムが終了しない場合、最終的にスタック オーバーフローにつながる明らかな脆弱性があることに注意してください。

    if(ch=='y' || ch=='Y')
        main();

}
于 2009-08-29T10:05:03.843 に答える
6

単純なステート マシンを実装します。次の状態があります。

  • 0 = 開始
  • 1 = 「(ab) の a を受け取りました」
  • 2 = 「(ab) の b を受信」
  • 3 = 「最終 b を受信」
  • -1 = エラー、無効な文法

次に、次のような関数が必要です。

int nextState(int currentState, char inputChar) {
  if (currentState == 0 && inputChar == 'a') return 1; // handled string is "a"
  if (currentState == 0 && inputChar == 'b') return 3; // handled string is "b"
  if (currentState == 1 && inputChar == 'b') return 2; // handled string is "ab", or "abab", or ...
  if (currentState == 2 && inputChar == 'a') return 1; // handled string is "aba", or "ababa", or ...
  if (currentState == 2 && inputChar == 'b') return 3; // handled string is "abb", or "ababb", or ...
  return -1;
}

状態 0 から開始して、入力文字に対してこの「ステート マシン」を反復し、状態 3 になった場合、入力は有効です。

int isValid(char* inputString) {
  int state = 0;
  for(int i=0; i<str_len(inputString); i++) {
    state = nextState(state, inputString[i]);
  }

  return (state == 3);
}
于 2009-08-29T09:35:57.240 に答える
4

あなたのコードに問題があります:

#include <iostream.h>

次のようにする必要があります。

#include <iostream>

以下は、非標準の (そして非常に古い) ヘッダーです。

#include <conio.h>

以下は不正です - true と false は予約語です。

enum track {true, false};

C および C++ では、main は int を返す必要があります。

void main()

非標準機能:

clrscr();

このポインタにメモリが割り当てられていません:

char*str;

次にここで使用されます-結果は未定義の動作になります:

cin>>str;

メインへの不正な呼び出し:

    main();

非常に古くて時代遅れの C++ コンパイラを使用していると思われます。MinGW などに置き換える必要があります。

于 2009-08-29T09:56:33.127 に答える
1

これをしないでください!

enum track {true, false};

ここで、true は 0 に等しく、false は 1 に等しくなります! 後で track_pos を割り当てると、間違った値になる可能性があります! (bool を int に変換するとき、true は 1 に変換され、false は 0 に変換されるためです。)

しかし、それは推測にすぎません。多分それは重要なことです。

于 2009-08-29T09:37:34.960 に答える