C语言杂谈(二)自增运算符++与间接访问运算符*的结合关系和应用模式
2016-03-16 00:17
323 查看
自增运算符++有前缀和后缀两种,在搭配间接访问运算符*时,因为顺序、括号和结合关系的影响,很容易让人产生误解,产生错误的结果,这篇文章来详细分析一下这几种运算符的不同搭配情况。
++、--和*的优先级顺序
在C语言运算符的优先级顺序中,后缀的++和--运算符运算优先级16,结合关系是从左到右;简介访问运算符*、前缀++和--运算符运算优先级15,结合关系是从右到左。根据这个关系,可以分析出不同情况下的应用。为了更直观的体现,有以下的例子。
举例说明
有数组a[5],值分别为10,11,12,13,14;有指针p指向a[0];另有指针q和整数b。这里注意的是,每段代码开始前,a数组的值和p指针都会回复初始状态。(在一开始写这些测试代码时,忽视了回复初值的问题,导致很多奇怪的错误,比如p已经不再指向a[0],或者a[0]本身已经改变了。)
1.后缀++
p指向a[1]值为11,q指向a[0]值为10。说明后缀自增运算符,返回的是自增前的值。
2.前缀++
p指向a[1]值为11,q指向a[1]值为11。说明前缀自增运算符,返回的是自增后的值。
3.*p++
p指向11,b值为10。此时先执行p++,p自增,指向a[1]。p++的值为自增前的值,即a[0]的地址,a[0]的值赋给b。
4.*(p++)
结果与3相同。*与++运算符优先级相同,运算顺序是自右向左。
5.(*p)++
此时虽然结果与3相同,但这时是先取p指向的值即a[0],a[0]自增即a[0]的值变成11,自增是后缀的,返回自增前的值,即10。结果相同,但原理还有很大的差别。
6. *++p
p指向11,b值为11。先执行++p,p自增,指向a[1],++p的值为自增后的值,即a[1]的地址,a[1]的值赋给b。
7.*(++p)
与6结果相同,*与++运算符优先级相同,运算顺序是自右向左。
8.++(*p)
p指向11,b值为11,先取p指向a[0]值为10,a[0]的值自增变成11,前缀自增返回值为11赋给b。
9. ++*p
结果同8,*与++运算符优先级相同,运算顺序是自右向左。
总结
第一个原则就是前缀值为变化后,后缀值为变化前。第二个原则,*++优先级相同,读的时候从右向左。这些都是本人自己试着总结的,如有错误请多指正,希望对有疑惑的朋友有所帮助。
完整代码
运行结果
![](http://images2015.cnblogs.com/blog/913257/201603/913257-20160316001651131-380327992.png)
补充:
在C++中,建议除非必须,否则不使用后置版本的递增递减运算符。
其原因是前置版本的递增运算符避免了不必要的工作,把加1后的值直接返回改变了运算对象。与之相比,后置版本需要先存储自增前的值,以便返回未修改的值。这是一种浪费。
++、--和*的优先级顺序
在C语言运算符的优先级顺序中,后缀的++和--运算符运算优先级16,结合关系是从左到右;简介访问运算符*、前缀++和--运算符运算优先级15,结合关系是从右到左。根据这个关系,可以分析出不同情况下的应用。为了更直观的体现,有以下的例子。
举例说明
有数组a[5],值分别为10,11,12,13,14;有指针p指向a[0];另有指针q和整数b。这里注意的是,每段代码开始前,a数组的值和p指针都会回复初始状态。(在一开始写这些测试代码时,忽视了回复初值的问题,导致很多奇怪的错误,比如p已经不再指向a[0],或者a[0]本身已经改变了。)
1.后缀++
p = a; q = p++;
p指向a[1]值为11,q指向a[0]值为10。说明后缀自增运算符,返回的是自增前的值。
2.前缀++
p = a; q = ++p;
p指向a[1]值为11,q指向a[1]值为11。说明前缀自增运算符,返回的是自增后的值。
3.*p++
p = a; b = *p++;
p指向11,b值为10。此时先执行p++,p自增,指向a[1]。p++的值为自增前的值,即a[0]的地址,a[0]的值赋给b。
4.*(p++)
p = a; b = *(p++);
结果与3相同。*与++运算符优先级相同,运算顺序是自右向左。
5.(*p)++
p = a; b = (*p)++;
此时虽然结果与3相同,但这时是先取p指向的值即a[0],a[0]自增即a[0]的值变成11,自增是后缀的,返回自增前的值,即10。结果相同,但原理还有很大的差别。
6. *++p
p = a; b = *++p;
p指向11,b值为11。先执行++p,p自增,指向a[1],++p的值为自增后的值,即a[1]的地址,a[1]的值赋给b。
7.*(++p)
p = a; b = *(++p);
与6结果相同,*与++运算符优先级相同,运算顺序是自右向左。
8.++(*p)
p = a; b = ++(*p);
p指向11,b值为11,先取p指向a[0]值为10,a[0]的值自增变成11,前缀自增返回值为11赋给b。
9. ++*p
p = a; b = ++*p;
结果同8,*与++运算符优先级相同,运算顺序是自右向左。
总结
第一个原则就是前缀值为变化后,后缀值为变化前。第二个原则,*++优先级相同,读的时候从右向左。这些都是本人自己试着总结的,如有错误请多指正,希望对有疑惑的朋友有所帮助。
完整代码
/*本程序用来测试前缀自增运算符,后缀自增运算符,取内容符号的运算优先级以及顺序带来的返回值的影响*/
#include "stdio.h"
void myPrint(int n,int j, int k)
{
printf("no.%d:p->%d, q->%d\n", n,j, k);
}
void myPrintNew(int n,int j, int k)
{
printf("no.%d:p->%d, b->%d\n", n,j, k);
}
void init(int a[5])
{
a[0] = 10;
a[1] = 11;
a[2] = 12;
a[3] = 13;
a[4] = 14;
}//防止某些测试的操作改变了数组的值,在每次使用数组之前使用初始化函数
int main(int argc, char* argv)
{
//int a[5] = { 10, 11, 12, 13, 14 }, *p,*q,b;
int a[5] ,*p, *q, b;
init(a);
//1.
init(a);
p = a; q = p++;
myPrint(1,*p, *q);
//p指向11,q指向10
//后缀自增运算符,返回的是自增前的值
//2.
init(a);
p = a; q = ++p;
myPrint(2,*p, *q);
//p指向11,q指向11
//前缀自增运算符,返回的是自增后的值
//1,2:阅读顺序:从左到右
//3.
init(a);
p = a; b = *p++;
myPrintNew(3,*p, b);
//p指向11,b值为10
//先执行p++,p自增,指向a[1],p++的值为自增前的值(见1),即a[0]的地址,a[0]的值赋给b
//4.
init(a);
p = a; b = *(p++);
myPrintNew(4,*p, b);
//结果与3相同
//*与++运算符优先级相同,运算顺序是自右向左
//5.
init(a);
p = a; b = (*p)++;
myPrintNew(5,*p, b);
//结果与3相同,但这时是先取p指向的值即a[0],a[0]自增即a[0]的值变成11,自增是后缀的,返回自增前的值,即10
//与8对照
//6。
init(a);
p = a; b = *++p;
myPrintNew(6, *p, b);
//p指向11,b值为11
//先执行++p,p自增,指向a[1],++p的值为自增后的值(见2),即a[1]的地址,a[1]的值赋给b
//7.
init(a);
p = a; b = *(++p);
myPrintNew(7, *p, b);
//与6结果相同
//*与++运算符优先级相同,运算顺序是自右向左
//8
init(a);
p = a; b = ++(*p);
myPrintNew(8, *p, b);
//p指向11,b值为11
//先取p指向a[0]值为10,a[0]的值自增变成11,前缀自增返回值为11赋给b
//9??
init(a);
p = a; b = ++*p;
myPrintNew(9, *p, b);
//结果同8
//*与++运算符优先级相同,运算顺序是自右向左
return 0;
}
运行结果
![](http://images2015.cnblogs.com/blog/913257/201603/913257-20160316001651131-380327992.png)
补充:
在C++中,建议除非必须,否则不使用后置版本的递增递减运算符。
其原因是前置版本的递增运算符避免了不必要的工作,把加1后的值直接返回改变了运算对象。与之相比,后置版本需要先存储自增前的值,以便返回未修改的值。这是一种浪费。
相关文章推荐
- C++11: CAS
- c++程序员不可不知的101条实用经验
- iOS c语言 基本运算符
- C语言 进制关系
- C语言基础-07-预处理指令1-宏定义
- C语言基础-08-预处理指令2-条件编译
- C语言基础-09-预处理指令3-文件包含
- C语言基础-10-变量类型
- C语言基础-11-static和extern关键字1-对函数的作用
- C语言基础-12-static和extern关键字2-对变量的作用
- C语言基础-13-结构体
- C语言基础-14-枚举
- C语言基础-15-typedef
- VC++6.0 afxres.h,mfc42d.lib错误解决方法
- C++ Exceptional 名称查找、命名空间和接口原则
- C++混合编程之idlcpp教程(一)
- C++-----直接声明对象PK new对象
- AVRWARE++开发笔记9:应用Atmel Studio学习C语言
- 单链表常见习题及C语言实现(持续更新)
- 【干货】C++通过模板特化实现类型萃取实例--实现区分基本类型与自定义类型的memcpy