1

だからここに私に問題を与えている私のコードのビットがあります:

void childProcessHandler(string command){


int argCounter = 0;
for(int i=0; i!=command.size(); i++)
    argCounter+=( command.at(i) == ' ');

char * temp, *token;
char *childArgs[argCounter];

argCounter = 1;

temp = new char [command.size()+1];
strcpy (temp, command.c_str());

token = strtok (temp," ");
childArgs[0] = token;

while (token!=NULL)
{
    token = strtok(NULL," ");
    childArgs[argCounter] = token;
    argCounter++;
}
    
//delete[] temp; //Should remove token as well?

execvp(childArgs[0], childArgs);

cout<<"PROBLEM!"<<endl;
exit(-1);

}

main() メソッドで、私のコードは forks() (親プロセスは子が終了するのを待機する) のポイントに到達し、子プロセス (プロセス ID == 0 はい?) は、ユーザーでメソッド childProcessHandler を呼び出します。入力 (実行するコマンド + 引数) を引数として使用します。次に、ユーザー入力をトークン化し、execvp を呼び出します。

すべてがコンパイルされ、実行されます。execvp はエラーが発生した場合にのみ戻るため、execvp の後の行には到達しません。

プロジェクトはUNIX端末をシミュレートすることですが、コマンド「日付」を指定すると、何も出力されません...子が終了し、親プロセスは正常に再開しますが、端末ウィンドウには何も送信されません...

私は何を間違っていますか?

(また、strtokを使用してトークン化することを「推奨」されましたが、もっと簡単なものがあれば、私は意見を受け入れます。)

ありがとう!

編集

たとえば、「date」の代わりに「date」と入力すると、上記のコードが機能します。childArgs[]配列の最後にnull文字を入れない「トークナイザー」には、何か怪しいものがあるのではないかと思います。私はそれで遊んでみます。素早い回答に感謝します!

(Ninja編集、delete[] tempも一応コメントアウト)

4

2 に答える 2

2

std::string と char/char* を混在させています。結構ですが、注意が必要です。これらは動作が異なります。

特にこの行:

temp = new char [command.size()+1];

文字列を保持する実際の配列を作成しています。

token = strtok (temp," ");

これにより、トークン (単なるポインター) が temp 内の場所を指すようになります。strtok() は、入力文字列を変更して、文字列内に一時的な文字列を作成します (クレイジーに聞こえますが、わかります)。

strtok() が提供する文字列を永続的なホームにコピーする必要があります。std::string を使用して時間とコードを節約するか、char* の方法で新しい文字列を自分で割り当てます。たとえば、次の代わりに:

childArgs[0] = token;

必要なもの:

   childArgs[0] = new char[strlen(token)+1];
   strcpy(childArgs[0], token);

コマンド引数のループ中に配列に格納されたトークンにも同じことが当てはまります。

于 2011-09-29T20:25:58.977 に答える
1

ポインタの childargs ベクトルは、メモリ「temp」のブロックに割り当てられたバイトを指します。temp を解放すると、childargs ポインタが指すメモリが削除され、ベクトル内の値の一部が破損する可能性があります。

childargs ポインタが指すメモリの解放を停止するには、delete[] の呼び出しを削除します。メモリをリークすることはありません。exec_ () を呼び出すと、プロセス イメージ全体が置き換えられます。exec _() (ほとんどの場合)への呼び出しを生き残る唯一のものは、ファイル記述子です。

テストとして、もう少し単純なことを試してみてください。子で fork() を呼び出した後、「date」へのパスを指定して exec を呼び出すだけです。パラメータリストベクトルをいじる前に、それを機能させてください。

別のテストとして、exec への呼び出しを削除し、ポインターのベクトル全体を出力して、トークン化が想定どおりに機能していることを確認します。ベクトルの終わりがどこにあるかを知るために、最終エントリは NULL でなければならないことに注意してください。

于 2011-09-29T20:42:06.027 に答える