分类:
- 算数 *** 作符
- 移位 *** 作符
- 位 *** 作符
- 赋值 *** 作符
- 单目 *** 作符
- 关系 *** 作符
- 逻辑 *** 作符
- 条件 *** 作符
- 逗号表达式
- 下表引用、函数调用的结构成员
+ - * / %
- 除了%都可以用于整数和浮点数之间的运算
- 除法 *** 作符"/":如果两个 *** 作数都是整数,执行整数除法。只要其中有浮点数执行运算那整个表达式就是浮点数的除法。
- %的两个 *** 作数必须是整数。
<< 左移位 >> 右移位
左移位 左边抛弃右边补0
右移位
- 算术右移
右边丢弃,左边补符号位(*)
- 逻辑右移
右边丢弃,左边补0
警告:对于移位运算符,不要移动负数位,这个标准没有定义。
int num = 10; num>>-1;//错误的位 *** 作符
位 *** 作符:
& 按位与 有0就为0 | 按位或 有一就为1 ^ 按位异或 相同为0相异为1
*** 作数必须是整数。
小练习
int num1 = 1; int num2 = 2; printf("%d ",num1&num2); printf("%d ",num1|num2); printf("%d ",num1^num2);
题:不创建临时变量实现两数的交换
方法一 思路 (加减法可能会溢出)
代码实现
int a = 2; int b = 3; a = a+b; b = a-b; a = a-b;
方法二 (思路) 一个数对同一个数两次异或回到本身。而且异或运算有交换律
代码实现
int a = 2; int b = 3; a = a^b; b = a^b; a = a^b; printf("%d ",a); printf("%d ",b);练习:
一个整数存储在内存中的二进制中的1的个数。
思路:1. 短除法思想。(只能计算正数)。
- 按位与1进行计算可以得到最后一位是什么,再加上右移 *** 作。
代码实现:
int main(){ int number = 0; int count = 0; scanf("%d",&number); //不能计算负数 // while(number){ // if (number%2 == 1){ // count++; // } // number = number /2; // } for(i = 0;i<32;i++){ //32是因为int占32位 if(1==((num>>i)&1)) count++; } printf("%d",count); return 0; }赋值 *** 作符(=)
初始化赋值、重新赋值、连续赋值。
复合赋值 *** 作符+= -= *= /= %= >>= <<= &= |= ^=单目 *** 作符
正、负是单目运算符,加、减是双目运算符
1是真但是真不一定是1。
计算数组长度 = sizeof(arr)/sizeof(arr[0])
坑题:
int main(){ short s = 0; int a = 10; printf("%dn",sizeof(s = a + 5)); printf("%dn",s); }
sizeof和数组解析:sizeof(s = a+5)的大小最后取决于s的类型。
s==5是因为sizeof运算符中的表达式仅仅是表达一下,并不会真正参与运算。
void test1(int arr[]){ printf("%d ",sizeof(arr));//(3) } void test2(char ch[]){ printf("%dn",sizeof(ch));//(4) } int main(){ int arr[10] = {0}; char ch[10] = {0}; printf("%d ",sizeof(arr));//(1) printf("%dn",sizeof(ch));//(2) test1(arr); test2(ch); return 0; }
解析:
关系 *** 作符 关系 *** 作符(1)处 = sizeof(int)*10 = 40
(2)处 = sizeof(char)*10 = 10
(3)处 = sizeof(arr第一个元素的指针) = 8或者4 (64位电脑和32位电脑)
(4)处 = sizeof(ch第一个元素的指针) = 8或者4 (64位电脑和32位电脑)
> >= < <= != ==逻辑 *** 作符
&& ||
区分逻辑与和按位与 && 和&
区分逻辑或和按位或 ||和 |
逻辑是两个,按位是一个。
笔试题
程序运行结果是?
int main(){ int i = 0,a=0,b=2,c=3,d=4; i = a++ && ++b &&d++; //i = a++||++b||d++; printf("a=%d b=%d c=%d d=%d",a,b,c,d); return 0; }
运行的结果是:a=1 b=2 c=3 d=4
解析:逻辑与左边为假右边就不计算了。在a++是先使用后运算。相当于i式第一部分就为假了。
程序运行结果是?
int main(){ int i = 0,a=0,b=2,c=3,d=4; i = a++||++b||d++; printf("a=%d b=%d c=%d d=%d",a,b,c,d); return 0; }
运行结果:a=1 b=3 c=3 d=4
解析:逻辑或左边为真。右边就不计算了。a++为假运行,++b为真运行。d++就不运行了。
条件 *** 作符(三目 *** 作符)表达式1?表达式2:表达式3逗号表达式
表达式1,表达式2,表达式3,表达式4……,表达式n
从左向右以此计算。整个表达式的结果是最后一个表达式的结果。
int a = 1; int b = 2; int c = (a>b,a = b+10,a,b=a+1); printf("%d",c);//结果为13下表引用、函数调用和结构成员
1.[ ]下标引用 *** 作符
*** 作数:一个数组名+一个索引值
int arr[10];//创建数组 arr[9] = 10;//使用下标引用 *** 作符 []的两个 *** 作数是arr和9.
2.( )函数调用 *** 作符,接受一个或者多个 *** 作数:第一个 *** 作数是函数名,剩余的 *** 作数就是传递给函数的参数。
3.访问一个结构的成员
. 结构体对象.成员
-> 结构体指针->成员名
//创建了一个结构体类型 Stu C语言中叫成员就类似于面向对象中的属性 struct Stu{ char name[10]; int age; char id[20]; }; int main(){ //使用结构体struct Stu这个类型创建了一个学生对象,并初始化 struct Stu s1 = {"张三",20,"201808520"}; printf("%sn",s1.name); printf("%dn",s1.age); printf("%sn",s1.id); struct Stu* ps = &s1; printf("%sn",ps->name); printf("%dn",ps->age); printf("%sn",ps->id); return 0; }表达式求值
表达式求值的顺序一部分是由 *** 作符的优先级和结和性决定。
同样,有些表达式的 *** 作数在求值的过程中可能需要转化成其他类型。
隐式类型转化C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型 *** 作数在使用之前被转换为普通整型,这种转换称为整型提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的 *** 作数的字节长度一般就是int的自己长度,同时也是CPU的通用寄存器的长度。 因此,及时两个char类型相加,在CPU执行时实际上也要先转换为CPU内存整型 *** 作数的标准长度。 通用CPU是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加的指令)。所以表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能进入CPU去执行运算。
实例:
问:输出的结果是什么?
char a = 3; char b = 127; char c = a + b; printf("%dn",c); //输出-126
解析:
char a = 3; //00000000000000000000000000000011 //截断 -> 00000011 -> 存给a char b = 127; //00000000000000000000000001111111 //截断 -> 01111111 -> 存给b char c= a+b; //a:00000011 整型提升 -> (按符号位提升) //00000000000000000000000000000011 //b:01111111 整型提升 -> //00000000000000000000000001111111 //相加 //00000000000000000000000010000010 //截断 -> 10000010 ->存给c printf("%dn",c); //a:10000010 整型提升 -> (按符号位提升) //11111111111111111111111110000010 -补码 //11111111111111111111111110000001 -反码 //10000000000000000000000001111110 -原码 //转化为十进制:-126
b和c的值被提升为普通整型,然后执行加法运算。加法运算完成之后,结果将被阶段,然后再存储于a中。
那么,什么是整型提升呢?
整型提升是按照变量的数据类型的符号位来提升的。无符号数直接在前面补0即可。
# 负数的整型提升 char a = -1; 整型提升 11111111 (补码) 补码-1-> 反码 正数不变 负数取反 # 正数的整形提升 char = 1; 整型提升 00000001(补码) 正数的三种码都一样
整型提升的例子
//案例1 int main(){ char a= 0xb6;//10110110 short b = 0xb600; int c = 0xb6000000; if(a==0xb6) printf("a"); if(b==0xb600) printf("b"); if(c==0xb6000000) printf("c"); return 0; }
说明整型提升的存在。
算数转换如果某个 *** 作符的各个 *** 作数属于不同的类型,那么除非其中一个 *** 作数的转换为另一个 *** 作数的类型,否则 *** 作就无法进行。寻常算数转换。
long double double float unsigned long int long int unsigned int int
如果某个 *** 作数的类型在上面这个列表中的排名较低,那么首先要转化为另一个 *** 作数的类型后执行运算。
注意:算术转化要合理进行,要不然会有一些潜在的问题。
float f = 3.14; int num = f;//因式转换,会精度丢失。*** 作符属性
复杂的表达式的求值有三个影响的因素。
- *** 作符的优先级
- *** 作符的结核性
- 是否控制求值顺序
两个相邻的 *** 作符先执哪个? 取决于优先级。如果相同的优先级,取决于他们的结合性。
*** 作符的优先级
注:图片引自 [https://blog.csdn.net/zhanghong056/article/details/76667298]
问题代码:
int main(){ int i = 1; int ret = (++i) + (++i) +(++i); printf("%d",ret); printf("%d",i); return 0; } //初步判定计算顺序是三个数的加法 但是是先第一个++i存储下来再计算还是 先改变值再计算。这是又歧义的。
划重点:
写表达式时如果不能通过 *** 作符的属性确定唯一的计算路径,那个表达式就是存在问题的。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)