2

初めて投稿するので、混乱させて申し訳ありません:

私はこのような関数を書いています:

int myFunc(char* inputStr, int *argCTemp, char** argVTemp[]);

私の関数の目的は、入力文字列 (基本的には任意のユーザー入力) のコピーを取得し、それを使用strtokしてトークンに変換し、配列ポインター ( ) を介して配列に入力することargVです。が終了したらmyFunc、うまくいけば、文字列から引数の数と文字列の配列が得られinputStrます。

これが私がそれを呼び出す方法の例です:

int main(int argc, char** argv[])
{
    int argCTemp = -1;
    char** argVTemp; 

    // 1 Do Stuff
    // 2 Get input string from user 
    // 3 then call myfunc like this:

    myFunc(inputStr, &argCTemp, &argVTemp);

    // 4: I get garbage whenever I try to use "argVTemp[i]" 
}

私の質問: 安全で一貫した方法でこれを行うにはどうすればよいですか? プロはこれをどのように行うのですか?


  1. malloc次の理由で使用しません。

    • 入力の引数の数またはそれぞれの長さがわかりません(スペースを動的に割り当てるため)。それが私がポインターを使用する理由だと思いました
    • メイン関数で宣言しているので、スタック上にある場合でも、使用される/メモリへのポインタは問題なく/スコープ内に留まるargCTempと思いました。argVTemp
  2. myFunc終了すると、作成されたスタック参照が無効になることがわかっているため、呼び出し元の関数からポインターを送信しました。ポインターなどを使用する必要がありますmallocか?

  3. 最後に: 終了する前に、 andmyfuncの値を確認し、有効な内容を持っていることを確認します。私は次のように設定しています:argCTempargVTempargCtempargVtemp

    (*argCTemp) = argCount;
    (*argVTemp)[0] = "foo";
    

関数が終了する前に問題なく動作しているようです。メモリ内の別の場所にポインターを設定しているため、参照が失敗する理由がわかりません。mallocポインターを設定するときにINSIDEを使用してみましたが、終了して呼び出し元の関数によって読み取られると、myFuncまだゴミになります。myFunc

これが紛らわしい場合は申し訳ありませんが、事前に助けてくれてありがとう.

4

3 に答える 3

1

「自分の入力の引数の数やそれぞれの長さが分からない」ので、あなたも使うことができますmalloc。バッファがいっぱいになったら、reallocバッファする必要があります。より良い方法: 入力全体を保存する必要はありません。ライン、トークン、またはブロックの方が優れています。それらを格納する静的配列を設定するだけです。入力が100 mbを超える場合は、ハッシュの方が良いかもしれません。

下手な英語でごめんなさい。

于 2012-03-19T05:52:17.910 に答える
0

一般的に言えば、結果に含まれるトークンの数がわからないためmalloc()realloc()や同等のものを使用して配列を動的に割り当てる必要があります。あるいは、呼び出し元に配列のサイズとともに配列を渡し、配列が十分に大きくない場合はエラー表示を返すようにすることもできます (動的割り当てが適切でない組み込みシステムの単純なコマンド パーサーに対してこれを行います)。

返された配列を少しずつ割り当てる例を次に示します。

static
char** myFunc_realloc( char** arr, size_t* elements)
{
    enum {
        allocation_chunk = 16
    };

    *elements += allocation_chunk;
    char** tmp = (char**) realloc( arr, (*elements) * sizeof(char*));

    if (!tmp) {
        abort();  // or whatever error handling
    }

    return tmp;
}

void myFunc_free( char** argv)
{
    free(argv);
}

int myFunc(char* inputStr, int *argCTemp, char** argVTemp[])
{
    size_t argv_elements = 0;
    size_t argv_used = 0;
    char** argv_arr = NULL;


    char* token = strtok( inputStr, " ");

    while (token) {
        if ((argv_used+1) >= argv_elements) {
            // we need to realloc - the +1 is because we want an extra 
            //  element for the NULL sentinel
            argv_arr = myFunc_realloc( argv_arr, &argv_elements);
        }

        argv_arr[argv_used] = token;
        ++argv_used;

        token = strtok( NULL, " ");
    }

    if ((argv_used+1) >= argv_elements) {
        argv_arr = myFunc_realloc( argv_arr, &argv_elements);
    }
    argv_arr[argv_used] = NULL;

    *argCTemp = argv_used;
    *argVTemp = argv_arr;

    return argv_used;
}

いくつかのメモ:

  • 割り当てが失敗すると、プログラムは終了します。別のエラー処理が必要になる場合があります。
  • 渡された入力文字列が「破損」しています。これは、関数の適切なインターフェイスではない可能性があります (一般に、このような関数は入力データを破棄しないことをお勧めします)。
  • 関数のユーザーはmyFunc_free()、返された配列の割り当てを解除するために呼び出す必要があります。現在、これは の単純なラッパーですfree()が、これにより、より高度なことを行う柔軟性が得られます (入力文字列を破棄する必要がないように、トークンにメモリを割り当てるなど)。
于 2012-03-19T15:19:20.073 に答える
0

初期化されていないポインターを関数に送信します (呼び出しも正しくありません。 & は必要ありません)。このポインターはランダムな場所を指しているため、ガベージが発生し、セグメンテーション違反も発生する可能性があります。

2つのうちの1つを行うことができます。

たとえば、静的にすることができる十分な大きさの配列を割り当てます

static char * arr[MAX SIZE]関数呼び出しで送信する(char **)&arrか、2 回実行して malloc を使用します。

また、最大サイズを渡すか、定数を使用して渡さないようにする必要があります。


int n次に、トークンの数を考えてみましょう

char * arr[] = malloc(sizeof(int *)*n);

これにより、ポインターの配列が作成されます。呼び出して、populate 関数に渡します。

(char **)&arr、コードで行ったように使用します

たとえば(*argVTemp)[0] = ;

(配列が不要になった場合は、free(arr) を呼び出して解放することを忘れないでください)

于 2012-03-19T05:29:28.477 に答える