Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> getchar() - вопрос с буфером ввода 
:(
    Опции темы
russians
Дата 21.8.2012, 02:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 297
Регистрация: 6.11.2006

Репутация: нет
Всего: нет



В книге K&R в первых главах даётся описание функций getchar и putchar, но пропущена проблема буфера.
Например, если выполнить код из этой статьи http://younglinux.info/c/getchar

Код

  char a, b, c;
 
  a = getchar();
  putchar(a);
  b = getchar();
  putchar(b);
  c = getchar();
  putchar(c);
 
  printf("\n");


то он не сработает, как ожидается, т.к. второй символ будет занят \n, а третий вторым символом. Плюс - непонятно из статьи, почему на выводе мы увидим букву, а не \n + букву. Также непонятно, вот я ввёл символ ~, который в while отмечен по условию выхода. Почему тогда не производится выход из программы в тот момент, как я ввожу этот символ, если он уже добавился в буфер обмена, а в тот момент, когда я нажимаю Enter? Непонятно. 

Кроме того, мне непонятно, почему этот код даёт завершение ввода по нажатию ~:
Код

#include <stdio.h>

main()
{
  int a = getchar();

  while(a  != '~') {
    putchar(a);
    a = getchar();
    }
    putchar("\n");
}

а более короткая запись - уже нет:
Код

#include <stdio.h>

main()
{
  int a;

  while((a = getchar())  != '~') {
    putchar(a);
    }
    putchar("\n");
}


И почему в выводе первого варианта отсутствует перевод на новую строку и присутствует L?

Код

paulmad@bird:~/kernigan$ ./few_chars 
~
Lpaulmad@bird:~/kernigan$


Это сообщение отредактировал(а) russians - 21.8.2012, 02:17
PM MAIL   Вверх
baldina
Дата 21.8.2012, 03:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



putchar() считывает один символ. три путчара считывают 3 символа. но в программу какие-либо символы попадут только после нажатия Enter, т.к. ввод буферизуется.
так что в первом примере надо ввести abc<Enter> и считаются все три символа. непонятки с ~ по той же причине.

putchar("\n"); выведет странные вещи, т.к. ей передан не символ, а указатель на строку.
PM MAIL   Вверх
russians
Дата 21.8.2012, 04:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 297
Регистрация: 6.11.2006

Репутация: нет
Всего: нет



baldina, стоп, а как же тогда работает getchar?
Ведь каждый цикл вызывается getchar, который считывает один символ из потока ввода, который, по определению K&R, являет собой последовательность символов, разбитых на строки. А мы вбиваем не по одному символу, а всю строку целиком и нажимаем Enter.
Как тогда понять конструкцию:

Код

while((a = getchar())  != '~') {
    putchar(a);
    }


Т.е. запускается getchar() и запускается ввод. Мы можем ввести целиком строку и нажимаем Enter. После этого getchar берёт введённую строку и посимвольно пробегается по ней? Непонятно, что если ввод строки открывает getchar, то функция должна завершить свою работу на этапе while и уничтожить строку, которая была введена, кроме первого символа, сохранённого в a, а её несуществующие символы обрабатываются в putchar. Что же тогда принимает строку на ввод из потока, если getchar принимает только один символ?

Это сообщение отредактировал(а) russians - 21.8.2012, 04:15
PM MAIL   Вверх
feodorv
Дата 21.8.2012, 04:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 11
Всего: 45



А ещё можно сбрасывать буфер ввода:
Код

  while(a  != '~') {
    putchar(a);
    fflush( stdin );
    a = getchar();
    }
Но на "ввод" нажимать всё равно придётся)))


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
russians
Дата 21.8.2012, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 297
Регистрация: 6.11.2006

Репутация: нет
Всего: нет



feodorv, а разве вызов getchar() после putchar не опустошает буфер автоматически? Или буфер работает по принципу стека?
PM MAIL   Вверх
baldina
Дата 21.8.2012, 13:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата(russians @  21.8.2012,  04:08 Найти цитируемый пост)
по определению K&R, являет собой последовательность символов, разбитых на строки

Вы не совсем правильно поняли. Это не по их определению, так консоль устроена.

Цитата(russians @  21.8.2012,  12:43 Найти цитируемый пост)
Или буфер работает по принципу стека? 

буфер работает по принципу очереди

Цитата(russians @  21.8.2012,  04:08 Найти цитируемый пост)
getchar берёт введённую строку и посимвольно пробегается по ней

нет. getchar() извлекает один единственный символ из буфера (начала очереди). что и как попадает в буфер от программиста скрыто, известно только, что попадает со стандартного ввода.

программисту достаточно знать, что:
1. getchar() получает очередной символ из потока ввода (будет ждать, если доступных символов нет)
2. символы, вводимые с клавиатуры, станут доступны программе после нажатия клавиши enter.

необходимость нажатия enter связана только с механизмом работы консоли (по историческим ныне несущественным причинам).
если на стандартный ввод перенаправить из файла, будет как раз последовательная посимвольная обработка.

Добавлено @ 13:08
Цитата(russians @  21.8.2012,  12:43 Найти цитируемый пост)
разве вызов getchar() после putchar не опустошает буфер автоматически

нет. они вообще с разными потоками связаны, stdin и stdout.

Добавлено @ 13:11
попробуйте заменить В вашем примере getchar и putchar на getc и putc, может быть сразу станет понятнее.
Это суть одно и то же, только в getc и putc поток ввода/вывода указывается явно, а getchar и putchar однозначно работают с stdin и stdout соответственно. 

Это сообщение отредактировал(а) baldina - 21.8.2012, 13:18
PM MAIL   Вверх
russians
Дата 21.8.2012, 13:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 297
Регистрация: 6.11.2006

Репутация: нет
Всего: нет



baldina, спасибо за подробное разъяснение.
Но разве издательство K& покойный R (WPH) не могли добавить этот нюанс в новую редакцию, учитывая то, что с этим может возникнуть непонимание? Объяснить, что существует buffered input и unbuffered input.
А потом говорят, что этой книги вполне достаточно для базового понимания C smile

Это сообщение отредактировал(а) russians - 21.8.2012, 13:42
PM MAIL   Вверх
baldina
Дата 21.8.2012, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата(russians @  21.8.2012,  13:33 Найти цитируемый пост)
для базового понимания C 

достаточно.
для базового понимания аппаратуры и ОС есть другие книги)))

Добавлено через 2 минуты и 12 секунд
Цитата(russians @  21.8.2012,  13:33 Найти цитируемый пост)
buffered input и unbuffered input.

в случае getc и getchar ввод всегда буферизирован, независимо консоль это или другой файл
в случае небуферизированного ввода с консоли enter все равно придется нажимать.
так что это к теме не относится))

Добавлено через 9 минут и 7 секунд
Буфер IO это сугубо программная вещь. Буферы, которые в драйверах (или в самой железке) совсем другого рода и уровня, Вы этим не можете управлять (посредством программного IO).
Представьте сетевой обмен. Например в Ethernet кадре данные это от 46 до 1500 байт. Можно читать/писать в сеть посимвольно, но это логически, с точки зрения программиста, а физически ходить данные все-равно будут порциями.
PM MAIL   Вверх
russians
Дата 21.8.2012, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 297
Регистрация: 6.11.2006

Репутация: нет
Всего: нет



baldina, ок, спасибо. Просто, в любом случае, человек наткнётся на эту проблему и ему будет непонятно, почему код, который он написал по заданию книги, не работает. Т.е. getchar() работает не просто так, он работает с системным буфером, и для цельного понимания нужно вводить элементы из устройства ОС Unix. Правда, у K&R для этого есть другая книжка smile

Это сообщение отредактировал(а) russians - 21.8.2012, 15:31
PM MAIL   Вверх
russians
Дата 21.8.2012, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 297
Регистрация: 6.11.2006

Репутация: нет
Всего: нет



baldina, а ещё такой вопрос: почему в варианте

Код

#include <stdio.h>
main()
{
  int a;
  while((a = getchar())  != EOF) {
    putchar(a);
    }
    putchar("\n");
}


текст вида aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^Z[Enter] прокатывает и вместо терминирования цикла - новая строка для ввода, а если напечатать одиночно ^Z - происходит терминирование цикла?

Просто в этом варианте: 

Код

#include <stdio.h>

main()
{
      int c, nl;
      
      nl = 0;
      
      while ((c = getchar()) != EOF)
            if (c == '\n')
               ++nl;
      printf("%d\n", nl);
      getchar();
}


мы считаем количество '\n', и тут getchar() доходит до конца строки. Почему в первом варианте не так?

Это сообщение отредактировал(а) russians - 21.8.2012, 16:37
PM MAIL   Вверх
baldina
Дата 21.8.2012, 19:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



пока enter не введен ^Z видимо просто сбрасывает буфер в программу (без enter), но не шлет конец файла. в отличие от ввода в начале строки
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0534 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.