向数组指针中添加和删除元素

3

我很偶然地看到了这个问题,它要求找出以下代码的输出结果 -

char abc[14] = "C Programming"; 
printf("%s", abc + abc[3] - abc[4]);

我真的不明白输出是怎么来的 - 编程,有人能解释一下吗?


3
这在技术上属于未定义行为,因为加法超出了范围,但我从来没有见过它导致问题。 - chris
1
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - chris
@chris 错了。发生的是三个数字的简单算术运算:abc 指针(一个整数)、abc[3](一个整数)和 abc[4](一个整数)。这个整数被推到 printf 调用的堆栈上。没有任何越界的数组引用。 - Kenney
5
@Kenney,不必进行解引用。如果指针操作数和结果都指向同一数组对象的元素或该数组对象的最后一个元素之后,则评估不应产生溢出;否则,行为未定义。(N1570 §6.5.6/8,但据我所知,在C和C++的每个标准版本中都以某种形式存在) - chris
@ul90 没问题...如果你写的代码未来不再使用。 - bolov
显示剩余8条评论
3个回答

5

虽然不太明显,但是代码展示了未定义行为。这是因为先进行了加法运算,导致指针超出了abc的边界,这是未定义的行为,即使没有解引用也是如此。"正确"的方法应该先进行减法运算。

char abc[14] = "C Programming"; 
printf("%s", abc + (abc[3] - abc[4]));

即使如此,结果也不会是确定的,因为没有保证字符使用ASCII编码。但由于ASCII广泛使用,我们将忽略这一点。其他答案解释了代码背后的“黑魔法”,所以我在这里不再重复。

2
abc[3]abc[4]只是char'r''o'。它们可以像其他整型一样使用。 'r'的值通常只是字符r的ASCII值。
因此,abc + abc[3] - abc[4]并不神奇,只是指针算术运算。
然而,在这段代码中,abc + abc[3]已经超出了索引范围,所以该代码无效。

2
@Kenney 仅仅使用 abc + abc[3] 形成指针是未定义行为,因为它并没有指向数组。然而,在实践中,它在所有明智的架构上都可以正常工作。 - Quentin
1
@Kenney 但是运算符结合规则指定了最左边的加法(或减法)先进行。例如, abc[3] - abc[4] + abc 不会触发 UB。 - Quentin
你不能忽略表达式的一部分,来描述关于该表达式的任何信息。 - Kenney
2
@Kenney 是的,我们可以这样做,因为另一部分本身就是一个表达式。这会触发未定义行为。 - Quentin
1
@Kenney 我们这样来看,你就能明白这确实是未定义行为:std::numeric_limits<long long>::max + 10 - 11。这就是一个例子。 - bolov
显示剩余2条评论

2
abcabc[14]数组的起始地址(即abc[0]的地址)。 abc[3]是数组中的第4个元素,即字符rabc[4]是数组中的第5个元素,即字符o。字符r的ASCII值为114,字符o的ASCII值为111,因此您需要将数组指针加上3(即114-111)。 您的输出应该是“rogramming”。 但是,正如评论中所述,这样做非常不好的编程风格,并且可能导致未定义的行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接