Eof си как ввести
Перейти к содержимому

Eof си как ввести

  • автор:

Си: проблема с 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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *