在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
概述: 表达式,由操作数和运算符组成。 笔试中通常的考点有操作符的优先级、异或等关系运算。
4.1 赋值语句赋值运算符"=",操作符左边代表着存储单元的地址,称为左值,右边带表着需要的值,称为右值。 注:赋值操作符的左操作数必须是非const的左值。 int const& max(int const& a, int const& b) { return a > b ? a : b; } int& fun(int& a) { a += 5; return a; } int* fun2(int* a) { return a; } int main() { int ii = 10, j = 20; fun(ii) = 800; // 语句1 正确 执行后 ii = 800 printf("%d", ii); max(ii, j) = 200; // 语句2 错误 表达式 max(ii, j)不是可修改的左值 printf("%d", ii); fun2(&ii) = 200; // 语句3 错误 无法从int转化为int* printf("%d", ii); *fun2(&ii) = 200; // 语句4 正确 printf("%d", ii); system("pause"); } 其次,赋值操作符具有右结合特性。当表达是含有多个赋值操作符时,从右向左结合。
4.2 自增与自减运算符4.2.1 简单运算前缀运算时"先变后用",而后缀运算时"先用后变"。 以++为例: 前缀:++a 表示取a的地址,增加它的内容,然后把值放在寄存器中; 后缀:a++ 表示取a的地址,把它的值装入寄存器,然后增加内存a的值。 看下面的代码: void main(){ int a, b, c, d; a = 5; b = 5; c = (a++) + (a++) + (a++); d = (++b) + (++b) + (++b); printf("%d, %d, %d, %d", a, b, c, d); } 上例中,在VS2010中输出"8, 8, 15, 24",在VC++6.0、Dev-C++以及gcc版本下输出"8, 8, 15, 22"。 在计算c的时候,括号的值都是5,执行c = 15后,a开始自增3次。 在计算d的时候,会受到编译器的影响,在VC++6.0下,由于汇编级只能实现两个数相加,不能实现三个数相加,所以语句"d = (++b) + (++b) + (++b);"相当于"d = (++b) + (++b); d = d + (++b);"拆成了两个语句的组合,这样第一个语句后b = 7,这样d = 7 + 7 = 14,再执行第二个语句,b = 8,d = d + b = 14 + 8 = 22;而在VS2010中进行了一些调整,在计算的时候,三次自增操作都已经执行完毕,故最后d = b + b + b = 8 + 8 + 8 = 24。 注:在实际编程中,应该避免使用这种可能受到不同编译器影响的代码。 4.2.2 作用的对象自增、自减运算符只能作用于变量,而不能作用于常量或表达式。只要是标准类型的变量,不管是整型、实型还是字符型、枚举型都可以作为这两个运算符的运算对象。 1)i+++j++; //合法 2) ++i+(++j); //合法 3) ++a+b++; //合法 4) ++array[--i]; //合法 5) ++6; // 不合法 6是常量 6) (i + j)++; // 不合法 7) 'A'++; // 不合法 8) (&p)++; // 不合法 注:"++i+++j;"是非法的,与上面的1)、2)进行比较,由于C/C++编译器会从左到右尽可能多将字符组合成一个运算符或标识符,因此i+++j++等效于(i++)+(j++),这个是合法的,而"++i+++j"等效于"++(i++)+j",第一个++作用的是括号中的表达式,因此是非法的。 4.2.3 运算符的结合方向自增、自减运算符及负号运算符的结合方向是从右向左。 如表达式"k = -i++" 等效于 "k = - (i++)",若 i = 5 则表达式运算后,k = -5,i = 6;
4.3 关系与逻辑运算符关系操作符(<、<=、>、>=)具有左结合性,如下面: if( i < j < k) ..
由于i < j 返回的是bool类型,0或者1,因此,只要k大于1,则上述表达式的值为true,而这与我们想要表达的意思不相符,如果想要表示这种递推的逻辑,应用下面的方式: if(i < j && j < k) ..
这里就引出了逻辑操作符: expr1 && expr2 // 逻辑与 expr1 || expr2 // 逻辑或 都是短路求值,即当expr1不满足条件的时候,才会去执行expr2的表达式。 for(int i = 0 , j = 0 ; !x && (++y) <5 ; x++) { ...; } 上面的结果执行完y = 1。
4.4 位运算符
这里主要讲一下遇到的用法,主要是异或,在做小算法题的时候,一些实用的技巧,下面写一下应用的情况(欢迎补充 *.*)。 1)给定一个整数n,判断它是否为2的正整数次幂 if( n > 1 && ((n & (n-1)) == 0)) // 判断n的二进制位是否仅有一位为1 cout<<"true"; 2)假设一个文件,每行记录了一个数,且每个数都出现了两次,但某一个数不小心删除了,怎么快速找出? 解答:运用异或的知识,A^B^C^D^E^B = A^C^D^E (异或满足交换律,且相同的异或为0),即依次读入文件中的数进行异或,最后得到的数就是所求。 3)找到一个未排序缺失的数(如n-1个1 ~ n的不同整数,缺少一个补齐n个)。 解答:1.求这n-1个数的和sum,然后计算 n*(n + 1)/2 - sum , 比较通俗的做法,但是n很大时会溢出。 2.用异或,首先求得从1到n共n个数的异或结果A,然后用题中的序列一次与A异或,最后得到的数就是所求。 4)不使用第三方变量,将或两个变量的值。 a = a^b; b = a^b; a = a^b; 5) 不使用算术运算符实现两个数的加法。 解答:对于二进制的加法,若不考虑进位,则1+1 = 0,1+0 = 1,0+1 = 1,0+0 = 0,与异或正好类似,即如果排除进位,可以用异或来实现。 这时,再考虑进位,0+0的进位为,1+0的进位为0,只有1+1的进位为1,通过对比发现与位运算的&操作类似。因此可以总结如下: 先不考虑进位,按位异或,得值a; 然后计算进位,并将进位的值左移,得值b,若b为0,则a就是结果;若b不为0,则结果为a+b(递归调用)。下面是代码: ind add(int a, int b) { if(b == 0) return a; // 没有进位 int sum = a^b; int carry = (a & b) << 1; // 进位 return add(sum, carry); } 6)如何实现位操作求两个数的平均值? (x & y) + ((x^y) >> 1);
如数x:01010,y:010000。x&y 为010000,即取x、y中对应位都为1的位,对于结果来说,相当于取得了都为1的位相加的一半; x^y结果为00110,即取x、y中对应为只有一个为1的位,对于结果来说是二者只有一个位为1的和,最终所求为均值,应右移一位即除以2; 最后,将二者相加即可(同时为1的部分 + 分别为1的部分)。 移位运算符 移位时的补位规则:
由于左移总是在低位补0,高位丢失,因而负数左移后,有可能会变成整数。如: int x = 0x8FFF0000; cout<<(x<<1); // 输出536739840
4.5 类型转换较小的类型将会被转换成较大的类型。 需要注意的是:在C++中,有符号数与无符号数转换时,内存中的内容并没有改变,只是对内存中相同的数据解释不同而已。
4.6 运算符优先级表达式的运算顺序主要由一下两种因素决定” 1)运算符的优先级:程序总是先执行优先级较高的运算符; 2)运算符的结合性:当运算符的优先级相同时,运算符的结合性决定运行顺序。 优先级表很长....很长.... 这里从网上找来一个全的...自己打实在是太累了 >.<
总结如下: 1)括号、下标、->和.(成员)最高; 2)单目的比双目的高;算术双目的比其他双目的高; 3)移位运算高于关系运算;关系运算高于按位运算;按位运算高于逻辑运算; 4)三目的只有一个条件运算,低于逻辑运算; 5)赋值运算仅比','高,且所有的赋值运算符优先级相同,结合访问从右向左。
到此,这一部分也告一段落了,主要就是多用多积累,只靠死记是不科学的。。文中如有错误请联系我.. 希望大家都有所收获 *.*
返回目录 -> C/C++基础概述
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论