Какова цель ungetc (или ungetch от K & R)?

Может ли кто-нибудь объяснить мне цель ungetch? Это из главы 4 K & R, в которой вы создаете обратный Польский калькулятор.

Я запустил программу без вызова ungetch, и в моих тестах она по-прежнему работает одинаково.

int getch(void) /* get a (possibly pushed back) character */ { if (bufp > 0) { return buf[--bufp]; } else { return getchar(); } } void ungetch(int c) /* push character back on input */ { if (bufp >= BUFSIZE) { printf("ungetch: too many characters\n"); } else { buf[bufp++] = c; } } 

(Я удалил тернарный оператор в getch, чтобы сделать его более ясным.)

Я не знаю о конкретном примере, о котором вы говорите (это probaby 23 года с тех пор, как я прочитал K & R, и это было первое издание.), Но часто при parsingе удобно «заглядывать» на следующего персонажа, чтобы увидеть, это часть того, что вы сейчас разбираете. Например, если вы читаете номер, вы хотите продолжать считывать цифры до тех пор, пока не перейдете на цифру. Ungetc позволяет читателю номера смотреть на следующего персонажа, не потребляя его, чтобы кто-то еще его мог прочитать. В примере с Грегом Хьюджиллом «2 3+» читатель числа читал 3 цифры, затем читал знак «плюс» и знал, что номер закончен, затем отключите знак «плюс», чтобы его можно было прочитать позже.

Попробуйте запустить программу без пробелов вокруг операторов. Я точно не помню формат этого примера, и у меня нет K & R, но вместо «2 3 +» попробуйте «2 3+». Функция ungetch() , вероятно, используется при parsingе чисел, поскольку парсер чисел будет считывать цифры до тех пор, пока не получит что-то, что не является цифрой. Если не-цифра – это пробел, то следующий getch() будет читать + и все будет хорошо. Однако, если следующая незначащая цифра равна + , тогда ей нужно будет оттолкнуть ее обратно на входной stream, чтобы основной цикл чтения мог найти его снова.

Надеюсь, я правильно помню пример.

Он много используется для лексических сканеров (часть компилятора, которая разбивает ваш текст на куски, такие как имена переменных, константы, операторы и т. Д.). Функция не нужна сканеру, это очень удобно.

Например, когда вы читаете имя переменной, вы не знаете, когда вы закончите, пока не прочитаете символ, который не может быть частью имени переменной. Но тогда вы должны помнить этого персонажа и найти способ сообщить его следующему fragmentу лексера. Вы могли бы создать глобальную переменную или что-то еще, или передать ее вызывающему, но как же вы возвращаете другие вещи, например коды ошибок? Вместо этого вы отключите символ (), чтобы вернуть его во входной stream, сделайте все, что вам нужно, с именем переменной и возвратом. Затем, когда лексер начинает читать следующий fragment, ему не нужно оглядываться вокруг лишних символов.

Взгляните на этот код, вы поймете:

 #include  #include  int main() { int y=0; char t[10]; int u=0; ungetch('a'); t[y++]=getch(); ungetch('m'); t[y++]=getch(); ungetch('a'); t[y++]=getch(); ungetch('z'); t[y++]=getch(); ungetch('z'); t[y++]=getch(); ungetch('a'); t[y++]=getch(); ungetch('l'); t[y++]=getch(); ungetch('\0'); t[y++]=getch(); ungetch('\0'); t[y++]=getch(); ungetch('\0'); t[y++]=getch(); printf("%s",t); return 0; }