You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于K&R《C程序设计语言》中getint()函数的技术疑问

关于K&R《C程序设计语言》getint()函数的疑问解答

嘿,作为同样啃过K&R的过来人,你的这个疑问特别典型——你观察到的“非数字字符导致无限循环”的现象完全没错,但咱们得从这个函数的设计定位说起,帮你理清思路:

你的理解偏差在哪里?

你没看错这个循环问题,但你可能忽略了getint()的设计本质是教学示例,而非工业级健壮函数。它的核心是演示「预读字符判断类型+ungetch回推缓冲」的用法,而不是要处理所有输入场景。

这个函数真的会无限循环吗?

是的,在你贴的main函数逻辑下确实会!你的main循环条件是getint(...) != EOF,但当遇到非数字、非正负号的字符时:

  1. getint()会把这个字符用ungetch()塞回输入流
  2. 然后返回0(不是EOF)
  3. 下次调用getint()时,又会读到这个被塞回去的字符,重复上述操作,永远返回0,永远到不了EOF,自然陷入无限循环。

为什么要这么设计?

K&R写这个函数的目的,是教你如何处理「需要先读一个字符判断类型,不符合就塞回去给后续逻辑处理」的场景,它有个隐含假设:

  • 调用者会处理getint()的返回值:当getint()返回0时,调用者应该去处理那个被回推的非数字字符(比如读取并丢弃、或者终止循环),而不是无脑继续调用getint()。
  • 这个函数的职责只是「提取整数」,如果当前位置不是整数开头,就把字符塞回去,告诉调用者「这里不是整数,你自己处理」,而不是替调用者做决定。

比如,把你的main函数改成这样,就不会循环了:

#include <stdio.h>
#include <ctype.h>

#define BUFSIZE 100

int getint(int *);
int getch(void);
void ungetch(int);

int main() {
    int n, array[BUFSIZE], res;
    for (n = 0; n < BUFSIZE; ) {
        res = getint(&array[n]);
        if (res == EOF) break;
        if (res != 0) { // 只有成功读取整数才移动数组下标
            n++;
        } else {
            // 处理非数字字符,比如读取并丢弃
            printf("跳过非数字字符: %c\n", getchar());
        }
    }
    return 0;
}

// 以下是原getint、getch、ungetch实现
int getint(int *pn) {
    int c, sign;
    while (isspace(c = getch())) ;
    if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
        ungetch(c); 
        return 0;
    }
    sign = (c == '-') ? -1 : 1;
    if (c == '-' || c == '+')
        c = getch();
    for (*pn = 0; isdigit(c); c = getch())
        *pn = 10 * *pn + (c - '0');
    *pn *= sign;
    if (c != EOF)
        ungetch(c);
    return c;
}

int buf[BUFSIZE];
int bufp = 0;

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

void ungetch(int c) {
    if (bufp >= BUFSIZE)
        printf("ungetch: can't push character\n");
    else
        buf[bufp++] = c;
}

关于你提到的习题修正

你说习题要求修正「'-'或'+'后接非数字时被视为有效0」的问题,这个是原函数的逻辑漏洞,和无限循环是两个层面的问题。原函数遇到+a或-b时,会把*pn设为0再乘以符号,最后返回a或b,相当于把这种无效格式当成了值为0的整数。

修正的思路是:读完符号后,检查下一个字符是不是数字,如果不是,把符号和非数字字符都塞回输入流,返回0,比如修改这部分代码:

sign = (c == '-') ? -1 : 1;
if (c == '-' || c == '+') {
    int sign_char = c; // 保存符号字符
    c = getch();
    if (!isdigit(c)) {
        ungetch(sign_char); // 把符号塞回去
        ungetch(c);         // 把非数字字符塞回去
        return 0;
    }
}

这样就能正确识别+a或-b是无效输入,不会当成值为0的整数了。


内容的提问来源于stack exchange,提问作者ThornyHatcher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:39:05