2009-05-17 9 views
2

私はシステムコールを使って基本的なbashをしようとしていますが、私はポインタ配列に少し問題があります。Cでこの配列ポインタをクリアするにはどうすればよいですか?

私のコードを再開するには、stdinからread()を使ってバッファにコマンドを読み込んだ後、strsep()を使って引数とすべての引数を配列に分けます。次に、fork()で新しいプロセスを作成し、execvp()で関連する引数でそのコマンドを実行します。

これは、ユーザーが「quit」(まだコード化されていない)と入力するまで無限ループになります。問題は、最初の反復の後に、次のコマンドと引数のために* pArgsが空である必要があることです。

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

int main(int argc, char **argv) { 
    char bBuffer[BUFSIZ], *pArgs[10], *aPtr = NULL, *sPtr; 
    int aCount; 
    pid_t pid; 

    while(1) { 
     write(1, "\e[1;31mmyBash \e[1;32m# \e[0m", 27); 
     read(0, bBuffer, BUFSIZ); 

     sPtr = bBuffer; 
     aCount = 0; 

     do { 
      aPtr = strsep(&sPtr, " "); 
      pArgs[aCount++] = aPtr; 
     } while(aPtr); 

     pArgs[aCount-2][strlen(pArgs[aCount-2])-1] = '\0'; 

     // Debug code to output pArgs content 
     write(1, "|>", 2); 
     write(1, pArgs[0], strlen(pArgs[0])); 
     write(1, "<|", 2); 

     if(strlen(pArgs[0]) > 1) { 
      pid = fork(); 

      if(pid == -1) { 
       perror("fork"); 
       exit(1); 
      } 

      if(pid == 0) { 
       execvp(pArgs[0], pArgs); 
       exit(0); 
      } 
     } 
    } 

    return 0; 
} 

P.S::申し訳ありませんが、私は、現時点では、入力と出力のテストケースを提供することができないと私は

は、ここに私のコードです...どのように行うのか分かりません。うまくいけば、これはあなたがそれを必要としないことを理解し、修正することは難しいことではありません。それはしかし必要なのかどうかは

ちょうど物事をクリアするために...後でそれを投稿します:
私は、配列をクリアする方法を尋ねたと私はそのための答えを得た知っています。しかし、今私の問題はそうではなく、バッファが収集していたごみがlitbによって指摘されていることは明らかです。ヌル文字で文字列を終了する方が、配列をクリアするよりも意味があります。だから私はlitbの答えを正しいものとしてマークしている。

答えて

2

問題は、データの読み取り後にヌル文字を追加しないことです。したがって、strsepコールはどこで停止するか分かりません。 Cでは、文字列はヌル文字で終了する必要があります(これは終端ヌル文字と呼ばれます)。代わりにそれと

// don't forget to add error handling at some point (s == -1) 
ssize_t s = read(0, bBuffer, BUFSIZ-1); 
bBuffer[s] = '\0'; 

execvpは、最初のnullポインタまでの引数を読みますから、私は、今、クリアすべきか、配列表示されません。ただし、doループでは、ヌルポインタがすでに追加されています。最後の呼び出しで戻されたNULLポインタはstrsepです。

もちろん、bBuffer(最初のコマンドをスキャンした後に*pArgsが指しているデータ)をクリアするだけでも、問題は解決されます。 bBuffer配列内の文字は、任意の感知可能な値に初期化されていると仮定することはできませんので、最初にスキャンする前に行う必要があることに注意してください。ただread呼び出しの前に(終端のNULL文字があまりにもスペースを持っている必要がありますので、しかし、どのような場合には、唯一の最大限BUFSIZE-1を読んで!)

memset(bBuffer, 0, sizeof bBuffer); 

場所。

しかし、上記のように、このmemset呼び出しは必要ありません。終端ヌル文字を手動で追加するだけです。

+0

私の答えが下落した理由を理解できません。明らかに、彼の問題はクリアされないことによって生成されませんポインタの配列ですが、他の場所に問題がありますので、配列をクリアする正しい方法を表示するだけで良いですが、バグを修正する方法を確実に示すことは少なくとも同じくらい重要です! –

+0

彼の "無限ループ"は意図的ですあなたは質問を間違って読んでいますが、私はそれが重要な情報であるので、これをアップウィートしています。 – rlbond

+0

無限ループを壊すつもりはありませんでした。読んで、BUFSIZが255だとしましょう。 "エコーハロー"。 fferには[echo helloblahblusomerandomdata .......]が含まれています。 strsepはどのように健全に動作するはずですか?ポインタ配列をクリアするだけでは行えません。彼が本当に望んだのは、bBuffer配列をクリアすることです。しかし、それは私が答えで言ったように必要ではありません –

7
int i; 
for (i = 0; i < 10; i++) 
    pArgs[i] = NULL; 
+0

memset()よりも優れています! –

+2

私はmemset()で答えた後、sizeof(pArgs)がこの場合OKである理由を説明するのが難しいので答えを削除しましたが、別のケースではOKではないかもしれません(pArgsの型がchar **の場合) 。 +1は 'for'ループに、-1はmemsetに対してこのコンテキストで。 – RichieHindle

+0

あなたはそれを残しておくべきです。 Memsetはまだ適切であり、スピードが問題であるときに行く良い方法です。 (http://www.cppreference.com/wiki/c/string/memsetを参照してください)まともなコンパイラはおそらくmemsetにループのためにおそらくこれを最適化するだろうtho – rpetrich

関連する問題