Программирование на C - пример K&R 1.5.2 - модифицированная программа не работает должным образом

Мой вопрос просто: «Почему мой код в строках 10 и 11 не работает должным образом?» Предполагаемая цель моего кода - делать то же, что и исходный код K&R, но НЕ считать nc всякий раз, когда (getchar() == '\n'), не могли бы вы меня просветить?

слегка измененный код K&R:

/** K&R - 1.5.2 Character Counting **/
#include <stdio.h>

/* count characters in input; 1st version */
main(){
  long nc;

  nc = 0;
  while (getchar() != EOF){
    if (getchar() != '\n'){
      ++nc;
    }
  }
  printf("%ld\n", nc);
}

Я использую 64-разрядную версию Windows 7, CodeBlocks10.05, компилятор GNU GCC.

мой текущий прогресс и понимание:

в примере запуска я ввожу слово two и нажимаю Enter, что равняется 4 входам, после чего я нажимаю ctrl+Z, чтобы ввести символ ^Z или EOF. Затем программа печатает 1. Я ожидал, что он напечатает 3. Я полагаю, что единственное логическое объяснение состоит в том, что он делает прямо противоположное тому, что я намеревался (он только считает символы новой строки?). Оказывается, если я наберу слово two и нажму Enter, скажем, 4 раза, будет напечатано 4. Кажется, что он подсчитывает nc для каждого введенного символа новой строки, но все же, если я нажимаю только ввод (в данном случае 4 раза), а затем EOF, он всегда печатает 0. После дальнейших экспериментов, некая невидимая рука 4, возможно, является магическим числом для этой программы. Если я запущу его и точно нажму клавишу ввода (число, кратное 4) раз, а затем EOF напечатает 0. Однако, если я нажму Enter еще несколько раз, EOF ничего не сделает, и я должен ввести в ^Z две строки, одну за другой, чтобы правильно завершить цикл while, и он напечатает 1. Это сбивает с толку!


person pying saucepan    schedule 24.08.2012    source источник


Ответы (3)


Проблема в том, что вам нужно сохранить значение из getchar() — в int — потому что вы читаете два символа при каждом увеличении счетчика. Один из них находится в тесте EOF; второй находится в тесте новой строки.

int c;

while ((c = getchar()) != EOF)
{
    if (c != '\n')
        ++nc;
}

Причина, по которой вам нужно сохранить результат getchar() в int, а не в char, заключается в том, что он может возвращать все возможные значения char, а также отдельное значение, EOF. Если вы не используете int (вы сохраняете прямо в char), произойдет одно из двух:

  1. Если char является знаковым типом, допустимый символ (часто y-umlaut, ÿ, СТРОЧНАЯ ЛАТИНСКАЯ БУКВА Y С ДИАРЕЗИСОМ, U+00FF — по крайней мере, в кодовых наборах, полученных из Latin 1 или ISO 8859-1) будет интерпретироваться как эквивалент EOF. , и ваша программа завершится преждевременно.
  2. Если char является беззнаковым типом, ни один символ никогда не будет эквивалентен EOF, поэтому программа никогда не остановит цикл.

Ни одно из этих обстоятельств нежелательно. Сохранение возвращаемого значения getchar() в int предотвращает обе проблемы; это «единственный» (или, по крайней мере, самый простой) правильный способ сделать это.

person Jonathan Leffler    schedule 24.08.2012

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

Вы должны понимать, что вызов getchar() считывает символ из входного потока. Если вы хотите проверить наличие новой строки, вы должны сохранить этот символ в переменной, а затем проверить эту переменную.

person sitifensys    schedule 24.08.2012

int c;

[...]

while ((c = getchar()) != EOF) {
    if (c != '\n') {
      ++nc;
    }
}

Каждый раз, когда вы вызываете getchar(), вы потребляете символ из stdin.

person InternetSeriousBusiness    schedule 24.08.2012
comment
Вероятно, вам следует немного объяснить, почему ваше решение верно. - person Jonathan Leffler; 25.08.2012
comment
вау, я только что закончил писать именно это, за исключением того, что я сделал переменную c char, и она делает то же самое, что и исходный код K&R? - person pying saucepan; 25.08.2012
comment
@pyingSaucepan char недостаточно широк, чтобы вместить EOF, именно поэтому getchar возвращает int. - person Chris Rice; 25.08.2012
comment
когда я ввожу тип два и нажимаю Enter и EOF, он все равно возвращает 4 - person pying saucepan; 25.08.2012
comment
мои извинения, я забыл поставить скобки вокруг c = getchar() - person pying saucepan; 25.08.2012