当未连接的代码行取消注释时,为什么此 C 程序会检测到字符串中的两个“\0”字符?

flo*_*jdt 2 c string null sizeof

我目前正在学习 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] != '\0')
        {
            printf("%c\n", string[i]);
        }
        else
        {
            printf("this dawmn null char\n");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这输出:

l
i
n
h
a
s
this dawmn null char
this dawmn null char
Run Code Online (Sandbox Code Playgroud)

这是注释掉该行的程序:

#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] != '\0')
        {
            printf("%c\n", string[i]);
        }
        else
        {
            printf("this dawmn null char\n");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它输出:

l
i
n
h
a
s
this dawmn null char
Run Code Online (Sandbox Code Playgroud)

Ste*_*mit 5

你的循环

for (int i = 0; i <= sizeof(string); i++)
Run Code Online (Sandbox Code Playgroud)

是非常轻微的错误。它应该是

for (int i = 0; i < sizeof(string); i++)
Run Code Online (Sandbox Code Playgroud)

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

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

if (string[i] != '\0')
     printf("string contains %d\n", string[i]);
else printf("this damn null char\n");
Run Code Online (Sandbox Code Playgroud)

为了更清楚地看到这一点。

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

for(i = 0; i < N; i++)
Run Code Online (Sandbox Code Playgroud)

这是一个“从 0 开始”的循环,从 0 运行到 N-1,总共 N 趟。有时,您需要一个基于 1 的循环:

for(i = 1; i <= N; i++)
Run Code Online (Sandbox Code Playgroud)

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

for(i = 0; i <= N; i++)      /* usually WRONG */
Run Code Online (Sandbox Code Playgroud)

您的循环从 0 运行到 N,总共 N+1 趟。