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