1

Unixコマンドラインを介して特定のファイルの行をカウントするユーティリティを書いています。通常、これは私にとっては非常に単純ですが、どうやら私は主要なオフナイトを過ごしています。このプログラムの目的は、コマンドラインから不明な数のファイルを取り込み、それらをバッファーに読み込んで、改行文字を確認することです。簡単に聞こえますか?

int size= 4096;

int main(int argc, char *argv[]){
  int fd, i, j, c, fileLines, totalLines;
  char *buf= (char *)malloc(size); //read buffer

  for (i=2; i<argc; i++){ //get first file

    fileLines=1;    

    if ((fd=open(argv[i], O_RDONLY))!= -1){ //open, read, print file count, close
        while ((c= read(fd, buf, size))!= 0){

            for (j=0; j<size; j++){
                if (buf[j] == '\n')
                    fileLines++;
            }
        }

    }
    printf("%s had %d lines of text\n", argv[i], fileLines);
    totalLines+= fileLines;
    close(fd);

  }

  printf("%d lines were counted overall\n", totalLines);    
  return 0;
}

私には2つの問題があります。1つ目は、最初のprintfステートメントがデバッガーの外部で実行されることはないということです。2つ目は、totalLinesの印刷出力は約175K行である必要がありますが、印刷される値は約767倍大きくなります。

関連するすべての変数が変更の範囲外であると宣言されているため、これを理解するのに問題がありますが、それでも、最初の印刷状態と行カウンターの更新が、異常なtotalLinesとともにデバッガーの外部で無視される理由を説明していません結果

どんな助けでも大歓迎です。

答え

2つの変更が提案されました。
1つ目はに変更j<sizeすることでしたj<c。これは必要なソリューションではありませんでしたが、適切なコーディング規約に従っています

2つ目はに変更i=2することでしたi=1。元の開始変数を使用した理由は、デバッガー実行可能ファイルを開始した方法でした。gdbコマンドラインでrun lc1 f1.txt、デバッガーを起動するために入力しました。その結果、arglistには3つの変数がありrun f1.txt、教授が最初の例を使用してgdbを紹介してくれたので、それが完全に適切かどうかはわかりませんでした。

4

6 に答える 6

3

初期化していませんtotalLines。ループ内でインクリメントしますが、最初に宣言するときに 0 に設定しません。

また、なぜから始めるのi=2ですか?これは 3 番目のコマンド ライン引数であり、プログラムの 2 番目のパラメーターです。これはあなたが意図したものですか、それともプログラムの最初のパラメーターから始めたかったのですか?

そして、他の人が指摘したように、j < c代わりにj < size.

于 2011-05-05T02:03:48.127 に答える
2

あなたのループは間違っています。する必要がありますj=0; j<c; j++。それはおそらくあなたが見ているエラーの直接の原因ではありませんが、間違いなく問題を引き起こします。

デバッガーを使用してコードをステップ実行してみましたか?

于 2011-05-05T02:01:35.943 に答える
1

検討:./program file.txt

argv[0] is "program"
argv[1] is "file.txt"

これは、forループが間違ったインデックスから開始することを意味し、cmd行を介して1つのファイルのみを渡す場合、コードはそのループに入ることはありません。インデックス1から開始する必要があります。

for (i=1; i<argc; i++){

あなたがそれらを宣言するとき、あなた自身に賛成して、すべての変数を初期化してください。これらのメモリ位置にゴミがないことを確認する唯一の方法です。

于 2011-05-05T02:07:28.547 に答える
1

まず、すばらしい質問です。:)必要なすべてのコードは、よく述べられており、作業が完了したことは明らかです。:)

デバッガーでプログラムをどのように開始しますか?argv[2]出発点はに到達しないことに関連しているかもしれないと思いますprintf()が、それはあなたがどのように始めているかに依存します。詳細は以下をご覧ください。

いくつかのコメント:

int size= 4096;

通常、この種のマジックナンバーにはCプリプロセッサマクロが使用されます。私はあなたの先生がおそらくプリプロセッサを決して使わないと言ったことを知っています、しかし慣用的なCは読むでしょう:

#define SIZE 4096
for (i=2; i<argc; i++){ //get first file

Try-はプログラムの名前であり、最初のコマンドライン引数になりますi=1-おそらく誰かがあなたを介してそれを呼び出した場合、ファイルの行数を数えたいと思います。:)(また、ループを終了させたいです。:)もちろん、の代わりを書き込もうとしている場合、ループは問題ありませんが、誰かが引数を台無しにした場合はあまり役に立ちません。それは後でプロジェクトとして安全に保管することができます。(今興味がある場合は、マンページを読んでください。:)argv[0]argv[1]./wc foofoowc -lgetopt(3)

    if ((fd=open(argv[i], O_RDONLY))!= -1){
        while ((c= read(fd, buf, size))!= 0){

            for (j=0; j<size; j++){

ループを-で終了しますが、最後のブロックの文字j<sizeのみを読み込みます。cあなたは最後のブロックで残ったゴミを読んでいます。/proc/(カーネルプログラマーの便宜のために短い読み取りを返す可能性のある生成されたファイルが含まれていても驚かないでしょう。)

                if (buf[j] == '\n')
                    fileLines++;
            }
        }

    }
    printf("%s had %d lines of text\n", argv[i], fileLines);
    totalLines+= fileLines;

に割り当てたのはこれが初めてですtotalLines。:)ガベージの初期値がありがちです。

    close(fd);

おそらく、close(fd);呼び出しをif((fd=open()))ブロックに移動する必要があります。開くことが失敗した場合、これはを呼び出しますclose(-1);。大したことではありませんが、close(2)エラーリターンをチェックしている場合(常に良い習慣です)、不必要なエラーが返されます。

  }

お役に立てれば!

于 2011-05-05T02:08:25.130 に答える
0

あなたはおそらくwcを知っているでしょうが、念のためにそれについて言及します。

特定の問題を直接デバッグするのに役立たないことはわかっていますが、ソースコードを一瞥したり、プログラムが機能していることを確認するために使用したりすることもできます。

于 2011-05-05T02:01:28.003 に答える
0

for() ループに論理エラーがあります。「読み取りまで」の代わりに「バイト読み取り」を使用する必要があります。コードで意味するのは、for() で「サイズ」の代わりに「c」を使用することです。

于 2011-05-05T02:01:50.950 に答える