第四章表达式
4.1 基础
1.基础符号
取地址符&
解引用符*
等运算符==
乘法运算符*
逻辑与运算符&&
逻辑或运算符 ||
条件运算符 ?:
逗号运算符 ,
2.左值和右值
当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。
4.2 算数运算符
1.bool型数据
bool型数据不参与运算,如:
bool b1=10; //b1为ture
bool b2=-b1; //b2亦为ture
原因如下:
当bool型数据b1送为10时,会升级为int型转换为1,而b2=-b1时,则将b2转换为-1,只要b2不为0,则b2为真。
2.取余%
整型数据使用除法时,经常会产生余数,可以采用取余的方式得到相应结果:
int a=21/6; //a的值为3,取整
int b=21/7; //b的值为3,刚好是整数
int c=20%6; //c的值为2,余数为2
float d=21.5%6; //d为float型,直接报错
3.负数取余%
除了-m导致溢出的特殊情况,其他时候(-m)/n和m/(-n)都等于-(m/n);
如果m%n不等于0,那么m%n与m同号,即m%(-n)等于m%n;(-m)%n等于-(m%n)。
21%6=3; 21/6=3;
21%7=0; 21/7=3;
-21 % -8 =-5; -21/-8=2;
21%-5=1; 21/-5=-4;
%的执行顺序与/和*同级别。
4.取整
在C++11新标准规定,无论正数负数,int取整一律向0取整。
1.1取为1 -1.1取为-1
4.3 逻辑和关系运算符
1.短路求值
①对于逻辑与运算符来说,当且仅当左侧运算对象为真时才对右侧运算对象求值。
②对于逻辑或运算符来说,当且仅当左侧运算对象为假时才对右侧运算对象求值。
void run1()
{
int a = 0, b = 0;
bool c;
c= b && (a = 1);
cout<< a << endl;
}
运算的结果为a=0,因为左侧为假,所以直接不进行右侧的计算。
2.C++符号运行顺序
常用优先级:
① ++; --;
② *; /; %;
③ +; -;
④ <; >; <=; >=
⑤ &; ^; |; &&; ||;
该图转自:http://blog.csdn.net/malina90/article/details/40398723
4.4 赋值运算符
1.赋值
赋值运算满足右结合律。
int i;
double d;
i= d = 3.5; //i=3d=3.5
d= i = 3.5; //i=3d=3
int *pi;
i= pi = 0; //因为pi为指针,报错
4.5 递增和递减运算符
1.递增顺序
++i和i++效果相同,但是有先后的顺序。
在赋值上,++i是先加1再赋值,i++是先赋值在加1:
int i = 0, j;
j= i++; //j=0,i=1 后置版本
j= ++i; //j=1,i=1 前置版本
所以为了避免不必要的麻烦,尽量选择前置版本
2.常用方法
利用++的优先级,向下送数,这种写法更简洁。
vector<int> a = { 1, 2, 3,4, 5, 6, 7, 8 };
auto pbeg = a.begin();
while (pbeg != a.end())
cout<< *pbeg++ << endl;
4.6 成员访问运算符
1.点运算符. 和 箭头运算符->
点运算符非常常见和箭头运算符一样,常用于访问对象的成员。
string s1 = "a string", *p =&s1;
auto n = s1.size(); //点运算符,用n调用s1中的对象size
n= (*p).size(); //点运算符,用n调用s1中的对象size
n= p->size(); //与 n = (*p).size();效果相同
4.7 条件运算符
1.条件运算符 ? :
条件运算符是用来高度简化ifelse的运算符,如果?之前的是真的,取第二个变量,如果?之前是假的,取第三个变量。
string finalgrade = (grade< 60) ? "false" : "pass";
2.条件运算符嵌套
条件运算符可以实现两层嵌套:
string finalgrade = (grade> 90) ? "high pass" : (grade < 60) ? "fail" : "pass";
//第一个?和:为一组 第二个?和右侧紧连着的是一组
3.输出
在输出过程中使用条件运算符,一定要在使用范围内加上括号。
cout << ((grade < 60) ? "fail" : "pass") << endl; //正确
cout<< (grade < 60) ? "fail" : "pass" << endl;
//报错,因为?会和<<连上,所以输出用这个必须加括号
4.8 位运算符
1.位移运算符 >> 和 <<
移动过程中靠边被移除的数据直接丢弃。
左移运算符<<
二进制中直接在右侧填上0。十进制中看起来是数据直接乘2。
右移运算符>>
二进制中要根据对象的类型在左侧填数据,如果无符号类型,直接填0;如果是有符号位,则在左侧插入符号位或0。
2.位求反运算符~
将数据转换成二进制之后1和0互换即可,但是需要注意符号的类型。
3.位与& 位或| 位异或^
位与 a&b 将数字转化为二进制数,对位都为1为真,否则为假;
位或 a|b 将数字转化为二进制数,对位只要有一个1即为真,两个0为假;
位异或 a^b 将数字转化为二进制数,对位相同为假,不同为真;
4.9 sizeof运算符
1.sizeof
sizeof运算符返回一条表达式或一个类型名字所占的字节数,满足右结合律。
它与a.size()不同,二者功能相似但是不是一个东西。
Sales_data data, *p;
sizeof(Sales_data); //存储Sales_data类型的对象所占的空间大小
sizeof data; //data类型的大小,即sizeof(Sales_data)
sizeof p; //普通指针所占的空间大小
sizeof *p; //p所指向的Sales_data类型的大小,即sizeof(Sales_data)
sizeof data.revenue; //Sales_data中revenue成员对应类型的大小
2.测试数组的元素数量
//感觉不太对
4.10 逗号运算符
1.逗号运算符
【,】为逗号运算符,它有最低的优先级,因此常用在for循环中,表示从左至右的计算。
2.常用计算
d= a ? ++b, ++c : --b, --c;
//它表示的是(d = a ? ++b, ++c :--b), --c;
//因为逗号的最低优先级,所以变成了这种形式
4.11 类型转换
1.理解算数转换
本质转换过程就是将占用短的字符转换成长的字符,保持二者一致进行计算。
16位编译器: //每个字节有8位
char:1个字节
char*(即指针变量):2个字节
short int:2个字节
int:2个字节
unsigned int:2个字节
float:4个字节
double:8个字节
long:4个字节
long long:8个字节
unsigned long:4个字节
32位编译器
char:1个字节
char*(即指针变量):4个字节
short int:2个字节
int:4个字节
unsigned int:4个字节
float:4个字节
double:8个字节
long:4个字节
long long:8个字节
unsigned long:4个字节
64位编译器
char:1个字节
char*(即指针变量):8个字节
short int:2个字节
int:4个字节
unsigned int:4个字节
float:4个字节
double:8个字节
long double:8个字节
long long double:8个字节
unsigned long:8个字节
因为现在程序都是在x64上进行,直接记64位编译器的结果即可。
2.转换实例
double+int转换为double
double+float转换为double
int=double将double小数点后的字节直接去除掉
bool=double只要double不是0就是真,转换为int
char+float转换为float
short+char同时提升为int
char+long转换为long
int+unsign long转换为unsinged long
unsigned int+long将根据各自所占空间的大小进行转换
3.强制转换
可以将变量的类型进行转换,同样的,指针数组等等也都可以使用强制转换。
4.12 运算符优先级表
见4.3的表格