2009-09-02 42 views
0

文字列をchdir()に渡そうとしています。しかし、私はいつもいくつかの末尾のものがchdir()を失敗させるように思えます。Cでの文字列解析

#define IN_LEN 128 

int main(int argc, char** argv) { 

    int counter; 
    char command[IN_LEN]; 
    char** tokens = (char**) malloc(sizeof(char)*IN_LEN); 
    size_t path_len; char path[IN_LEN]; 

     ... 

    fgets(command, IN_LEN, stdin) 
    counter = 0; 
    tmp = strtok(command, delim); 
    while(tmp != NULL) { 
     *(tokens+counter) = tmp; 
     tmp = strtok(NULL, delim); 
     counter++; 
    } 

    if(strncmp(*tokens, cd_command, strlen(cd_command)) == 0) { 
     path_len = strlen(*(tokens+1)); 
     strncpy(path, *(tokens+1), path_len-1); 
    // this is where I try to remove the trailing junk... 
    // but it doesn't work on a second system 
     if(chdir(path) < 0) { 
      error_string = strerror(errno); 
      fprintf(stderr, "path: %s\n%s\n", path, error_string); 
} 

// just to check if the chdir worked 
char buffer[1000]; 
    printf("%s\n", getcwd(buffer, 1000)); 

    } 

    return 0; 
} 

これを行うには、より良い方法が必要です。助けてもらえますか? I'vrはscanfを使用しようとしましたが、プログラムがscanfを呼び出すときにハングします。あなたはstrncpyをを呼び出した後にパス文字列にnullを「\ 0」を追加することを忘れてしまったように見えます

おかげ

答えて

5

()。ヌルターミネータなしでは、chdir()は文字列の終わりを知らず、見つかるまで探し続けます。これにより、パスの最後に余分な文字が表示されるようになります。

+0

ああはい。どのような愚かな間違い。ありがとうございます。私はかなりイライラしていた。 – devin

+0

毎回ニッケルがあったら、愚かなプログラミングミスをしました... –

3

あなたの例では、少なくとも2つの問題があります。

strncpy()を使用するのは最初のもので、コピーするバッファの最後に '\ 0'ターミネータを付ける必要はありません。あなたのケースでは、strncpy()を使用する必要はありません(これは私が遭遇した正確な理由のために危険であると考えています)。あなたのトークンはstrtok()で終わる '\ 0'になり、トークンはパスバッファーと同じサイズのバッファーから来るので、パスバッファーより小さくなることが保証されます。ちょうどstrcpy()を使用してください。あるいは、コードが後で来て、バッファサイズに悩まされている人の回復力になるようにするには、非標準のstrlcpy()のようなものを使用してください。

大まかにはstrncpy()を使用しないでください。

コードのもう1つの問題は、tokens割り当てが正しくないことです。

char** tokens = (char**) malloc(sizeof(char)*IN_LEN); 

は、入力文字列バッファーと同じ大きさの領域を割り当てますが、charではなくその割り当て内の文字列へのポインタを格納しています。あなたは文字よりも少ないトークンを(定義によって)持っていますが、各トークンポインタはおそらく文字の4倍です(プラットフォームのポインタサイズに依存します)。文字列に十分なトークンがある場合は、このバッファーをオーバーランさせます。

例えば、IN_LENが14で、入力文字列が "a b c d e f g"であるとします。区切り文字としてスペースを使用すると、7つのトークンがあり、28バイトのポインター配列が必要になります。かなり多くは、malloc()コールによって割り当てられた14以上。

簡単な変更:

char** tokens = (char**) malloc((sizeof(char*) * IN_LEN)/2); 

は十分なスペースを割り当てる必要があります(?そこにoff-by-oneエラーがあるかもしれ+1が必要です)。

3つ目の問題は、アレイにゼロまたは唯一のトークンが追加されていても、*tokensおよび*(tokens+1)にアクセスする可能性があることです。これらのポインタを逆参照する前に、counter変数のチェックをいくつか追加する必要があります。