这是Coursera的一个测验(未评分)。问题是,以下代码可能评估的内容是什么?正确的答案是127和0(其他选项崩溃,-1,128。为什么以下代码可能评估为0?我理解为什么它会评估为127.它是否就像char字节未初始化一样简单因此是否可以评估0到127之间的任何#?
int foo(void) {
char bar[128];
char *baz = &bar[0];
baz[127] = 0;
return strlen(baz);
}
答案 0 :(得分:5)
代码的行为是 indeterminate 。我的意思是答案可以是0到127之间的任何内容。
strlen
将读取未初始化的内存,但不包括bar[127]
,将作为终止条件。
但是因为该数组由char
元素组成,所以读取这些数据不是未定义,因为char
类型不能有陷阱表示。只是它们包含不确定的值。
(如果bar
有静态存储持续时间,那将是完全不同的事情。然后答案总是为零。)
下面的大部分评论都是对这个答案的错误表述作出反应,表明行为未定义。
答案 1 :(得分:5)
以前这个答案有错误的信息,这个案例不会调用undefined behavior。
编辑回答:
TL; DR 我们无法得到确定的答案,代码包含不确定行为。
详细说明,char bar[128];
是一个自动局部变量,如果没有明确初始化,将包含不确定值。
引用C11
,章节§6.7.9
如果没有显式初始化具有自动存储持续时间的对象,则其值为 不定。 [....]
在您的代码中,您只为索引127处的数组的一个成员分配了值。剩余的元素仍然具有不确定的值。
尝试将该数组(基本上是指向数组的第一个元素的指针)传递给strlen()
,导致读取这些值(搜索空终结符)和由于不确定的值,无法保证它会在任何特定的位置找到空终止符。
所以,这个问题没有明确答案。
注意: (弥补我的错误理解,以防止读者进一步陷入同一陷阱)
这里,读取未初始化的值(即不确定的值)不会调用未定义的行为,正如人们所想的那样。
一个班轮:对象的地址。
有关此主题的详细讨论,请参阅here。
答案 2 :(得分:1)
有两件事可以使这个代码UB,如列出的here。这是一个具有自动存储持续时间且具有地址的变量,因此第一种情况肯定不适用。
根据陷阱表示的定义,不允许变量保存陷阱表示C11 6.2.6.1/5强调我的:
某些对象表示不需要表示的值 对象类型。如果对象的存储值具有这样的值 表示,并由没有的左值表达式读取 字符类型,行为未定义。如果这样的表示是 由副作用产生,修改对象的全部或任何部分 通过左值表达式,没有字符类型, 行为未定义.50)这种表示称为陷阱 表示。
这意味着该数组包含未指定的值。这种未指定值的一种情况可能是值0,在数组中的任何位置,被视为空终止符。