2017-01-07 5 views
-3

私は標準入力からコマンドラインを読み込んで、それをトークンに解析するはずの関数に渡すプログラムを書いた。なぜ私の解析関数がすべての予想されるトークンを返すのですか?

これは、解析関数である:これは私が私のプログラムへの供給入力の一例である

int main() { 
    int status; 
    pid_t pid; 
    pid = fork(); 

    while(1) {  
     if(pid < 0) { 
      status = -1; 
      perror("Fork"); 
     } else if(pid == 0) { 
      char* cmd; 
      printf("$"); 
      if(fgets(cmd, sizeof cmd, stdin) == NULL) break; 
      parse_cmdline(cmd); 
     } else { 
      if(waitpid(pid, &status, 0) != pid) { 
       status = -1; 
      } 
      break; 
     } 
    } 


    return 0; 
} 

char** parse_cmdline(char* cmdline) { 
    char ** arr = malloc(10 * sizeof(char*)); 
    for (int i =0 ; i < 10; ++i) 
     arr[i] = malloc(30 * sizeof(char)); 
    char * token = strtok(cmdline, " "); 
    int i = 0; 
    while(token != NULL) { 
     if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*)); 
     arr[i] = token; 
     token = strtok(NULL, " "); 
     i++; 
    } 
    printf("flag1"); 
    return arr; 
} 

そして、これは私がそれをmain()を、それを使用しています方法です

ls l a 

予想される出力は、

です。
l 

(つまり、私の解析機能により、印刷された第2引数である)

そして文字通り何も起こりません。 printf( "flag1")さえありません。印刷します。しかし、char ** commandsを削除してprintf("%s", commands[0]);をparse_cmdline関数に入れると、返り値を代入しない以外はすべて動作します。なぜ、どのようにそれを修正するには?コマンドの

#include <stddef.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 

char** parse_cmdline(char* cmdline) { 
    char ** arr = malloc(10 * sizeof(char*)); 
    for (int i =0 ; i < 10; ++i) 
     arr[i] = malloc(30 * sizeof(char)); 
    char * token = strtok(cmdline, " "); 
    int i = 0; 
    while(token != NULL) { 
     if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*)); 
     arr[i] = token; 
     token = strtok(NULL, " "); 
     i++; 
    } 
    printf("%s\n", arr[1]); 
    return arr; 
} 
+0

最小限の完全で検証可能な例を投稿してください。 – EOF

+0

さらに何が必要ですか? –

+0

何かをファイルに貼り付けてコンパイルすることができます。また、コンパイルの結果をパイプで入力することもできます。おそらく出力私はプログラムの実行の出力を比較することができます。 – EOF

答えて

1

この部分は奇妙に見える - コメントをインライン参照:

char ** arr = malloc(10 * sizeof(char*)); 
for (int i =0 ; i < 10; ++i) 
    arr[i] = malloc(30 * sizeof(char));  // Here you allocate memory 
              // for holding a part of the command 

char * token = strtok(cmdline, " "); 
int i = 0; 
while(token != NULL) { 
    if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*)); 

    arr[i] = token;    // But here you overwrite the pointer value and 
           // and thereby create a memory leak 

    token = strtok(NULL, " "); 
    i++; 
} 

はおそらく、あなたの代わりに、文字列のコピーをやってみたかった - などを:

strcpy(arr[i], token); // Instead of arr[i] = token; 

さらにこの行は奇妙なよう:

if(i > 9) arr = realloc(arr, (i+10)*sizeof(char*)); 

あなたはを増やすことができるようにarrを増やしますが、このtあなたは最初にやったように新しい文字列のためのメモリを割り当てません。

0

まず、あなたが割り当てされていません部屋:要求されたよう


は、ここに私のコードの全体です。

char cmd[100]; 

は、メモリが(fgets修正の適切な使用と同様)未定義の動作を引き起こし、この割り当てない:このような何かにcmdの宣言を変更します。あなたのループの繰り返し処理は、入力されたデータの上に、彼らが十分でなかった場合、その後、あなたが不完全なコマンドラインを解析しようとしているので

if (strstr(cmd, "\n") == NULL) { 
    /* the user typed more than 100 characters */ 
} 

と、次の時間:100の文字が十分でなかった場合しかし、あなたはまた、fgets()からチェックする必要がありますより多くの不完全なコマンドを解析します。

:あなたは、ループ内 strtokからポインタでそれらを置き換えるため

最後に、strtok返しcmdのトークンへのポインタなので、すべてのこれらの文字列は、あなたは、あなたのparse関数の先頭でメモリリークして割り当てられました

arr[i] = token; /* this throws away the address of the 10-character array you allocated * at the beginning of the function. You can't free() that memory * anymore. Your program is "leaking" memory. */ 

厳密に言えば、reallocが有効なアドレス、つまりNULLを返すかどうかを厳密にチェックする必要があります。 mallocもあります。このような小さなプログラムでは、これで問題が生じることはほとんどありませんが、正しい方法です。

構文解析済みのコマンドは、使用した後に処分する必要があります。 mallocreallocの両方のポインタ配列を割り当てますが、あなたのプログラムではfreeは決してありません。プログラムが実行されている間にすぐにプログラムが終了しても、それはメモリリークです。 (やはり、小さなプログラムでは問題が発生することはありませんが、それは良い方法です。)

関連する問題