C-char *数组的最后一个元素

问题描述

对于以下示例代码

render()

由于tmp在循环中指向g_commands数组中的指针,所以在将gfcommands [1]赋给“ efg”之后,由于g_commands的最后一个元素不再为null,因此我希望循环会产生分段错误。但是程序无一例外地完成并成功打印了abcdefg。

为什么会这样?编译器也将NULL添加到char *数组的末尾吗?

解决方法

我希望循环会产生分段错误,因为g_commands的最后一个元素不再为null。但是程序无一例外地完成并成功打印了abcdefg。

为什么会这样?编译器也将NULL添加到char *数组的末尾吗?

在取消指向指向数组末尾的指针tmp的指针的引用时,调用undefined behavior,并尝试使用printf("%s",*tmp)打印不确定的字符串。

未定义的行为不需要提供错误的结果。认为事物正确时认为事物正确是一种误解。

您什么都不能期待。解释未定义行为的原因和方式也没有太大意义,因为这与编写生产代码完全无关。

我认识一些人,他们喜欢研究这些问题并了解实现的行为,但通常来说,如果您对编写不敏感,可移植和可靠的代码感兴趣,那么这些并不是更需要关注的事情。

,

该程序具有未定义的行为。特别是,这意味着程序可以产生预期或意外结果。

我希望自最后一个元素以来,循环会产生分段错误 的g_commands不再为空

由于数组g_commands

,该程序可以正常运行而不会产生分段错误
char* g_commands[]={
    "abcd",NULL
};

是在全局名称空间中定义的,数组之后没有对象的其他定义。这样的声明具有静态的存储持续时间,编译器通常将此内存设置为零。

如果要在main之类的位置移动定义

#include <stdio.h>
/*
char* g_commands[]={
    "abcd",NULL
};
*/
int main()
{
    char* g_commands[]={
        "abcd",NULL
    };
    
    g_commands[1] = "efg";
    
    char ** tmp = &g_commands[0];
    
    for(; *tmp != NULL; tmp++){
        printf("%s",*tmp);
    }

    return 0;
}

然后发生分段错误的可能性非常高。

,

让我们逐步进行一下。

char* g_commands[]={
    "abcd",NULL
};

int main()
{
    
    g_commands[1] = "efg";

在这一点上,g_commands已更改,就像您通过以下方式将其初始化一样:

// char* g_commands[]={
//    "abcd",//    "efg"
// };

请注意,从这一点开始,g_commands中不再有终止的空指针。

以下

    char ** tmp = &g_commands[0];

也可以写成

// char ** tmp = g_commands;

现在,当您遍历g_commands的元素时,您正在测试是否引用了空指针的tmp。不幸的是,您之前确实使用非空指针覆盖了g_commands的最后一个元素,所以

    for(; *tmp != NULL; tmp++){
        printf("%s",*tmp);
    }

正在超出数组的范围,并调用了未定义的行为。

    return 0;
}