为什么这个 C 程序在未连接的代码行被取消注释时检测字符串中的两个''字符?



我目前正在学习C,我编写了这个程序来检查"\0"字符是否真的在字符串的末尾,如"K和R"所示。

不过,我得到了最奇怪的结果。

如果我评论"int lista[] = {0, 1, 2, 3, 4};"程序的语句(这是一个与该程序的其他语句无关的语句,它是我将要进行的另一个测试的一部分)。 程序的输出按预期出现,检测到一个结束字符串的"\0"字符。 但是,如果我不注释该语句,程序输出会在字符串末尾检测到两个"\0">字符。 为什么会这样?

这是未注释语句的程序:

#include <stdio.h>
int main(void)
{
int lista[] = {0, 1, 2, 3, 4};
char string[] = "linhas";

for (int i = 0; i <= sizeof(string); i++)
{
if (string[i] != '')
{
printf("%cn", string[i]);
}
else
{
printf("this dawmn null charn");
}
}
}

这输出:

l
i
n
h
a
s
this dawmn null char
this dawmn null char

这是注释掉该行的程序:

#include <stdio.h>
int main(void)
{
/*int lista[] = {0, 1, 2, 3, 4};*/
char string[] = "linhas";
for (int i = 0; i <= sizeof(string); i++)
{
if (string[i] != '')
{
printf("%cn", string[i]);
}
else
{
printf("this dawmn null charn");
}
}
}

它输出:

l
i
n
h
a
s
this dawmn null char

你的循环

for (int i = 0; i <= sizeof(string); i++)

总是有点不对劲。 它应该是

for (int i = 0; i < sizeof(string); i++)

通过使用<=,您在循环中进行了一次过多的行程,并且您访问了string数组之外的内存。 看起来,在lista数组就位的情况下,您错误访问的额外字节(在string数组之外)恰好是 0,因此您会获得"this dawmn null char"消息的额外第二次打印输出。

但是,当您注释掉lista数组时,一定是您错误访问的额外字节不是 0,因此它被打印为自身。 它可能是一个不可见的控制字符,这就是为什么你看不到任何东西。 我建议将您的代码更改为

if (string[i] != '')
printf("string contains %dn", string[i]);
else printf("this damn null charn");

以更清楚地看到这一点。

这里重要的教训是,如果你有一个应该运行 N 次的循环,有两种方法可以编写它。 在 C 中,绝大多数时候,你想把它写成

for(i = 0; i < N; i++)

这是一个"从 0 开始"的循环,从 0 到 N-1 运行,总共 N 次行程。 偶尔,您需要一个从 1 开始的循环:

for(i = 1; i <= N; i++)

这从 1 到 N 运行,同样总共 N 次行程。 但是如果你写

for(i = 0; i <= N; i++)      /* usually WRONG */

您的循环从 0 到 N,总共 N+1 次行程。

不要混淆strlen(string)在您的情况下哪个应该是6sizeof(string)哪个是数组的大小,包括''字节! ;-)

在声明为具有"自动大小"的数组的字符串的情况下,差异只有一个,但如果你有char string[256]sizeof(string)就不一样了,strlen(string) + 1

有了char *stringsizeof(string)可能会84

@SteveSummit详细解释了所有内容。这是一个简短的答案。

访问元素lista[sizeof(lista)]是未定义的行为,因此讨论它应该具有什么价值是"毫无意义的"。我引用了毫无意义的,因为出于调试目的,了解未定义的行为如何表现自己可能是一件好事。但是,如果此代码要投入生产,则永远不应访问lista[sizeof(lista)]。它总是越界,总是一个错误。

最新更新