0

次のコードは、奇妙な動作を示しています。改行を押すと入力を入力している間、ヒストグラム値を出力するだけです。それ以外の場合、EOF(^ Z)を直接入力すると、すべてゼロが表示されます。改行が押されたときにのみ入力を受け取る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

1 に答える 1

1

あなたのコードは、EOFを示す前に空白(空白、タブ、改行)が続かない入力の単語を1つ入力しない限り、多かれ少なかれ正常に機能します(Control-D私のマシンでは、を使用するControl-Zと、Windowsで実行されていることが示唆されます) . 最後の空白なしで EOF を指定すると、最後の単語はヒストグラムに追加されません。wordlengthもちろん、配列の外側にインデックスを付けないように、単語の長さが大きすぎないことも確認する必要があります(if (nc > MAXSIZE) nc = MAXSIZE;すべての非常に長い単語を同じサイズとしてカウントするため)。

メインの処理ループの後、nc > 0の適切なエントリをインクリメントするかどうかを確認する必要がありますwordlength

isspace()fromの使用も検討してください<ctype.h>

デバッガーでシンボルを使用できるように、可能な限りenum代わりに使用します。#define1 つのよくある間違いを慎重に回避しました。変数cintではなく にしましたchar

#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()ます。


コメントでは、あなたのプログラムがあなたの環境で動かない理由を教えてほしいとお願いしています。プログラムを実行しているプラ​​ットフォーム/環境を(まだ)正式に特定していないため、これは不可能です。

ただし、投稿された元のプログラムが Unix ライクな環境でかなり正常に動作することを実証しました (MacOS X 10.7.2 でテストしていますが、他の同様の Unix ライクなシステムでも同じように動作します)。改訂版はわずかに改善されています。スペースや改行が続いていなくても、最後に入力された単語がカウントされます。

推測どおり、Windows で作業している場合、端末 I/O モデルは異なる可能性があります。特に、C 標準では、テキスト ファイル (おそらく端末入力を含む) は、EOF の前に改行で終了する必要があります。最後の改行の後の文字はすべて破棄される可能性がありますが、これはプラットフォームに依存します。バイナリ ファイルの動作は異なります。最後の改行の後のデータであれば、報告している動作と一致します。不明なシステムのドキュメントを参照すると、これは予想される動作である可能性があります。これは、PJ Plauger によって彼の優れた (しかしやや時代遅れの) 'The Standard C Library' で特定された実装間の違いの領域の 1 つです。

ただし、仮説が正しい場合でも、コードが正しいことを明確にしたいと思います (十分です)。問題は、システムの文書化された動作と期待が一致しないことです。作業しているプラ​​ットフォームを報告することが重要な場合があることに注意してください。エッジケースに侵入しているため、より重要になる傾向があります。でバグに遭遇する可能性は依然として非常に低いですgetchar()

ちなみに、私がテストしていたときは、Control-D2 回入力する必要がありました (これは、私がしなければならないことだと思っていたことです)。abc最初に、行 ( ) に入力した文字を 3 バイトの読み取りとしてプログラムにフラッシュしました。2番目は、入力した文字(すべてゼロ)を0バイトの読み取りとしてプログラムにフラッシュし、getchar(). abcまた、 (最後に空白)、次にEOFでテストしました。あなたのコードはabc、空白なしで を数えませんでした。abc後に空白が続くとカウントされました。

于 2012-02-07T14:52:16.317 に答える