Си: проблема с getchar() и EOF(^Z) в Windows консоли
Уже очень долгое время пытаюсь понять: Почему цикл не завершается, если я введу «dfkjsdf^Z», в то время как при
«dfkjsdf (тут я нажимаю Enter) ^Z» — завершается? То есть, как сделать так, чтобы он вышел из цикла, если я нажимаю CTRL+Z до того, как нажму Enter Это, пожалуй, самое непонятное для меня в языке Си. И сколько бы я не рылся в гугле, ответа все же найти не смог..
int main() < int c; int i = 0; int arr[10]; while((arr[i] = getchar()) != EOF && i < 10) < printf("arr[i] is %c\n",arr[i]); i++; >return 0; >
Отслеживать
52.3k 11 11 золотых знаков 108 108 серебряных знаков 312 312 бронзовых знаков
задан 15 дек 2017 в 20:20
83 7 7 бронзовых знаков
То есть вы набираете на клавиатуре dfkjsdf^Z без Enter’а? И да, какая у вас система, и какая консоль? Обработка ^Z зависит от консоли.
15 дек 2017 в 20:32
Это поведение не языка Си, а виндоус консоли (переходите в *nix)
15 дек 2017 в 20:42
Да. То есть я ввожу dfkjsdf , затем CTRL+Z , затем Enter . Windows 10. cmd
15 дек 2017 в 20:58
@avp: Чем тут должен помочь «переход в *nix»? Логика Ctrl-D в *nix отличается в деталях, но внешне она похожа. При построчной буферизации конец файла возникает только при нажатии Ctrl-D на пустом буфере, то есть нажимать Enter перед Ctrl-D придется и там.
16 дек 2017 в 15:42
@AnT, в родном для языка окружении проще учиться (и вообще . )
16 дек 2017 в 16:50
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Это не имеет никакого отношения к языку С, а зависит только от алгорима обработки комбинации Ctrl + Z консолью Windows и интерпретацией результатов этой обработки той реализацией стандартной библиотеки, которую вы используете.
Ввод в Windows терминале буферизуется построчно. При этом обработка присутствующих в буфере символов ^Z следует довольно запутанному алгоритму (по крайней мере при использовании стантартной библиотеки из комплекта MSVC).
- Комбинация Ctrl + Z сама по себе не вызывает «проталкивания» накопленного буфера на выход (в отличие от комбинации Ctrl + D в Linux). Она лишь добавляет во входной буфер символ ^Z , т.е. \x1a . Вы можете нажать Ctrl + Z несколько раз, помещая во входной буфер несколько символов ^Z . После этого вы можете продолжать вводить что-то еще. Чтобы все-таки послать накопленный буфер ожидающему процессу, придется нажать Enter .
- Если входной буфер содержит какие-то символы до первого появления символа ^Z , то ожидающий ввода процесс увидит все эти символы, после чего процесс увидит один символ ^Z , т.е. \x1a . Это будет просто символ \x1a . Никакой ситуации «конец файла» при этом не возникнет. Однако остаток входного буфера (после первого символа ^Z ) процессу виден не будет, как будто его и не было. То есть если вы введете в Windows терминале последовательность abc^Z^Zdef^Zghi и нажмете Enter , то на вход ваш процесс получит символы a , b , c и \x1a . Весь остальной ввод пропадет бесследно. Заметьте, что при этом «пропадает» и символ перевода строки, cгенерированный нажатием Enter .
- Если входной буфер сразу же начинается с символа ^Z , то входной буфер считается пустым. Все его содержимое пропадает, не происходит даже чтения символа ^Z . Возникает ситуация «конец файла». То есть если вы введете в Windows терминале последовательность ^Zdef и нажмете Enter , то на вход ваш процесс не получит вообще ничего. Вместо этого функция ввода сообщит вам, что наткнулась на конец файла.
Поэтому для того, чтобы создать в буферизованном консольном вводе ситуацию «конец файла» придется вводить ^Z в самом начале новой строки.
Если вам нужна посимвольная обработка входа, то можно предварительно отключить построчную буферизацию ввода
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); DWORD dwMode; GetConsoleMode(hIn, &dwMode); dwMode &= ~ENABLE_LINE_INPUT; SetConsoleMode(hIn, dwMode);
В таком варианте каждый введенный символ будет немедленно читаться вашей getchar() и символ ^Z будет немедленно интерпретироваться как конец файла.
Научный форум dxdy
Вот занялся нормальным изучением языка си, естественно воспользовался классикой Керниган, Ричи. Трудность понимания возникла в начале при чтении главы про «символическую константу EOF». Там говорят, что она обозначает конец входного потока ну и приведен текст программы где она используется:
Используется синтаксис C
while ( ( c = getchar ( ) ) != EOF )
putchar ( c ) ;
Так вот, здесь я так понимаю входной поток — это данные(символы), введенные с клавиатуры .Тогда что принимать за конец входного потока? Я же могу бесконечно набирать текст с клавиатуры (насколько позволяет память), как функция getch() определит эту константу и когда?
Re: Смысл EOF в си
14.07.2012, 21:45
Я тоже недавно читал/компилял. В винде программа выдаёт результат после нажатия ctrl+c, т.е. после прерывания её работы.
Re: Смысл EOF в си
14.07.2012, 23:04
А, то есть нажатием комбинации клавиш ctrl+c мы передаем системе значение EOF. Правильно? Ну пока как-то не особо ясно для чего нужна эта константа. Там даже было задание: написать программу, выводящую значение EOF, я написал, скомпилил, в результате вывелся пробел.
Re: Смысл EOF в си
14.07.2012, 23:18
| Админ форума |
Dosaev в сообщении #595304 писал(а):
[syntax lang=»c»]#include
.
[/syntax]
Dosaev , при включении кода в текст сообщения используется что-нибудь одно: или [cоde], или [syntаx]. Лучше [syntаx], причем для облегчения последующих ссылок на код — с атрибутом lines=n (для нумерации строк). Поправил.
Re: Смысл EOF в си
14.07.2012, 23:18
| Заслуженный участник |
Вообще-то EOF вводится по Ctrl+D (UNIX) / Ctrl+Z (Win). Ctrl+C — это прерывание работы программы.
Зачем эта константа нужна? Чтобы отследить, когда поток ввода закончится. Так всегда было: чтобы ввести простенький текст в файл с консоли, достаточно скомандовать «copy con 1.txt», ввести текст и нажать Ctrl+Z.
Re: Смысл EOF в си
14.07.2012, 23:19
Последний раз редактировалось Pavia 14.07.2012, 23:21, всего редактировалось 1 раз.
Цитата:
Тогда что принимать за конец входного потока? Я же могу бесконечно набирать текст с клавиатуры (насколько позволяет память), как функция getch() определит эту константу и когда?
Вот что написано в википедии.
Цитата:
Для указания терминалу в UNIX «EOF» следует воспользоваться комбинацией клавиш Ctrl+D. В Windows — Ctrl+Z.
На самом деле всё сложнее. EOF не является символом.
getch() По примеру большинства функций возвращает -1 когда происходит внутренняя ошибка. Такой ошибкой является конец файла. Закрытие файла.
Всё является файлом. Так вот консольный/терминальный ввод и вывод обычно на более низком уровне представим как файлы с хэндалами 0 и 1.
getch попросту читает данные из файла и как только обнаруживает что файл закрыт то выдает код ошибки -1=EOF.
Техническая реализация зависит от ОС. Но скорее всего ОС является POSIX совместимой.
Представление ввода вывода в виде файлов удобно для реализации перенаправления ввода/вывода. К примеру в дос можно написать в терминале «test.exe По идеи если написать «test.exe
Как ввести символ EOF (End Of File — конец файла)
требуется в конце ввода ввести специальный псевдо-символ EOF (конец файла). Он вводится комбинацией клавиш Ctrl+D.
- Как переключаться между консолями linux.
- Как перезагрузить X-сервер.
- Почему не получается переименовать файл.
- Постраничный просмотр вывода в терминале.
- Аналог Norton Commander, Volkov Commander, Far в Linux.
- Как запустить эмулятор терминала в другом окне.
- Как выполнить команды при старте консольной сессии.
- Как ввести символ EOF (End Of File — конец файла).
- Как перенаправить вывод в никуда (нулевое устройство).
- Как принудительно выключить компьютер.
- Как принудительно перезагрузить компьютер.
Сайты Google
Сообщить о нарушении
Сайты Google
Сообщить о нарушении
Сайт использует файлы cookie сервисов Google. Это необходимо для его нормальной работы и анализа трафика. Статистика использования сайта отправляется в Google. Нажимая кнопку «Принимаю», вы соглашаетесь с использованием файлов cookie. Правила в отношении файлов cookie
Eof си как ввести
Объясните, пожалуйста, почему EOF c консоли (в Win XP) это Ctrl+Z и Ctrl+M.
На других форумах находил, что Ctrl+Z+Enter — это EOF, а у меня Ctrl+Z и Ctrl+M.
К какому источнику обратиться для понимания этой ситуации?
Может кто у себя проверит:
#include #include int main () < setlocale(LC_ALL, "Rusian"); char c = getchar(); while (c != EOF) < putchar(c); getchar(); >getchar(); return 0; >
| 8Observer8 |
| Посмотреть профиль |
| Найти ещё сообщения от 8Observer8 |
Регистрация: 09.01.2008
Сообщений: 26,238
привожу табличку из TechHelp’а (был такой справочник эпохи MS DOS)
Dec Hex Ctl Name Control Meaning │ Dec Hex Ctl Name Control Meaning ▀▀▀ ▀▀▀ ▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ │ ▀▀▀ ▀▀▀ ▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ 0 00 ^@ NUL null (end string) │ 16 10 ^P DLE data line escape 1 01 ^A SOH start of heading │ 17 11 ^Q DC1 dev ctrl 1 (X-ON) 2 02 ^B STX start of text │ 18 12 ^R DC2 device ctrl 2 3 03 ^C ETX end of text │ 19 13 ^S DC3 dev ctrl 3 (X-OFF) 4 04 ^D EOT end of transmission │ 20 14 ^T DC4 device ctrl 4 5 05 ^E ENQ enquiry │ 21 15 ^U NAK negative acknowledge 6 06 ^F ACK acknowledge │ 22 16 ^V SYN synchronous idle 7 07 ^G BEL bell │ 23 17 ^W ETB end transmit block 8 08 ^H BS backspace │ 24 18 ^X CAN cancel 9 09 ^I HT TAB horizontal tab │ 25 19 ^Y EM end of medium 10 0a ^J LF line feed │ 26 1a ^Z SUB substitute 11 0b ^K VT vertical tab │ 27 1b ^[ ESC escape 12 0c ^L FF form feed │ 28 1c ^\ FS file separator 13 0d ^M CR carriage return │ 29 1d ^] GS group separator 14 0e ^N SO shift out │ 30 1e ^^ RS record separator 15 0f ^O SI shift in │ 31 1f ^_ US unit separator ─────────────────────────────────────┴──────────────────────────────────────── Box & Special Characters ASCII■Decimal■Hex■Binary XRef ASCII
отсюда легко увидеть, что нажатие CTRL-M возвращает такой же код, как и нажатие ENTER,
а нажатие CTRL-Z возвращает код 26 — который и интерпретируется как конец файла (EOF)
| Serge_Bliznykov |
| Посмотреть профиль |
| Найти ещё сообщения от Serge_Bliznykov |