K& R - 第1.9节:理解字符数组(以及偶然的缓冲区)

时间:2016-02-06 16:38:27

标签: c arrays char

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

  • 每个字符数组都以' \ 0'?
  • 结尾
  • 对于' \ 0',它的长度是否总是等于字符数+ 1?
    • 意思是如果我指定的字符数组长度为10,那么我只能存储9个字符,而不是' \ 0'?
    • 或' \ 0'在最后一个数组插槽之后,所有10个插槽都可以用于任何字符,第11个不可到达的插槽将包含' \ 0'炭?

进一步深入本节的示例,它定义了一个getline()函数,该函数读取字符串并计算其中的字符数。 you can see the entire code here (in this example getline() was changed to gline(), since getline() is already defined in newer stdio.h libraries)
这里的功能:

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;
}

说明数组以这种方式存储输入:
[h][e][l][l][o][\n][\0]
该函数将返回6的计数,包括&#39; \ n&#39;焦炭, 但是只有当循环退出时才会出现这种情况,因为&#39; \ n&#39;焦炭。
如果循环因为达到了它的限制而退出,它将返回一个这样的数组(据我所知):
[s][n][a][z][z][y][\0]
现在伯爵也将是6。
比较两个字符串将返回它们在明确&#34;时髦&#34;时相等。是一个比#34;你好&#34;更长的词, 所以这段代码有一个错误(根据我的个人要求,因为我不想数&#39; \ n&#39;作为字符串的一部分)。

尝试解决这个问题,我尝试(在许多其他方面)尝试删除添加&#39; \ n&#39; char到数组而不是递增计数器, 我偶然发现当输入的字符多于数组可以存储的字符时,额外的字符在输入缓冲区中等待, 然后将传递给getline()函数,所以如果我输入:
&#34;时髦的lolz \ n&#34;
它会像这样使用它:
第一个getline()调用:[s][n][a][z][z][y][\0]
第二个getline()调用:[ ][l][o][l][z][\n][\0]

此更改还引入了一个有趣的错误,如果我尝试输入一个长度恰好为7个字符的字符串(包括&#39; \ n&#39;),程序将立即退出,因为它会通过&#39 ; \ 0&#39; char到下一个getline()调用,返回0并退出调用main()中getline()的while循环。

我现在很困惑下一步该做什么。 如何让它不计算&#39; \ n&#39; char还要避免它创建的bug吗?

非常感谢

2 个答案:

答案 0 :(得分:4)

C中有一个约定,字符串以空字符结尾。根据该惯例,您的所有问题都是基于的。所以

  • 每个字符数组都以&#39; \ 0&#39;?
  • 结尾

不,它以\ 0结束,因为程序员把它放在那里。

  • 对于&#39; \ 0&#39;,它的长度是否总是等于字符数+ 1?

是的,但仅仅是因为这个惯例。例如,你为字符串的长度分配了一个字节(字符),以容纳这个\ 0。

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

答案 1 :(得分:1)

  

每个字符数组都以'\ 0'结尾吗?

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

因此nul仅表示字符数组中字符串的结尾。如果字符数组表示字符串以外的数据,那么它可能在任何地方都包含零元素。

  

它的长度是否总是等于'\ 0'的字符数+ 1?

您再次将字符串与字符数组混淆。他们不一样。字符串碰巧使用字符数组作为容器。 字符串需要一个数组 至少字符串的长度加一。

  

意思是如果我指定的字符数组长度为10,那就是   能够只存储9个不是'\ 0'的字符?

您将能够存储任何值的10个字符。但是,如果您选择将数组解释为字符串,则该字符串仅包含那些字符,包括第一个空字符。

  

或'\ 0'是否位于最后一个数组插槽之后,因此所有10个插槽都可以   用于任何字符和第11个不可到达的插槽将包含   '\ 0'字符?

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

  

比较两个字符串将返回它们在清楚时是相等的   “时髦”是一个比“你好”更长的词,

这些字符串在什么世界中是平等的?它们具有相同的长度,而不是相同的内容。

  

所以这段代码有一个bug(根据我的个人要求,就像我一样   喜欢不把'\ n'算作字符串的一部分。)

其他人的代码没有做所要求的代码几乎不是一个错误;该实现是设计使然,与标准库fgets()函数的行为相同。如果您需要不同的行为,那么您当然可以自由地实现您的需求;只省略部分:

if (c == '\n') {
    s[i] = c;
    ++i;
}

要显式刷新缓冲区中的任何剩余字符,上面删除的代码可能会替换为:

while(c != '\n') {
    c = getchar() ;
}

您可能不这样做的一个原因是数据可能来自重定向到stdin的文件。

保留'\n'的一个原因是能够检测到不完整的输入,这在某些情况下可能很有用。例如,你可能想要行中的所有数据,无论长度如何,尽管必须有限的缓冲区长度,但是没有换行符返回的字符串将指示有更多的日期要读取,因此您可以编写代码来处理这种情况