【问题标题】:K&R answer book - exercise 1.16 - getline functionK&R 答案簿 - 练习 1.16 - getline 函数
【发布时间】:2013-12-28 17:08:53
【问题描述】:

“修改最长行程序的主程序,使其正确打印任意长输入行的长度,并尽可能多地打印文本。”

这是练习 1.16 的 K&R 答案簿中的完整代码:

#include <stdio.h>
#define MAXLINE 1000

int getline (char line[], int maxline);
void copy (char to[], char from[]);
main()
{


int len;
int max; 
char line[MAXLINE];
char longest[MAXLINE];

max = 0;
while ((len = getline(line, MAXLINE)) > 0 ){
    printf("%d %s", len, line);
    if (len >max){
        max = len;
        copy (longest, line);
    }
}
if (max > 0)
    printf("%s", longest);

getchar();
return 0;
}
int getline(char s[], int lim)
{
int c, i, j;

j = 0;
for (i = 0; (c = getchar()) != EOF && c != '\n'; ++i)
    if (i < lim-2){
        s[j] = c;
        ++j;
    }
    if (c == '\n'){
        s[j] = c;
        ++j;
        ++i;
    }
    s[j] = '\0';
    return i;
}
void copy (char to[], char from[])
{
int i;

i = 0;
while ((to[i] = from[i]) != '\0')
    ++i;
}

看看getline函数,下面这行用lim-2代替lim-1的目的是什么:

if (i < lim-2){

这似乎根本没有任何目的。 '\0' 字符标记不应该出现在 s[lim] 而不是 s[lim-1] 或 s[lim-2]?

此外,如果超过字符限制,该函数将跳过最新的字符,直到找到换行符,并将换行符添加到 char 字符串,但跳过下一个“适合”字符来自过程中的输入流。这是什么目的?

我不太确定作者在这里的意图是什么,这本书也没有提供任何解释。

edit:使用诸如 line[5] 之类的数组,我的印象是字符数组中的 NULL 字符在 line[5] 中,我们可以在数组下标 0-4 中放入一些东西。这个假设是错误的吗?

【问题讨论】:

  • '\0'和'\n'需要减2。
  • 数组长度被指定为“limit 总单位(字节)”。索引从array[0]array[limit-1]。在这种情况下,s[lim-1] 需要保存'\0' 字节。请注意,POSIX 现在有一个 getline() 函数,其原型与 K&R 中的 getline() 完全不同。

标签: c


【解决方案1】:

这似乎根本没有任何目的。 '\0' 不应该 字符标记出现在 s[lim] 而不是 s[lim-1] 或 s[lim-2]?

没有。 lim 是缓冲区的大小,因此数组的最后一个索引是 lim-1。 该代码使用lim-2,因为它为结束字符串字符 ('\0') 和新行 ("\n") 保留空间。

此外,该函数会跳过最新的字符(如果出现) 超过字符限制,直到找到一个换行符,并且它 将换行符添加到 char 字符串,但跳过任何 来自过程中输入流的下一个“适合”字符。 这是什么目的?

getline 函数读取输入字符串,该字符串分成大小为 MAX_LINE 的不同块,然后将这些块复制到 longest 缓冲区中。由于longest 缓冲区的大小是固定的,因此可以打印的字符串的最大长度为 MAX_LINE(即只有第一个块)。因此,longest 缓冲区的大小是您可以打印出的字符串的真正限制,即使您在输入中插入更长的字符串也是如此。该练习包括使longest 缓冲区动态化,以便应用程序能够读取和打印任意长字符串。您必须使用动态内存,因为您不知道输入字符串的大小。一种可能的解决方案是将每个块保存到一个临时缓冲区中,当所有缓冲区都在内存中时,您可以计算输入字符串的大小,然后将所有块复制到一个新缓冲区中,其大小是输入字符串的长度。

【讨论】:

  • 对不起,这有点晚了,但是当你说“练习包括使最长的缓冲区动态化以便应用程序能够读取和打印任意长串。”我猜如果缓冲区是动态的,也就是不固定的,那么我就不必担心缓冲区的大小,但这不是练习要做的。您还说过以下内容:“您必须使用动态内存,因为您不知道输入字符串的大小。”您是说鉴于目前我必须使用的工具并需要动态内存分配,我的选择有限?
【解决方案2】:

是的,我只是碰巧读了同一页,也很困惑。我认为只有在以下情况下才会出现问题:

1。输入行超过lim;

2。输入行直接以 EOF 结束,没有换行符 \n

因此它只保存直到s[lim-3] 的有意义的字符,将\0 放入s[lim-2] 并留下s[lim-1] 未使用。

但是在实践中(我使用的是 OSx),EOF 只能通过在行首键入 control-D 来触发 - 这意味着所有行都以 \n 结尾(尤其是最后一行)。所以无论是否超过lim,最后保存在s[]中的最后两个字符总是\n\0

当输入是一些文件主干而不是终端上的输入时,您可以阅读以下内容:Why should text files end with a newline?,我今天也找到了,我认为这两个问题高度相关。

希望我的回答有帮助! :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    • 2015-01-14
    • 1970-01-01
    相关资源
    最近更新 更多