2

私は C の初心者であり、gcc と gdb を使用してデバッグし、Fedora でプログラムをテストしています。ユーザーからの入力を受け取るプログラムがあります。入力された最初の文字列が「create」の場合は、2 番目のコマンドを調べます。それが「object」の場合は、createObject 関数に進みます。

うまくいけば、私のコードがこれを少し明確にするでしょう:

static void parseCmd(char **input) {
    if(!strcmp(input[0], "create")) {
        if(!strcmp(input[1], "object")) {
            if(input[2] && strcmp(input[2], ""))
                createObject(input[2]);
            else
                printf("Object needs a name\n");
        }
        else
            printf("Command needs more parameters\n");
    }
    else
        printf("Command not recognized\n");
}

「オブジェクトの作成」だけを入力してテストすると(オブジェクトの後にスペースがなく、ENTERキーのみ)

Linuxでは、「オブジェクトには名前が必要です」と表示されます

しかし、Windows ではプログラムがクラッシュし、ハングするだけです。Linux と同じように動作するようにコードを変更するにはどうすればよいですか?

4

4 に答える 4

3

次のようなコードがあります。

if(input[2] && strcmp(input[2], ""))

input[2]が存在し、空でないかどうかを検出しようとしているようです。

ただし、これは機能しません。3 番目のパラメーターがないinput[2]と NULL または になるという保証はありません""

input[2]その時点でガベージ値を持つ可能性がありますが、ガベージはテストに合格します!

それを修正するには、いくつかのオプションがあります。
いずれにせよ、この関数の呼び出し元は、有効なデータに設定されていない要素が代わりに Zero/nil に設定されることを保証する必要があります。

または、私が好む方法として、関数のシグネチャを次のように変更します。

static void parseCmd(char **input, int num_inputs);

そして、input-array とともに入力の数を渡します。

于 2012-08-03T21:55:49.000 に答える
2

この行に問題があります:

if(input[2] && strcmp(input[2], ""))

テストのinput[2]は「オブジェクトの作成」が存在しません。これがクラッシュする理由を説明しています。

この助けを願っています。

よろしく。

于 2012-08-03T21:55:27.637 に答える
1

あなたは、ヒットするアクセス権がないメモリをヒットしています。

参考にさせていただきます

ポインタが有効かどうかを確認する方法は?

彼がどのように物を渡しているか知りたい人:

int main(void) 
{ 
    char* values[] = {"1", "2", "3"};
    parseCmd(values);
} 

入力[2]にアクセスしようとすると発生しますが、何を取り入れているのかわからない場合はいつでも発生する可能性があります。入力を取得するときに健全性チェックを行うことをお勧めします。values[2] に何も入れていない場合は、関数にそれを認識させるか、処理方法を変更してください。ポインターとポインターへのポインターを使用すると、値を割り当てるときに健全性チェックを軽視することはできません。

于 2012-08-03T22:13:56.667 に答える
1

潜在的なアクセス違反または未定義の動作 (まあ、未定義の値) の領域に入りました。

input[2] && strcmp(input[2], "")

の長さがinput2 だけの場合、これは読み取り可能なポイントを超えて読み取っています。最悪の場合、(Windows のように) segfault が発生し、最良の場合、OS がそれを許可し、ランダムな値を取得します。(ただし、Linux はそれまたは *input[2] を 0 として扱っているようです。)

とにかく、アクセスが許可されていないコンテンツを読み取るのではなく、入力の長さを渡し、代わりにそれを確認してください。

static void parseCmd( char **input, size_t num) { //or just int if size_t isn't already defined
    //compare num
}

- 編集 -

Daniel Fischer が指摘したように、明らかargv[argc]に有効な読み取りであり、null ポインターであることが保証されています。

実際に関数に渡していると仮定するとargv、これは、この動作に依存できることを意味します。ただし、他の2つのifステートメントはこれをチェックしません。関数を一般化するために、長さを渡す方が良いです(または、paulsm4が言ったように、getopt関数を調べる必要があります-これにより、パラメーターの解析が大幅に行われます独自の解析方法をローリングするよりも簡単です)。

于 2012-08-03T21:55:14.653 に答える