【问题标题】:In K&R 1.9 longest line example, what is getchar() doing?在 K&R 1.9 最长线示例中,getchar() 是做什么的?
【发布时间】:2013-03-28 23:45:39
【问题描述】:

我现在似乎理解了这个程序,除了 getline 函数不是很直观,因为它似乎复制了所有 getchar() 返回到一个字符数组 s[] 从来没有真正用于任何重要的事情。

int getline(char s[], int lim)
{
    int c, i;
    for(i=0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
        s[i] = c;
    if(c == '\n')
    {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';
    return i;
}

该函数可以很容易地忽略s[i] = c; 这一行,因为该函数实际上所做的只是计算字符数,直到它到达EOF'\n'getchar() 返回

我真正不明白的是为什么程序向前推进,因为主循环如下:

main()
{
    int len; /* current line length */
    int max; /* maximum length seen so far */
    char line[MAXLINE]; /* current input line */
    char longest[MAXLINE]; /* longest line saved here */

    max = 0;
    while ((len = getline(line, MAXLINE)) > 0)
        if (len > max)
        {
            max = len;
            copy(longest, line);
        }
    if (max > 0) /* there was a line */
        printf("%s", longest);
    return 0;
}

唯一的解释是getchar() 函数在用户输入一整行文本并按下enter 键后发挥作用。所以它似乎在运行时工作是我的猜测。

程序是这样进行的吗?程序是不是先进入while循环,然后等待用户输入一行文本,一旦用户敲回车,getline函数的for循环就被迭代了?我觉得会是这样,因为用户可以在输入过程中输入 backspace

我的问题是,该计划到底进展如何?都是因为getchar()函数吗?

当我在终端中点击 ctrl-D 时,会发生其他一些令人困惑的事情。如果我在换行符的开头点击 ctrl-D,程序将终止。如果我在填充了一些文本的行的末尾点击 ctrl-D,它不会终止,并且它的行为方式与点击 enter。如果我在一行文本中按几次 ctrl-D,程序最终将结束。

这只是我的终端处理会话的方式,还是如果我只想学习 C,我不应该担心这些事情?

我问的原因是我喜欢跟踪程序以更好地理解它,但是getchar() 函数让这很棘手。

【问题讨论】:

    标签: c kernighan-and-ritchie


    【解决方案1】:

    在参数声明中(在该上下文中),char s[] 真正意味着char *s。 C 标准对此的描述方式是:

    将参数声明为“类型的数组”应调整为 "合格的指针 类型”。

    所以s 确实是一个指针,类型为char*,并且当函数修改s[i] 时,它正在修改lineith 元素。

    通话中:

    getline(line, MAXLINE)
    

    line 是一个数组,但在大多数情况下,数组表达式会隐式转换为指向数组第一个元素的指针。

    这两条规则似乎是一个阴谋的一部分,它看起来像数组和指针在 C 中实际上是相同的东西。它们绝对不是。指针对象包含某个对象的地址(或不指向任何对象的空指针);数组对象包含有序的元素序列。但是在 C 中,大多数数组的操作都是通过指向数组元素的指针来完成的,指针算法用于从一个元素前进到下一个元素。

    推荐阅读(我说了很多):comp.lang.c FAQ 的第 6 部分。

    【讨论】:

    • +1 表示正确答案,基本上是我所说的解决 OPs 问题的方法,但文档要好得多。
    【解决方案2】:

    getchar 从标准输入中读取一个字符。所以如果你坐在终端上,它会阻塞程序,直到它接收到你输入的字符,然后它就完成了。但是标准输入在交互时是行缓冲的,因此在您按下回车之前,程序不会处理您键入的内容。这意味着getchar 将能够继续读取您键入的所有字符,因为它们是从缓冲区中读取的。

    你对函数有误解。数组被传递给函数*,它将getchar 读取的每个字符(EOF 或换行符除外)存储在连续的元素中。这就是它的重点 - 不是计算字符数,而是将它们存储在数组中。

    (*实际上传递了一个指针,但是这里的函数仍然可以把它当作一个数组来处理。)

    【讨论】:

    • 谢谢,我现在明白了。但现在我对程序如何结束感到困惑。为什么按 Ctrl-D 与按 Enter 不一样?
    • 这取决于您的系统使用 Ctrl-D 执行的操作。有时您必须按两次才能发送 EOF。
    • 数组“传递给函数”并不完全正确。实际传递的(按值,因为所有 C 参数都传递)是指向数组第一个元素的指针。
    • @KeithThompson - 我只是让解释尽可能简单。由于该函数将其视为一个数组,因此我认为不需要引入指针。
    • @teppic:你可以暂时摆脱这种假设,但最终你会想知道s[] 有多大,为什么sizeof s 给你一个大小指针。 (我并不是说你不明白这一点。)严格来说,该函数将s 视为指针; [] 运算符是根据指针算法定义的。
    【解决方案3】:

    数组 用于重要的事情:它由调用者提供并返回修改后的新内容。从合理的角度来看,填充数组是调用函数的目的。

    【讨论】:

      【解决方案4】:

      那个数组(数组引用)其实是一个指针,char s[]和char *s是一样的。所以它在那个数组中构建它的结果,这就是它稍后在 main 中复制的原因。 K&R 中很少有“魔法”。

      【讨论】:

      • -1:数组不是指针,指针不是数组。我建议你阅读comp.lang.c FAQ 的第 6 部分。
      • 好的,现在我明白 getline 函数的真正作用了。但是,getchar() 函数是否也会像我怀疑的那样通过输入导致程序的进度?我只是对程序如何知道开始阅读新事物感到有点困惑。但是getchar() 函数会随着任何新输入逐步向前移动程序是有意义的。但是,我对程序如何终止感到有些困惑。
      • @pmg 读取 K&R 的 A7.3.1,数组引用,数组不是指针而是对它们的引用,并且该数组是数组引用。
      • 我撤销了 -1,但数组不是指针——在许多用法中,它们会转换为指向其第一个元素的指针。
      • 数组不是指针,而是在参数声明的上下文中(在那个上下文中),char s[] 真正的意思是char *s
      猜你喜欢
      • 2010-11-22
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 2015-06-17
      • 1970-01-01
      • 1970-01-01
      • 2010-10-09
      相关资源
      最近更新 更多