博客题目也许有些奇怪:{*s++ += 7} != {*s++ = *s++ + 7}
先看一下代码,一个小问题:
#include<stdio.h>
int *f(int *s)
{
s += 1;printf("%p\n",s);
s[1] += 6;
*s++ +=7;
printf("%p\n",s);
return s;
}
main()
{
int a[5]={1,2,3,4,5},*p;
printf("%p,%p,%p,%p,%p\n",&a[0],&a[1],&a[2],&a[3],&a[4]);
p=f(&a[1]);
printf("%d,%d,%d,%d\n",a[1],a[2],*p,p[1]);
}
运算结果:
现在这个代码的运行结果似乎有疑问,与预算的不相同。
我们主要的关注对象是*s++ += 7部分,代码作用不解释了。
我们先看着个问题:
int sum=0;
sum += 3;
首先想到的是:sum += 3; 等价于sum = sum + 3;
这显然没有问题,优先处理的是+=运算符,将其拆开还原即可。
回到问题*s++ += 7上,运算符出现了:++(右自增),*(取值),+=三种。
通常根据C语言的运算符知识会作出如下思考:优先级中++ 优于 * 优于 += ,所以在处理*s++ += 7时首要考虑的是++运算符而不是+=。
*s++ += 7;等价于*(s++) += 7;
(s++)先取值在加一,可能在本题中会有人想到*s++ += 7;中的可以思考如下:
*(s++) += 7;中先使用s的值(s的值是一个地址),之后进行*s的取值,然后++发挥作用使得*s的值加一,最后再到+=的运算符,将式子还原。可以发现其中的问题是:++发挥作用使得*s的值加一,加一后的式子变成了:常数 += 常数 ;
显然这种式子是不被C语言所允许的,但是本文开始出就已经给出了程序的运算结果,说明代码没问题!
现在思考出错的原因,显然思路在加一的操作后出了错误,现在给出合理的解释(这里只是猜想):
*(s++) += 7;
①先处理(s++),对s的态度是先使用s的值;
②*(s)取值;
③*(s)取值后不进行 ++ 原本的加一行为,而是执行+=操作符:
④原式变为:( s指针往右加一 )= *s + 7 ;
⑤结果是:原地址对应的值执行+7,+7后将结果10赋给地址,地址只是往后移动一次。
解释右侧写为(s指针往右加一 )的原因:s++先是使用s的地址,在等待s的地址加一,由于上面②③操作使得加一操作未能得到执行,因此将其后续操作放在等式的左边。
以上的猜测过程完整的解释了开始的代码运行结果。
猜想的作用与验证思路:①是解释问题的原因②解释原因后使用猜想的方法进行预测③实验验证
现在进行预测:
将开始代码修改,将*s++ +=7; 改为*s++ *=7; 其余部分不变
代码:
#include<stdio.h>
int *f(int *s)
{
s += 1;printf("%p\n",s);
s[1] += 6;
*s++ *=7; //还可以改为 -=;/=;%=
printf("%p\n",s);
return s;
}
main()
{
int a[5]={1,2,3,4,5},*p;
printf("%p,%p,%p,%p,%p\n",&a[0],&a[1],&a[2],&a[3],&a[4]);
p=f(&a[1]);
printf("%d,%d,%d,%d\n",a[1],a[2],*p,p[1]);
}
预测结果:2,21,10,5
实际运行结果是:
预测与实际运行结果相同,猜想正确。因此以后遇见*s++ += 7类似问题时就可以按猜想的过程解决。
PS:由于本人能力有限,文中出现错误的地方希望能得到大家的指正,谢谢!