2015-07-22 3 views
0

Это мой первый вопрос о stackoverflow. Простите меня, если я не искал должным образом, но, похоже, я не нашел объяснения. Просто попытался привести пример из статей Бьюрн Струустгруп. Добавлены мои биты, чтобы увидеть, как массив меняет размер, когда я набираю текст.Почему getchar работает как буфер вместо работы в ожидании в реальном времени

Но, похоже, это не так! getchar() просто ждет, пока я закончил с вводом всех символов, а затем он выполнит цикл. Согласно логике, он фактически не переходит в цикл, не получает персонажа, не выполняет его действия, а затем итерации. Мне интересно, является ли это конкретной реализацией или предполагается, что это так?

Я нахожусь на Ubuntu 14.04 LTS, используя Codeblocks с gcc 4.8.2. Источник был в файлах cpp, если это имеет значение.

while(true) 
{ 
    int c = getchar(); 
    if(c=='\n' || c==EOF) 
    { 
     text[i] = 0; 
     break; 
    } 
    text[i] = c; 

    if(i == maxsize-1) 
    { 
     maxsize = maxsize+maxsize; 
     text = (char*)realloc(text,maxsize); 
     if(text == 0) exit(1); 
     cout << "\n Increasing array size to " << maxsize << endl; 
    } 

    i++; 
} 

Выход следующим образом:

массив Размер теперь: 10 Пожалуйста, введите текст: это какой-то образец текста. Мне бы хотелось, чтобы память была перераспределена прямо здесь, но, видимо, это не так!

Увеличение размера массива до 20

Увеличение размера массива до 40

Увеличение размера массива до 80

Увеличение размера массива до 160

Вы вошли: это какой-то образец текста. Мне бы хотелось, чтобы память была перераспределена прямо здесь, но, видимо, это не так!

массив Размер теперь: 160

ответ

1

Это не имеет ничего общего с getchar напрямую. «Проблема» - это базовый терминал, который будет буферизовать ваш вход. Ввод будет отправлен в программу после нажатия кнопки ввода. В Linux (не знаю, есть ли способ в Windows) вы можете обойти это путем вызова

/bin/stty raw 

в терминале или по телефону

system ("/bin/stty raw"); 

в вашей программе. Это приведет к тому, что getchar немедленно вернет вам входной символ.

Не забудьте сбросить tty поведение, вызвав

/bin/stty cooked 

когда сделано!

Вот пример (для Linux):

#include <stdio.h> 
#include <stdlib.h> 

using namespace std; 

int main() { 
    system ("/bin/stty raw"); 
    char c = getchar(); 
    system ("/bin/stty cooked"); 
    return 0; 
} 

также посмотреть на эту SO сообщение: How to avoid press enter with any getchar()

Кроме того, как было предложено в комментариях, смотрите здесь: http://linux.die.net/man/3/termios особенно команда tcsetattr, которая должна работать кросс-платформенно.

+0

Вы должны указать страницу termios man и функцию tcsetattr, которая может помочь в настройке терминала ввода-вывода. –

+0

Очень хорошее предложение. К сожалению, я не знаком с termios. Если да, вы можете опубликовать его в качестве ответа. Я кратко добавил ваше предложение к ответу – Nidhoegger

+0

Я попытался добавить фрагменты в начале и в конце программы. Оно работает! Но тогда часть (c == '\ n') не работает. Он застрял в цикле while навсегда. Я предполагаю, что это ожидаемое поведение, поскольку я прошел через SO Post. Есть ли способ, по которому я могу проверить, является ли введенный символ символом новой строки? –

1

Фактически, tcsetattr не относится к Windows (что обычно упоминается на этом сайте как «кросс-платформенная»). Однако вопрос помечен для Linux, поэтому «кросс-платформенный» - спорный вопрос.

По умолчанию стандартного ввода, вывода и ошибок потоки установлены в

  • линия буферизации (вход)
  • блок-буферном (выход)
  • линии буфера (ошибка)

Вы можете изменить , что, используя setbuf, но, конечно же, не решит проблему (ответ требует ввода одного символа). POSIX терминал ввода/вывода (termios) позволяет вам с помощью системного вызова изменять любой из флагов, показанных с помощью stty. Как правило, вы можете вызвать stty непосредственно из сценария, редко из программы C.

Чтение одного символа часто задаваемый вопрос, например,

Вы можете также использовать ncurses: функция filter полезна для программ, обрабатывающих командную строку (а не полноэкранное приложение). Существует пример программы в ncurses-examples (filter.c), которая делает это.

+0

Это было очень полезно. Я просмотрел документацию tcsetattr, и я предполагаю, что это кросс-платформенная, она предназначена для всех версий Linux, которые, я думаю, должны работать. Не похоже, что существует истинное кросс-платформенное решение, если не используются некоторые внешние библиотеки? Или у нас есть несколько кодовых блоков для управления этим поведением в зависимости от ОС, в которой работает программа, и использования предпроцессорных директив для управления вызовом get в зависимости от реализации, на которой работает программа? Каким будет правильный способ? –

+0

Существует множество подходов, например, использование интерфейса более высокого уровня для скрытия деталей реализации. Программы с большим количеством ifdef трудно поддерживать (полная реализация в отдельных исходных файлах, но использование общих заголовков для обеспечения согласованности интерфейсов - это способ решить эту проблему). –