Правильно ли поведение getchar () для этой программы? - PullRequest
0 голосов
/ 07 февраля 2012

Следующий код показывает странное поведение. При вводе, если я нажимаю символ новой строки, только гистограмма выводит только значение, в противном случае, если я непосредственно ввожу 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");

    }

}

1 Ответ

1 голос
/ 07 февраля 2012

Ваш код работает более или менее разумно для меня, если я не наберу ни единого слова ввода, за которым не будет пробела (пробел, табуляция, новая строка), прежде чем указать EOF ( Control-D на моем компьютере); если вы используете Control-Z , это предполагает, что вы работаете в Windows). Если вы указываете EOF без последнего пробела, последнее слово не добавляется к гистограмме. Вы, конечно, должны также убедиться, что длина слова не слишком велика, чтобы не индексировать вне массива wordlength (if (nc > MAXSIZE) nc = MAXSIZE; для подсчета всех очень длинных слов одинакового размера).

После основного цикла обработки вы должны проверить, является ли nc > 0, и если да, увеличить соответствующую запись в wordlength.

Рассмотрите возможность использования isspace() из <ctype.h>.

Я использую enum вместо #define, когда это возможно, чтобы символы были доступны в отладчике. Вы тщательно избежали одной распространенной ошибки; вы превратили переменную c в int, а не 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, то модель терминала ввода-вывода может отличаться. В частности, стандарт C требует, чтобы текстовые файлы (возможно, включая ввод с терминала) заканчивались символом новой строки перед EOF; любые символы после последней новой строки могут быть отброшены, но это зависит от платформы. Поведение для двоичных файлов отличается. Если данные после последней новой строки, это будет соответствовать поведению, о котором вы сообщаете. Это вполне может быть ожидаемое поведение - если вы посмотрите документацию для вашей неопознанной системы. Это одна из областей различий между реализациями, указанными П. Дж. Плаугером в его превосходной (но несколько устаревшей) «Стандартной библиотеке С».

Однако, если мои предположения верны, я все же хочу прояснить, что ваш код верен (достаточно); проблема в том, что ваши ожидания не соответствуют задокументированному поведению вашей системы. Обратите внимание, что отчетность о платформе, на которой вы работаете, иногда очень важна Это имеет тенденцию быть более важным, поскольку вы покушаетесь на крайние случаи. И все же крайне маловероятно, что вы обнаружили ошибку в getchar().

Между прочим, когда я тестировал, мне нужно было дважды набрать Control-D (и это именно то, что я ожидал сделать). В первый раз символы, которые я ввел в строку (abc), были сброшены в программу в виде 3-байтового чтения; вторая также сбрасывала введенные мной символы (все их ноль) в программу в виде 0-байтового чтения, которое затем интерпретировалось как EOF как getchar(). Я также проверил с abc (пробел в конце), а затем EOF. Ваш код не засчитал abc без пробела; он действительно считал abc, когда за ним следовал пробел.

...