
分类:
- 算数 *** 作符
- 移位 *** 作符
- 位 *** 作符
- 赋值 *** 作符
- 单目 *** 作符
- 关系 *** 作符
- 逻辑 *** 作符
- 条件 *** 作符
- 逗号表达式
- 下表引用、函数调用的结构成员
+ - * / %
- 除了%都可以用于整数和浮点数之间的运算
- 除法 *** 作符"/":如果两个 *** 作数都是整数,执行整数除法。只要其中有浮点数执行运算那整个表达式就是浮点数的除法。
- %的两个 *** 作数必须是整数。
<< 左移位 >> 右移位
左移位 左边抛弃右边补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条)