问题描述
对于以下示例代码;
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;
}