一起在指针上使用前缀和后缀时的奇怪输出
Posted
技术标签:
【中文标题】一起在指针上使用前缀和后缀时的奇怪输出【英文标题】:Weird output when use prefix and postfix on pointer together 【发布时间】:2015-04-13 22:18:53 【问题描述】:给定下面的代码
char buf[] = "asfsf";
char *a=buf;
++*a++;
cout<<*a;
我希望结果是“s”的下一个字符,即“t”,但结果仍然是“s”。为什么?
为什么 ++*a++ 和
不一样*a++;
++*a;
cout<<*a;
这真的是 ++i++ 的重复问题吗?我知道 ++i++ 是一种未定义的行为,会导致编译错误,但 ++*i++ 实际上可以运行。我的情况也是未定义的行为吗?
【问题讨论】:
你应该使用const char *a="asfsf";
这不是一个骗子(至少是指定的副本)。这一个包括取消引用,这意味着两个增量应用于不同的对象(即,一个应用于a
,另一个应用于*a
)。这使得它与对同一个对象应用两个增量略有不同(但完全不同)。
你的代码应该被避免,即使它是明确定义的行为(不是)。它在我的系统(OS X)上出现Bus error: 10
故障(以及从字符串常量到char*
的不推荐转换的警告)
@vsoftco 它出错了,因为他正在写入只读内存(字符串文字)。 little modification 可能会在没有 ro-overreach 的情况下给出他所看到的内容..
@WhozCraig 同意,我使用的最大值仍然是 *a++
。不止一个 2 ++/*
运算符只会让阅读您的代码的人感到困惑。
【参考方案1】:
根据语言语法,运算符关联为:
++(*a++)
注意:关联性并不意味着操作的顺序。
*a++
计算为一个左值,指定a
最初指向的位置,具有修改a
的副作用。到目前为止一切都很好。
将前缀-++
应用于该左值会增加存储在那里的值(将'a'
更改为'b'
)。
虽然这两个增量是无序的,但这不会导致UB,因为不同的对象在增量,并且指定后一个位置的左值不依赖于增量。 (它使用旧值a
)。
【讨论】:
@bogdan 感谢您指出这一点。选项是++ cast-expression
和 postfix-expression ++
。但前者不会产生postfix-expression
,而后者会产生cast-expression
。【参考方案2】:
就目前而言,您的代码具有未定义的行为,因为它试图修改字符串文字的内容。
阻止编译器接受此类代码的一种方法(可能是首选方法)是定义您的a
,例如:
char const *a="asfsf";
这样,++*a
部分根本无法编译。
为了方便说明,我们稍微修改一下代码,变成:
#include <iostream>
int main()
char x[]="asfsf";
char *a = x;
++*a++;
std::cout<<x;
现在a
指向我们可以实际写入的内存,并获得有意义的结果。这将打印出bsfsf
。如果我们打印出a
,我们将得到sfsf
。
发生的情况是a++
增加了a
,但 仍然产生a
的原始值。即取消引用,引用x
的第一个元素。然后对其应用预增量,将其从 a
更改为 b
。
如果你想增加指针,取消引用结果,然后增加它,你可以使用:++*++a;
。好吧,不,你不会使用它——或者至少我希望你不会。它确实增加了a
以指向数组的第二个元素,然后增加第二个元素以将其从s
更改为t
——但是任何阅读代码的人都会被完全原谅,如果他们讨厌你的写作就这样吧。
【讨论】:
这对我来说很有意义。谢谢! 您能否详细说明为什么“a++
增加了a
但仍然产生a
的原始值”??
@Martund:这就是定义后增量要做的事情。例如,如果我执行以下操作: int i=0; printf("%d", i++); printf("%d", i);, it should print out
0 1. So the
i++`产生了i
的现有值(即0),但增加了i
,所以下次我们看它时,它值为 1。以上是关于一起在指针上使用前缀和后缀时的奇怪输出的主要内容,如果未能解决你的问题,请参考以下文章
在 C 中对于后缀和前缀运算符,操作数应该是一个左值,那么在这些运算符的情况下,左值对于指针变量的实际含义是啥?
关于字符串 “*****AB**C*D*****” 中前缀后缀和中间 '*' 的处理