指针算术:++*ptr 还是 *ptr++?

22

我正在学习 C 语言,但是对 ++*ptr*ptr++ 之间的区别感到相当困惑。

例如:

int x = 19;
int *ptr = &x;

我知道++*ptr*ptr++会产生不同的结果,但我不确定为什么会这样?

3个回答

54

这些语句产生不同的结果是因为运算符绑定的方式不同。特别地,前缀++运算符与*具有相同的优先级,并且它们从右到左结合。因此

++*ptr

被解析为

++(*ptr)

意思是“递增指针ptr所指向的值”。另一方面,后缀++操作符比解引用运算符*的优先级高,因此

*ptr++

意思是

*(ptr++)
这意味着“将ptr增加到指向其后面的元素,然后解除引用其旧值”(由于后缀 ++ 返回指针以前拥有的值)。
在您描述的上下文中,您可能希望编写++*ptr,它将通过ptr间接递增x。编写*ptr++会很危险,因为它会在x之后前进ptr,并且由于x不是数组的一部分,指针将在内存中悬挂(也许在自身之上!)
希望能对你有所帮助!

@templatetypedef我认为和++的优先级是相同的,但由于它们的结合性是从左到右,所以会出现这种情况。当你说"++比绑得更紧"时,你是指这个意思吗? - Algorithmist
*ptr++ 相当于 *(ptr++) 相当于 *(ptr = ptr + sizeof(datatype)) - instinct
如果您的指针指向一个字符串并且您想跳转到字符串中的下一个字符,那么*ptr++会非常有用。 - jAYANT YADAV
3
@instinct:不,后一种形式甚至远远不能等同于*(ptr++) - AnT stands with Russia
1
指针算术运算考虑到所指向类型的大小,因此 ptr + sizeof(datatype) 实际上会移动 sizeof(datatype) * sizeof(datatype) 字节。请参见此示例。 [注意:由于 -xc 命令行选项,示例编译为 C 而不是 C++。] - Justin Time - Reinstate Monica
显示剩余4条评论

14
接受的答案是不正确的。后缀 ++ 运算符的优先级与取消引用/间接寻址 * 不同。前缀和后缀运算符具有不同的优先级,只有前缀运算符与取消引用/间接寻址具有相同的优先级。
优先级表格所示,后缀 ++ 比取消引用/间接寻址 * 的优先级。因此* ptr++ 被计算为 *(ptr++)ptr ++ 评估为ptr的当前值;它仅作为副作用递增ptr。表达式的值与ptr的当前值相同。因此,它不会对指针存储的值产生任何影响。它只会取消引用指针(即获取存储在其中的当前值(即19)),然后推进指针。在您的示例中,在ptr的新位置上没有定义的存储值,因此指针指向垃圾。现在解除引用它将是危险的。
同样,正如表格所示,前缀 ++ 与取消引用/间接寻址 * 具有相同的优先级,但由于右-左结合性,它被计算为 ++ (* ptr)。这将首先解除引用指针(即获取在地址指向的值),然后递增该值。即,值现在为20。
关于两者的影响,接受的答案是正确的,但实际机制与给出的机制不同。

这是比所选答案更好的答案。此外,优先级表中的注2解释了为什么ptr++会被计算为ptr - fnisi
*ptr 返回一个左值。因此 ++*ptr 将绝对修改指针 ptr 所指向的对象(x)的值。 - giusti
必看的Linux内核演示 - giusti
@giusti 哎呀,你说得对。当然,抱歉和谢谢。已编辑。困乏的大脑在几个月来完全准确的答案中引入了一个错误。 - verbose

4
正如templatetypedef所说,但是你应该在*ptr周围提供括号以确保结果。例如,以下在我的计算机上使用GCC生成1606415888,而使用CLang生成0:
int x = 19;
int *ptr = &x;
printf("%d\n", *ptr++);
printf("%d\n", *ptr);

你期望x的值为20。因此请使用(*ptr)++


你不觉得第一个 printf() 应该打印 19 吗? - Algorithmist

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