让我们从一个关于字符数组的基本问题开始,我从书中的描述中无法理解:
进一步深入本节的示例,它定义了一个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吗?
非常感谢
答案 0 :(得分:4)
C中有一个约定,字符串以空字符结尾。根据该惯例,您的所有问题都是基于的。所以
不,它以\ 0结束,因为程序员把它放在那里。
是的,但仅仅是因为这个惯例。例如,你为字符串的长度分配了一个字节(字符),以容纳这个\ 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'
的一个原因是能够检测到不完整的输入,这在某些情况下可能很有用。例如,你可能想要行中的所有数据,无论长度如何,尽管必须有限的缓冲区长度,但是没有换行符返回的字符串将指示有更多的日期要读取,因此您可以编写代码来处理这种情况