C: вопросы о printf() и putchar()

Я читал книгу K&R и хотел проверить функции printf() и putchar() способами, которые я никогда не пробовал. Я столкнулся с несколькими неожиданными событиями и хотел бы услышать от более опытных программистов, почему это происходит.

char c;
while((c = getchar()) != EOF) {
//put char(c);
    printf("%d your character was.\n", c);
}
  1. Как получить EOF (конец файла) во входном потоке (функции getchar() или scanf())? Неожиданный ключ, который не распознается функцией getchar()/scanf(), может его создать?
  2. В моей книге сказано, что c должно быть целым числом, потому что оно должно хранить EOF, а переменная должна быть достаточно большой, чтобы содержать любой возможный символ, который может содержать EOF. Для меня это не имеет смысла, потому что EOF — это постоянное целое число со значением -1, которое может хранить даже char. Кто-нибудь может пояснить, что имелось в виду?
  3. Что происходит, когда я посылаю «привет» или «привет» в функцию putchar()? Он ожидает получить целое число, но возвращает странный вывод, такой как EE или oo, если я отправлю последнюю строку или последовательность символов.
  4. Почему, когда я использую функцию printf(), написанную выше, я получаю два вывода? Один - тот, который я ввел, а другой - целое число, которое в ASCII является концом строки. Производит ли он второй вывод, потому что я нажимаю ввод, который он принимает за второй символ?

Спасибо.


person Jonas Hoffmann    schedule 24.06.2013    source источник
comment
EOF обычно равен -1, getchar() возвращает его, когда read() из терминала возвращает 0. Вы не можете использовать char для getchar, потому что тогда в случае печати символа с кодом 255 (например, 'Ъ' в KOI8-R) вы получите ложный EOF. Чтобы скрыть вводимые символы, вы должны правильно настроить свой терминал (отключить эхо).   -  person Eddy_Em    schedule 24.06.2013
comment
Говоря false EOF, вы имеете в виду, что символ представляет собой целое число больше 1 байта и может быть распознано getchar(), если диапазон переменной установлен более 1 байта?   -  person Jonas Hoffmann    schedule 24.06.2013
comment
'hello' не является допустимой строкой, возможно, это приводит к неопределенному поведению. Что-то между '' должно представлять только один символ.   -  person Bernhard Barker    schedule 24.06.2013
comment
Говоря «ложный EOF», я имею в виду, что вы вводите символ, но ваше приложение будет думать, что это EOF. Любая буква == unsigned char, поэтому для отправки EOF нужно как минимум 2 байта!   -  person Eddy_Em    schedule 24.06.2013
comment
Я согласен, что любая буква является беззнаковым символом, но диапазон символов также является отрицательным числом. Как получается, что EOF нужно 2 байта, если это -1? Какие символы может ввести человек, чтобы приложение подумало, что это EOF?   -  person Jonas Hoffmann    schedule 24.06.2013
comment
Если ваша текущая кодовая страница 1252 (по умолчанию в большинстве западных культур), ввод ÿ (ЛАТИНСКАЯ СТРОЧНАЯ БУКВА Y С ДИЭРЕЗИСОМ, значение которой в этой кодовой странице равно 255) вызовет такой поддельный EOF. Потому что (signed char)255 == (signed char)-1 верно.   -  person Medinoc    schedule 24.06.2013
comment
getchar() вернет вам любое возможное char, что означает любое значение от 0 до 255 (если беззнаковое). Но в случае ошибки он должен дать вам код ошибки, поэтому getchar() должен возвращать как минимум 257 различных значений, char — это тип, который не может различать более 256 значений. Так что вам нужен более широкий тип. По историческим причинам short не подходил (не был уверен, что его длина больше байта), тогда был выбран int (уверен, что он достаточно длинный). Таким образом, технически getchar() возвращает 0-255 в случае чтения реального символа и -1 в случае ошибки. Вы должны различать -1 и 255.   -  person Jean-Baptiste Yunès    schedule 24.06.2013


Ответы (2)


  1. в Linux вы можете отправить его с помощью Ctrl+d

  2. вам нужен int, иначе вы не сможете отличить EOF от последнего возможного символа (0xFFFF — это не то же самое, что 0x00FF)

  3. putchar хочет символ, а не строку, если вы пытаетесь дать ему строку, она напечатает часть адреса строки

  4. вы получаете только один вывод: значение ascii введенного вами символа, другой «вход» - это то, что вы набрали в терминале

изменить – подробнее о 2

Вам нужен int, потому что getchar может возвращать как символ значения -1 (0x00FF), так и целое число значения -1 (0xFFFF), они не имеют одинакового значения: символ значения -1 является допустимым символом ( например, это ÿ в латинице-1), в то время как целое число со значением -1 в этом контексте является EOF.

Вот простая программа, которая показывает разницу:

#include <stdio.h>

int main(int argc, char ** argv) {
    {
        char c = 0xFF; /* this is a valid char */
        if (c == EOF) printf("wrong end of file detection\n");
    }
    {
        int c = 0xFF; /* this is a valid char */
        if (c == EOF) printf("wrong end of file detection\n");
    }
}

Первый тест проходит успешно, потому что 0xFF == -1 для char, а второй тест завершается неудачей, потому что 0x00FF != -1 для int.

Я надеюсь, что это делает его немного яснее.

person Guillaume    schedule 24.06.2013
comment
а в Windows EOF — это Ctrl+Z - person gkovacs90; 24.06.2013
comment
Спасибо. Я бы хотел, чтобы второй пункт был более объяснен. Вы имеете в виду, что есть символы больше 0x00FF (1 байт), и если мы используем символ, он не может распознать эти символы? - person Jonas Hoffmann; 24.06.2013
comment
@decas, при работе с функциями char нет символов больше 0x000000FF, за исключением EOF, который равен 0xFFFFFFFF на 32-битной платформе. Проблема возникает из-за того, что (char)0x000000FF и (char)0xFFFFFFFF имеют одинаковое значение: 0xFF псевдоним -1. - person Medinoc; 24.06.2013

  1. вы должны закрыть входной поток, чтобы получить EOF. Обычно с помощью CTRL-D в UNIX, но см. конфигурацию tty (stty -a)
  2. уже ответил
  3. такой же
  4. ваш tty повторяет то, что вы вводите по умолчанию. Если вы этого не хотите, установите режим noecho (stty -echo). Будьте осторожны, так как некоторые оболочки снова устанавливают эхо. Попробуйте с ш. Вы должны знать, что taht также буферизует ваши входные данные до тех пор, пока RETURN не наберет тип (см. руководство по stty для необработанного режима, если вам нужно).
person Jean-Baptiste Yunès    schedule 24.06.2013