【问题标题】:getop() function K&R book p 78gettop() 函数 K&R 书第 78 页
【发布时间】:2015-10-23 09:45:10
【问题描述】:

我正在学习 K&R 书籍。目前我正在阅读第 78 页的函数 getop()。 我确实了解代码,但我需要澄清两件事。

getop()的代码如下:

int getch(void);
void ungetch(int);

/* getop: get next character or numeric operand */
int getop(char s[])
{
    int i, c;
    while ((s[0] = c = getch()) == ' ' || c == '\t')
        ;
    s[1] = '\0';

    if (!isdigit(c) && c != '.')
        return c; /* not a number */

    i = 0;
    if (isdigit(c)) /* collect integer part */
        while (isdigit(s[++i] = c = getch()))
            ;
    if (c == '.') /* collect fraction part */
        while (isdigit(s[++i] = c = getch()))
            ;
    s[i] = '\0';

    if (c != EOF)
        ungetch(c);

    return NUMBER;
}

我的问题是关于:s[0] 在:

 while ((s[0] = c = getch()) == ' ' || c == '\t')

while 循环背后的想法是跳过空格和水平制表符,那么我们为什么要在 s[0] 中保存 'c' 呢?为什么作者不简单地写:

while (c= getch() == ' ' || c == '\t')

我们以后不会使用空格和制表符,为什么我们需要将c保存在s[0]中呢?这里需要s[0]是什么?

我的第二个问题是:

s[1] = '\0';

为什么我们在这里将'\0'(字符串结尾)分配给s[1]?

我已经阅读了 stackoverflow.com 上发布的一些关于它的先前答案,但我并不完全相信!

关于上述问题的公认答案是:“因为函数可能会在读取剩余输入之前返回,因此 s 需要是一个完整的(和终止的)字符串。”

好的。但是,如果输入的开头有一个空格,然后是操作数或运算符怎么办?在这种情况下,s[1] = '\0' 会过早关闭字符串吗?不是吗?

【问题讨论】:

    标签: c kernighan-and-ritchie


    【解决方案1】:

    在回答您的第一个问题时,在这种情况下分配给s[0] 是一种方便的编码快捷方式。对于getch() 读取的每个 字符,c 的值将被复制到s[0],无论它是被使用还是被丢弃。如果要丢弃,没什么大不了的;它将在while() 循环的下一次迭代中被覆盖。如果要使用它,那么它已经被复制到目标数组s[] 中的必要位置。

    回答你的第二个问题,

    但是如果输入在开头有一个空格,然后是 操作数或运算符?

    请注意,先前的while() 循环可防止在退出循环后出现在s[0] 中的空白字符(空格和制表符)。因此,在执行后

    s[1] = '\0';
    

    s[] 字符串将包含一个既不是空格也不是制表符的单个字符,后跟一个字符串终止符。

    在下一个语句中

    if (!isdigit(c) && c != '.')
        return c; /* not a number */
    

    如果字符不是数字或小数点,函数将返回。这就是为什么必须终止字符串的原因。

    【讨论】:

    • 很好的解释,虽然我会删除诸如“方便”之类的积极形容词,因为这表明这个凌乱的 K&R 代码遵循某种良好的 C 编码实践,而实际上它充满了非常相反。
    • @Lundin:我完全同意,从“良好的编码实践”的角度来看,所讨论的 K&R 代码很糟糕,但该代码说明了 C 语言的某些新颖性,这对于新手学习很重要。从算法设计的角度来看,我相信从代码原作者的角度来看(早在今天的“良好编码实践”被构想出来之前),在代码中此时对 s[0] 的赋值是方便,因为以后不需要执行。
    【解决方案2】:

    但是如果输入的开头有一个空格,然后是一个操作数或运算符怎么办?在这种情况下,s[1] = '\0' 会过早关闭字符串吗?不是吗?

    不,

    i = 0;
    if (isdigit(c)) /* collect integer part */
        while (isdigit(s[++i] = c = getch()))
    

    这样可以确保,如果有要读取的内容,它将在\0 上被覆盖,因为i=0 和s[++i] 的意思是,存储在包含s[1] 的s[1] 中

    【讨论】:

    • 感谢回答我的第二个问题!对我的第一个问题有何评论?
    【解决方案3】:

    关于您的第一个问题:s[0] in:

    while ((s[0] = c = getch()) == ' ' || c == '\t')
    

    因为在 s[0] 中保存 'c' 有助于提前存储第一个数字,以便我们可以从简单的 i 等于 1 开始我们的下一个代码。

    i = 0;
    if (isdigit(c)) /* collect integer part */
        while (isdigit(s[++i] = c = getch()))
    

    上面的代码用于存储从索引 i = 1 开始的下一个字符串字符

    关于你的第二个问题:

    我们做不到

    s[0] = '\0';
    

    因为那时我们已经在 s[0] 处存储了字符串中的第一个数字

    见

    (s[0] = c = getch())
    

    【讨论】:

      【解决方案4】:

      这里给出的答案已经很好了,不过我想在第二个问题上再补充一点。 “好的。但是如果输入在开头有一个空格,然后是操作数或运算符怎么办?在这种情况下,s[1] = '\0' 会过早关闭字符串?不是吗?” 在这种情况下,我们根本不关心字符串(如果遇到数字,无论如何都会被覆盖),因为仅在遇到十进制数字时才使用字符串,其余字符,例如“+”或“-”或 '\n' 直接返回。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-10-11
        • 1970-01-01
        • 2018-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-11
        相关资源
        最近更新 更多