Пожалуйста, объясните этот пример кода C

Этот код исходит от K&R. Я читал ее несколько раз, но она все еще ускользает от моего понимания.

#define BUFSIZE 100

char buf[BUFSIZE];
int bufp = 0;

int getch(void)
{
      return(bufp>0)?buf[--bufp]:getchar();
}

int ungetch(int c)
{
      if(bufp>=BUFSIZE)
            printf("too many characters");
      else buf[bufp++]=c;
}

Цель этих двух функций, как говорит K&R, состоит в том, чтобы предотвратить чтение программой слишком большого количества входных данных. то есть без этого кода функция не сможет определить, что она прочитала достаточно данных, не прочитав сначала слишком много. Но я не понимаю, как это работает.

Например, рассмотрим getch(). Насколько я вижу, это шаги, которые он предпринимает:

  1. проверьте, больше ли bufp 0.
  2. если да, то верните символьное значение buf[--bufp].
  3. иначе вернуть getchar().

Я хотел бы задать более конкретный вопрос, но я буквально не знаю, как этот код достигает того, для чего он предназначен, поэтому мой вопрос: какова (а) цель и (б) аргументация этого кода?

Заранее спасибо.

ПРИМЕЧАНИЕ. Для всех поклонников K&R этот код можно найти на странице 79 (полагаю, в зависимости от вашего издания)


person Community    schedule 14.12.2011    source источник
comment
Тест внутри ungetch, вероятно, должен включать bufp, а не printf в своем состоянии. Я думаю, это опечатка.   -  person Basile Starynkevitch    schedule 14.12.2011
comment
У меня сейчас нет под рукой K&R, но я думаю, что в ungetch условие if должно быть bufp>=BUFSIZE   -  person kol    schedule 14.12.2011
comment
Извините, наверное, моя ошибка. Кто-то исправил это сейчас, поэтому я не могу вспомнить, что я изначально набрал.   -  person    schedule 14.12.2011
comment
В моем 1-м издании K&R есть bufp > BUFSIZE, но это выглядит как ошибка.   -  person Fred Larson    schedule 14.12.2011


Ответы (5)


(a) Цель этого кода состоит в том, чтобы иметь возможность прочитать символ, а затем "непрочитать" его, если окажется, что вы случайно прочитали символ слишком много (макс. 100 символов, которые должны быть "непрочитаны" ). Это полезно в парсерах с опережением.

(b) getch читает из buf, если у него есть содержимое, обозначенное bufp>0. Если buf пусто, вызывается getchar. Обратите внимание, что он использует buf в качестве стека: он читает его справа налево.

ungetch помещает символ в стек buf после проверки заполнения стека.

person Fred Foo    schedule 14.12.2011
comment
Но если предположить, что ungetch не вызывается, то getch всегда будет возвращать getchar(), так как bufp будет бесконечно равен нулю. Я не понимаю эту часть. - person ; 14.12.2011
comment
@JJG: правильно, если вы никогда не вызываете ungetch, вам не понадобится буфер, и вы всегда будете получать свежие данные от getchar. - person Fred Foo; 14.12.2011

Код на самом деле не предназначен для "чтения слишком большого количества введенных данных", а для того, чтобы вы могли возвратить уже прочитанные символы.

Например, вы читаете один символ с помощью getch, смотрите, является ли это буквой, кладете его обратно с помощью ungetch и читаете все буквы в цикле. Это способ предсказать, каким будет следующий персонаж.

person Some programmer dude    schedule 14.12.2011

Этот блок кода предназначен для использования программами, принимающими решения на основе того, что они считывают из потока. Иногда таким программам нужно просмотреть несколько символов из потока без фактического потребления ввода. Например, если ваш ввод выглядит как abcde12xy789 и вы должны разделить его на abcde, 12, xy, 789 (т. е. отделить группы последовательных букв от групп последовательных цифр), вы не знаете, что достигли конца группы букв. пока не увидишь цифру. Однако вы не хотите потреблять эту цифру в то время, когда вы ее видите: все, что вам нужно, это знать, что группа букв заканчивается; вам нужен способ «вернуть» эту цифру. В этой ситуации пригодится ungetch: как только вы видите цифру после группы букв, вы возвращаете цифру обратно, вызывая ungetch. Ваша следующая итерация выберет эту цифру обратно с помощью того же механизма getch, избавив вас от необходимости сохранять символ, который вы читали, но не использовали.

person Sergey Kalinichenko    schedule 14.12.2011

    1. The other idea also shown here can be also called as a very primitive I/O stack mangement system and gives the implementation of the function getch() and ungetch().
    2. To go a step further , suppose you want to design an Operating System , how can you handle the memory which stores all the keystrokes?

Это решается приведенным выше фрагментом кода. Расширение этой концепции используется при обработке файлов, особенно при редактировании файлов. В этом случае вместо использования getchar(), который используется для ввода данных из стандартного ввода, файл используется как источник ввода.

person Vageesh    schedule 14.12.2011

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

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

Из-за свойства LIFO (Last in first out) стека буфер в этом коде должен быть поставлен в очередь, так как он будет работать лучше в случае более чем одного дополнительного ввода.

Эта ошибка в коде сбила меня с толку, и, наконец, этот буфер должен быть поставлен в очередь, как показано ниже.

#define BUFSIZE 100

char buf[BUFSIZE];
int bufr = 0;
int buff = 0;

int getch(void)
{
      if (bufr ==BUFSIZE)
             bufr=0;

      return(bufr>=0)?buf[bufr++]:getchar();
}

int ungetch(int c)
{
      if(buff>=BUFSIZE && bufr == 0)
            printf("too many characters");
      else if(buff ==BUFSIZE) 
            buff=0;  

       if(buff<=BUFSIZE)
            buf[buff++]=c;
}
person Abhinandan Arya    schedule 23.05.2019