C K&;R-第1.9节:理解字符数组(以及附带的缓冲区)

C K&;R-第1.9节:理解字符数组(以及附带的缓冲区),c,arrays,char,C,Arrays,Char,让我们从一个关于字符数组的非常基本的问题开始,我无法从书中的描述中理解这个问题: 是否每个字符数组都以“\0”结尾 它的长度是否始终等于“\0”的字符数+1? 这意味着,如果我指定字符数组长度为10,我将只能存储9个不是“\0”的字符 还是“\0”位于最后一个数组插槽之后,因此所有10个插槽都可以用于任何字符,而第11个不可访问的插槽将包含“\0”字符 进一步讨论本节中的示例,它定义了一个getline()函数,用于读取字符串并计算其中的字符数。 下面是函数: int getline(c

让我们从一个关于字符数组的非常基本的问题开始,我无法从书中的描述中理解这个问题:

  • 是否每个字符数组都以“\0”结尾
  • 它的长度是否始终等于“\0”的字符数+1?
    • 这意味着,如果我指定字符数组长度为10,我将只能存储9个不是“\0”的字符
    • 还是“\0”位于最后一个数组插槽之后,因此所有10个插槽都可以用于任何字符,而第11个不可访问的插槽将包含“\0”字符
进一步讨论本节中的示例,它定义了一个getline()函数,用于读取字符串并计算其中的字符数。
下面是函数:

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;
}
intgetline(字符s[],intlim){
int c,i;
对于(i=0;i
据解释,数组以这种方式存储输入:
[h][e][l][l][o][\n][\0]

函数将返回6的计数,包括'\n'字符, 但这仅在循环由于“\n”字符而退出时才是正确的。
如果循环因达到极限而退出,它将返回如下数组(据我所知):
[s][n][a][z][z][y][\0]

现在计数也将是6。
当“snazzy”明显比“hello”长时,比较两个字符串将返回它们相等的结果, 所以这段代码有一个bug(根据我个人的要求,因为我不想将“\n”作为字符串的一部分)

为了解决这个问题,我尝试(除其他外)删除将“\n”字符添加到数组中而不增加计数器, 我顺便发现,当输入的字符超过数组所能存储的字符数时,多余的字符会在输入缓冲区中等待, 稍后将传递给getline()函数,因此如果我输入:
“时髦的lolz\n”
它会像这样用完:
第一个getline()调用:
[s][n][a][z][y][\0]

第二个getline()调用:
[[l][o][l][z][\n][\0]

此更改还引入了一个有趣的错误,如果我尝试输入一个长度正好为7个字符(包括“\n”)的字符串,程序将立即退出,因为它将向下一个getline()调用传递“\0”字符,该调用将返回0,并将退出main()中调用getline()的while循环

我现在不知道下一步该怎么办。 如何使它既不计算'\n'字符,又能避免它创建的错误

非常感谢

在C语言中有一个惯例,字符串以空字符结尾。根据这个惯例,你所有的问题都是以这个为基础的。所以

  • 是否每个字符数组都以“\0”结尾
不,它以\0结尾,因为程序员将它放在那里

  • 它的长度是否始终等于“\0”的字符数+1
是的,但只是因为这个惯例。例如,您分配的字节(char)比字符串长度多一个,以适应此\0

字符串存储在字符数组中,例如
chars[32]
char*s=malloc(strlen(name)+1)

是否每个字符数组都以“\0”结尾

没有;字符串是一种特殊情况-它们是带有nul(
\0
)终止符的字符数组。这与其说是语言的一个特性,不如说是一种约定,尽管它是语言的一部分,因为文字常量字符串有一个nul终止符。此外,在字符串中,nul出现在字符串的末尾,而不是数组的末尾-包含字符串的数组可能比它包含的字符串长

因此nul仅表示字符数组中字符串的结尾。如果字符数组表示字符串以外的数据,则它可能在任何位置包含零个元素

它的长度是否始终等于“\0”的字符数+1

再次将字符串与字符数组合并。它们不一样。字符串恰好使用字符数组作为容器。字符串要求数组的长度至少等于字符串的长度加1

这意味着,如果我指定字符数组长度为10,则 只能存储9个不是“\0”的字符吗

您将能够存储任意值的10个字符。但是,如果选择将数组解释为字符串,则该字符串仅包含第一个nul字符之前的字符

还是“\0”位于最后一个阵列插槽之后,因此所有10个插槽都可以 用于任何字符,并且第11个不可访问的插槽将包含 “\0”字符

nul位于字符串的末尾,而不是数组的末尾,当然也不在数组的末尾之后

比较这两个字符串将返回它们相等的结果 “时髦”比“你好”长

在什么世界上这些弦是相等的?它们的长度相等,而内容不相等

因此,这段代码有一个bug(根据我的个人需求,我会这样做) 不将“\n”作为字符串的一部分)

其他人的代码不能满足您的要求,这几乎不是一个bug;该实现是经过设计的,与标准库函数的行为相同。如果你需要不同的行为,那么你当然可以根据自己的需要自由实施;省略这一部分:

if (c == '\n') {
    s[i] = c;
    ++i;
}
要显式刷新缓冲区中的任何剩余字符,可将上面删除的代码替换为:

while(c != '\n') {
    c = getchar() ;
}
您可能不这样做的一个原因是数据可能来自重定向到stdin的文件

保留
'\n'
的一个原因是允许检测不完整的输入,这在某些情况下可能很有用。例如,您可能需要所有的d