Как этот цикл else-if отслеживает количество слов, введенных в C

#c #word-count

#c #количество слов

Вопрос:

Я изучаю C, используя книгу K amp; R, на компьютере с Windows. Я пробую программу ( bare bones Unix word count ), которая подсчитывает строки, символы и слова. Хотя эта программа правильно подсчитывает количество символов, количество строк и слов в моем выводе всегда равно 0 и 1, независимо от того, что я ввожу. Я также несколько озадачен одной частью программы, к которой я перейду дальше-

 #include<stdio.h>
#define IN 1
#define OUT 0

int main()
{
    int c,state, nc,nw,nl;
    nl=nw=nc=0;
    state=OUT;
    while(c=getchar()!=EOF)
    {
          nc;
        if(c=='n')
              nl;   

        if(c=='n'||c=='t'||c==' ')
            state=OUT;
        else if(state==OUT)
        {
            state=IN;
              nw;
        }
    }

    printf("n No. of characters, lines and words are : %d,%d,%dn",nc,nl,nw);
    return 0;

}
  

Из того, что это выглядит, эта программа использует nc , nl и nw , соответственно, для подсчета количества символов, строк и слов, введенных во входной поток. До сих пор мое понимание логики программы —

  1. IN и OUT — две переменные, используемые для указания текущего состояния программы. IN указывает, что программа в настоящее время находится «внутри» слова — другими словами — до сих пор в введенных символах не было обнаружено пробелов, новой строки или табуляции. Или я так думаю.
  2. В самом начале, перед while циклом, STATE значение out равно . Это указывает на то, что прямо сейчас слово не встречается.
  3. Когда начинается цикл while, с каждым введенным символом (если это не EOF- Ctrl Z ) количество символов nc увеличивается. В первом if statement , если символ является новой строкой 'n' , nl увеличивается. Это должно отслеживать количество встреченных строк.
  4. Второй оператор if используется для отслеживания того, находится ли программа в данный момент внутри слова или нет, путем установки значения STATE 0 всякий раз, когда есть пробел, новая строка или табуляция. До сих пор я понял логику.
  5. Тем не менее, я совершенно сбит с толку, перейдя к else-if. Здесь программа проверяет, есть ли STATE OUT . Теперь STATE это будет out в двух условиях: когда программа запускается в первый раз, и STATE устанавливается 0 перед циклом while. Пример — рассмотрим ввод WORD . Здесь, перед W тем, как встречается, STATE установлено значение 0 . Теперь, когда это STATE так 0 , и ввод W , мы приходим к else if statement . Следующий ввод после W O . Итак, STATE установлено значение 1 (указывающее, что программа находится внутри слова), и количество слов увеличивается.
  6. Но, поскольку исходные входные данные были WORD такими, что происходит, когда R они встречаются? В чем ценность STATE настоящего момента? Это все еще 1 потому, что он был установлен 1 внутри последнего оператора else-if? Но опять же, если это так 1 , то нет никакого условия для того, когда STATE это 1 произойдет.

Наконец, очевидно, что в программе есть какие-то недостатки, потому что в приведенном ниже примере вывода количество строк и слов всегда фиксировано (0 и 1).

 hello word
good morning
^Z

 No. of characters, lines and words are : 24,0,1
  

Я понимаю, что мой вопрос очень длинный, но я действительно в тупике и ищу ответы на два основных вопроса:

  • Как работает логика оператора else-if.
  • Почему программа выдает неверный вывод.

Большое спасибо за вашу помощь

Комментарии:

1. Пожалуйста, проверьте с помощью отладчика. Это даст вам четкое представление

Ответ №1:

Вы получаете неверный ввод, потому что у вас отсутствуют круглые скобки:

 while((c=getchar())!=EOF)
      ^           ^
  

Без них вы всегда сравниваете возвращаемое значение getchar() с EOF и присваиваете результат этого сравнения c . То есть c всегда будет либо 1, либо 0.

Комментарии:

1. О, я это пропустил. Теперь я получаю правильный вывод. Тем не менее, я все еще не совсем понимаю оператор else-if. Для примера входного СЛОВА, как только встречаются W и O, как программа обрабатывает R? Если я прав, на данном этапе СОСТОЯНИЕ установлено на неподвижное, и нет никаких условий для решения этой проблемы. Затем, как программа обрабатывает R и D WORD.

2. Программа продолжит работу в состоянии IN, поскольку он найдет » » или » t» или » n», так что nc и все. W => nc 1 state = IN, O => nc 1 state = IN, R => nc 1 state = IN, D => nc 1 state = IN.

3. Вот почему 1) вы никогда не должны использовать присваивание внутри выражений и 2) вы не должны использовать K amp; R для целей обучения или для любых других целей, помимо археологии и ностальгии. Хотя эта ошибка на самом деле упоминается в K amp; R 2nd edition p19. Такая отличная книга: «Делай так …», «… но подождите, на самом деле не делайте этого, потому что это неправильная и плохая практика».

4. Я понимаю вашу точку зрения. У меня также возникает все больше и больше сомнений по мере прохождения K amp; R. Не говоря уже о том, что я считаю, что это больше подходит для программистов среднего и продвинутого уровня. Есть ли какой-либо конкретный материал, который вы бы предложили для учебных целей?

Ответ №2:

Как работает логика оператора else-if.

Оператор IF проверяет, есть ли новая строка, пробел или табуляция, чтобы ВЫРЕЗАТЬ слово, поэтому, если есть, он переводит переменную «state» в значение OUT .

Следующий поворот цикла, если переменная «c» не является новой строкой, таблицей или пробелом, поскольку переменная «state» отсутствует, вызывается ELSE IF.

ELSE IF увеличивает nw, потому что после пробела табуляция или новая строка (и если это не другая строка) — это новое слово. И верните переменную «state» в значение IN, чтобы вернуться к оператору IF .

ПРИМЕР:

«WORD» => «W» -> nc nw state = OUT, «O» -> nc state = IN, «R» -> nc state = IN, «D» -> nc state = IN

«WO RD» => «W» -> nc nw state = OUT, «O» -> nc state = IN, » » -> nc state = OUT, «R» -> nc nw state = IN, «D» -> nc состояние = В

И если вы хотите легко понять, добавьте сразу после оператора while:

 while((c=getchar())!=EOF)
{
    printf("number of char = %d, number of words = %d, number or lines = %d, state = %d",nc,nw,nl,state)
  

Итак, вы увидите, что делает код после каждого поворота цикла.

Ответ №3:

Вот очень простой пошаговый обзор фиксированного кода. Я надеюсь, что это ответит на все исходные вопросы.

Единственное другое предложение — включить и проверить предупреждающие сообщения компилятора, поскольку они часто содержат подсказки о потенциальных источниках ошибок. На самом деле, gcc , и clang предупредит об исходной программе и предложит правильное исправление.

Включить стандартные (std) заголовочные файлы ввода / вывода

 #include <stdio.h>
  

Используйте препроцессор для определения (постоянных) макросов, которые используются для представления состояния либо IN на стороне слова, либо OUT на стороне слова. Определение для «outside» означает, что текущий символ (c) является пробелом в этой программе.

Пробел — это символ, который ничего не отображает, но может изменять выходные данные, например, переход к следующему расположению символа (пробел), к следующей остановке табуляции (табуляции) или переход к следующей строке (перевод строки).

 #define IN 1
#define OUT 0
  

Будучи простой программой, программа находится в main функции. Это нормально для короткой программы, подобной этой, но не очень хорошая идея в более крупных и сложных программах.

 int main(int argc, char* argv[])
{
    int c;     /* This is a 'current' character being read from input */
    int state; /* The state of being either IN- or OUT-side of a word. */
    int nc;    /* Count of number of characters read */
    int nw;    /* Count of number of "words" */
    int nl;    /* Line count */
    nl = nw = nc = 0; /* Initialize the counts to zero */
    state = OUT;  /* Begin with the word 'state' being OUT-side of a word */
  

Получите один символ из стандартного ввода (stdin), присвоите его
переменной c . Это делается сначала из-за (добавленной) круглой скобки, заключающей выражение c = getchar() . Затем результат этого присваивания (который равен c ) сравнивается с EOF (конец файла).

Хотя содержимое c не равно EOF , while тело цикла выполняется повторно, пока getchar() не будет присвоено EOF значение to c .

     while ( EOF != (c = getchar()) )
    {
  

Поскольку у вас есть новый символ, увеличьте количество символов, nc , переменную на единицу.

           nc;
  

Если c это новая строка, увеличьте количество строк, nl , count .

         if (c == 'n')
              nl;   
  

Если переменная c представляет собой символ новой строки, табуляции или пробела, затем отправьте state переменную в OUT , потому что они указывают, что c это не часть «слова».

         if (c == 'n' || c== 't' || c == ' ') {
            state = OUT;
        }
  

Если предыдущее if утверждение не получило значения true, следуйте else инструкции.
Оператор else состоит из второго if оператора, который оценивает state , равно ли OUT . Если это так, то выполните следующий блок.

         else if (state == OUT)
        {
  

Этот блок содержит два оператора, установите state значение IN и увеличьте значение nw (количество слов).

             state = IN;
              nw;
        } /* end of "else if" block */
    } /* end of while loop block */
  

После getchar() возврата an EOF (конец файла) и завершения цикла while программа печатает этот итоговый вывод, прежде чем возвращать ноль родительскому процессу (не беспокойтесь об этом здесь, это просто ведение домашнего хозяйства) и завершение программы.

     printf("n No. of characters, lines and words are : %d, %d, %dn", nc, nl, nw);

    return 0;
} /* end of main */