2012-02-07 10 views
0

次のコードは奇妙な動作を示しています。改行を押すと入力を与えながらヒストグラム値を出力します。それ以外の場合は直接EOF(^ Z)を入力すると、すべてゼロが表示されます。 getline()関数に問題があります。改行が押されたときにだけ入力を受け取ります。getchar()の動作はこのプログラムに対して正しいですか?

#include <stdio.h> 
#define IN 1 /* inside a word */ 
#define OUT 0 /* outside a word */ 
#define MAXLEN 50 
/* count lines, words, and characters in input */ 
main() 
{ 
    int c, i, j, nc, state; 
    int wordlength[MAXLEN]; 
    state = OUT; 
    nc = 0; 
    for (i = 0; i < MAXLEN; i++) 
     wordlength[i] = 0; 
    while ((c = getchar()) != EOF) { 
     if (c == ' ' || c == '\n' || c == '\t') { 
      if (state == IN) { 
       wordlength[nc-1]++; 
      } 
      state = OUT; 

     } 
     else if (state == OUT) { 
      //putchar('\n'); 
      state = IN; 
      nc = 0; 
     } 
     if (state == IN) { 
      ++nc; 
     } 
    } 

    for (j = 0; j < MAXLEN; j++) 
      printf("\n%d - %d",j,wordlength[j]); 

    for (i = 10; i >= 0; i--) { 
     for (j = 0; j < MAXLEN; j++) 
      printf(((wordlength[j] > i)?"|":" ")); 
     printf("\n"); 

    } 

} 
+4

C99(旧C標準、現在の標準はC2011)の必要に応じてCを書く方法を学び、 'main()'関数に明示的な戻り値の型を指定してください。引数リストを無視するときは 'int main(void)'を、コマンドライン引数を処理するときは 'int main(int argc、char ** argv)'を強くお勧めします。 –

+0

残念ながら、stdinは通常はラインバッファーですので、入力したキーボード入力があればEnterキーを押す必要があります。あなたはそれをunbufferedにするか、それをしないようにすることができます。 –

+0

@Jonathanは助言に感謝します。私は本を​​読んで、読書のポイントまでしか情報を使っていない解決策を書こうとしています。 – bubble

答えて

1

私は私のマシン上のEOF(はControl-Dを示す前に、任意のホワイトスペース(空白、タブ、改行)が続いていない入力の単一の単語を入力しない限り、あなたのコードは私のために多かれ少なかれsanely動作します。 Control-Zを使用すると、Windowsで実行されていることが示唆されます)。最終的な空白なしでEOFを指定すると、最後の単語はヒストグラムに追加されません。もちろん、単語の長さが大きすぎないようにして、wordlength配列(同じサイズのすべての非常に長い単語を数えるためにif (nc > MAXSIZE) nc = MAXSIZE;)の外側にインデックスを作成しないようにする必要があります。

メイン処理ループの後に、があるかどうかを確認し、そうであればwordlengthの該当するエントリを増分する必要があります。

isspace()<ctype.h>からも使用することを検討してください。

可能な限り#defineの代わりにenumを使用して、シンボルがデバッガで使用できるようにします。あなたは慎重に1つのよくある間違いを避けました。変数ccharではなくintにしました。

#include <stdio.h> 

enum { IN = 1, OUT = 0 }; /* inside, outside a word */ 
enum { MAXLEN = 50 }; 

/* count lines, words, and characters in input */ 
int main(void) 
{ 
    int c, i, j, nc, state; 
    int wordlength[MAXLEN]; 
    state = OUT; 
    nc = 0; 

    for (i = 0; i < MAXLEN; i++) 
     wordlength[i] = 0; 

    while ((c = getchar()) != EOF) 
    { 
     if (c == ' ' || c == '\n' || c == '\t') 
     { 
      if (state == IN) 
      { 
       if (nc > MAXLEN) 
        nc = MAXLEN; /* All long words grouped together */ 
       wordlength[nc-1]++; 
      } 
      state = OUT; 
     } 
     else if (state == OUT) 
     { 
      state = IN; 
      nc = 0; 
     } 
     if (state == IN) 
      ++nc; 
    } 

    if (nc > 0) 
    { 
     if (nc > MAXLEN) 
      nc = MAXLEN; /* All long words grouped together */ 
     wordlength[nc-1]++; 
    } 

    for (j = 0; j < MAXLEN; j++) 
     printf("\n%d - %d", j, wordlength[j]); 

    for (i = 10; i >= 0; i--) 
    { 
     for (j = 0; j < MAXLEN; j++) 
      putchar((wordlength[j] > i) ? '|' : ' '); 
     printf("\n"); 
    } 
    return 0; 
} 

あなたはあなたのマシンに問題があると言いました。私はシステム内のバグを発見したと主張することに非常に慎重で、特にgetchar()のような明白な呼び出しでは慎重です。私はその可能性を排除することはできませんが、それは私が非難していると思う最後のことです。 getchar()にバグがあると思う前に、私が間違ってやったことを解決するために多くの時間を費やしていました。


コメントには、自分の環境でプログラムが動作していない理由がわかります。プログラムを実行しているプラ​​ットフォーム/環境を正式には特定していないので、これは不可能です。

しかし私はあなたの元のas-postedプログラムがUnixライクな環境でうまく動作することを実証しました(私はMacOS X 10.7.2でテストしていますが、他の同様のUnix系システム)。改訂版は少し上手く機能します。たとえスペースや改行が続いていなくても、最後に入力した単語を数えます。

あなたが推測しているように、Windowsで作業している場合、端末I/Oモデルは異なる場合があります。特に、Cの標準では、EOFの前にテキストファイル(たぶん端末入力を含む)を改行で終わらせなければならないことが要求されています。最後の改行後の文字はすべて破棄される可能性がありますが、それはプラットフォームに依存します。バイナリファイルの動作は異なります。最後の改行の後のデータであれば、報告している動作と一致します。未確認のシステムのドキュメントを参照すると、予想通りの動作になる可能性があります。これは、P J Plaugerが彼の優れた(しかし幾分かの日付)「The Standard C Library」で特定した実装の違いの1つです。

しかし、私が仮定していることが正しいとすれば、あなたのコードが正しい(十分な)ことを明確にしたいと思います。問題は単にあなたの期待がシステムの文書化された動作と一致しないことです。あなたが作業しているプラ​​ットフォームの報告は時には重要であることに注意してください。あなたがエッジの場合に侵入すると、それはより重要になる傾向があります。また、getchar()のバグにヒットしたことはほとんどありません。

ちなみに、私がテストしていたときに、Control-Dを2回入力する必要がありました(それは私がやらなければならないことでした)。最初に、私が行に入力した文字(abc)をプログラムに3バイトの読み込みとしてフラッシュしました。 2番目の文字は、0バイトの読み込みとしてプログラムに入力した文字(すべて0)をフラッシュして、getchar()でEOFと解釈しました。私もabc(最後は空欄)とEOFでテストしました。あなたのコードは空白なしでabcを数えませんでした。空白が続いたときにabcを数えました。

+0

あなたの答えは、このプログラムの予想どおりの動作を説明しています。私はどんな言葉も入力しないように注意してきました。> MAXLEN。 enumやその他の条件のような代替案を提案してくれてありがとう。このプログラムを書いているのは、Cを学ぶことでした。なぜこのプログラム\ mが仕事をするための別の方法を示唆するのではなく、なぜ動作しないのかを伝えれば、はるかに義務づけられます。 – bubble

関連する問題