2016-09-25 10 views
3

私はおもちゃのbashシェルを書いています。今私の目標は、特定のコマンドが見つかるパスを探す環境を循環させることです。今私はパスを区切っています(例えば、 "/home/user/bin:home/user/.local/bin:/usr/local/sbin"など)を ":"で区切ります。新しい文字列finalPathのパスに移動し、最後に "/ cmd"を連結します。strtok()は元の文字列を上書きします

私の問題は、パスの内容をfinalPathにコピーしようとすると、私がfinalPathに行った変更がパスに反映されることです。コードが今すぐになると、pathは "home/user/bin"に1回だけ設定され、サイクルスルーして再び同じものに設定され、トークナイザは "NULL"をヒットしてwhileループを終了します。

これは、pathfinalPathがメモリアドレスを共有していることを示していますが、理論的にはstrcpyが新しいコピーをメモリに作成するため、文字列とポインタで間違っている必要があります。

この予期しない動作の原因は何ですか?

編集:このコードは、私はstrcpyの

をコメントアウトするときに私のコードの機能縮小版は以下の通りです期待と同じように実行します。

int findpath(char* cmd, command_t* p_cmd) { 
    char* path_var; 

    path_var = getenv("PATH"); 

    char* path; 
    char tempEnv[sizeof(path_var)]; 
    strcpy(tempEnv, path_var); 
    path = strtok(tempEnv, ":"); 

    while(path != NULL) { 
     char fullPath[1000]; 
     strcpy(finalPath, path); 
     printf("path: %s\n", path); 
     printf("finalPath: %s\n", finalPath); 
     path = strtok(NULL, ":"); 
    } 
+3

はい、 'strtok'は実際にソース文字列を変更します。それは記録された賞賛です。 – alain

+3

'sizeof(path_var)'は 'path_var'の長さではありません。これはポインタサイズです。 – BLUEPIXY

+0

ソース文字列を変更するStrtokはうまくいきます、それはstrcpyです。私は混乱しています。編集:いくつかの明確化は、私がstrcpyをコメントアウトするときにこのコードがちょうどうまくいくということです。 – teleTele

答えて

3

BLUEPIXYは右である:tempEnvは十分な大きさではありませんあなたの弦のために。試してみてください:これは穴だらけであることを条件とする

char *tempEnv; 
tempEnv = malloc(strlen(path_var)+1); 
strcpy(tempEnv, path_var); 

と終わりに

free(tempEnv); 

を。 hereのように、より安全な文字列関数を使用する必要があります。たとえば、path_varの長さに適度な制限を設定するには、strnlenを使用します。その制限内でpath_varがNULL終端されていることを確認してください。 strcpyの代わりにstrncpyを使用してください。必要に応じてstrncpyの後ろにNULLを追加してください。あなたの目標が本番のコードではなく学習しているように見えるので、私はここには含まれていません。ハッピーハッキング!

+0

' path_var'はnullで終了しないかもしれないと思いますか?プログラムはどのように伝えることができますか?私は遠隔からの説得力がないことを知りません。 'getenv()'の出力はヌルで終了する文字列です。 'strncpy()'を使うのは混在しているので、ソースがターゲットよりも長い場合はnull終了を保証せず、ソースがターゲットよりも短い場合はヌルパディングを保証します。 「奇妙な機能です。安全上の懸念のための普遍的な答えではありません(あなたが慎重であれば安全に使用できます)。 –

+1

'char tempEnv [strlen(path_var)+1];'も細かいです。 –

+0

@JonathanLeffler明確にするために編集しました。私が得ようとしたのは、 '* c 'がプログラムの制御下にないとき、' while(* C++)i ++; 'は悪い考えです。いずれにせよ、私はこの答えが安全な弦の習慣に関して不完全であることに同意します---私は私より多くの経験を持つ人々にそれを残します。 :) – cxw

関連する問題