一、算术操作符
算术操作符是最常见的,包括:
‘+’(加) ‘-’(减) ‘*’(乘) ‘/’(除) ‘%’(取余)
其中重点提一下‘/’(除)和‘%’(取余)操作符 ,其它3个太简单就不介绍了,相信大家都懂.
(1) .’ / '(除)操作符的除数(除号后面的数)不能为0,否则编译器会报错,毕竟这样不符合数学的规则了.电脑表示它不会算除数为0.😂
//除数b为0时会报错 #include <stdio.h> int main() { int a = 4, b = 0; int c = a / b; printf("%d", c); return 0; }
(2).相除的结果是和数学中的一样吗?
#include <stdio.h> int main() { int a = 11, b = 4; int c = a / b; int d = a % b; printf("c=%d\n", c); printf("d=%d", d); return 0; }
结果:
c=2 d=3
分析:c语言中的除法操作符结果只保留整数部分,而余数可以通过‘’%'(取余)操作符得到,这里11/4=2余3,所以有了上面的结果.
注意:!!!
除了‘’%‘(取余)操作符以外,其它操作符都可以用于浮点型., ’‘%’(取余)操作符的左右两个操作数必须为整数。返回的是整除之后的余数。
二、移位操作符
移位操作符的作用是什么呢?
其实"位"是指二进制位,所以移位操作符是指移动一个数的二进制位.
注意:!!!
移位操作符的操作数只能是整数。
说到二进制位,这就不得不提到二进制的三种形式
- 原码
- 反码
- 补码
如果有不了解的小伙伴可以点击下面的传送门
(1) 左移操作符(‘<<’)
左移操作符即将操作数的二进制位向左移动
移动规则:
左边抛弃、右边补0(例题后面有效果图)
左移正数:
例如:将整形6左移两位
#include <stdio.h> int main() { int a = 6; printf("%d\n", a << 2);//将操作数a的二进制位向左移动两位 printf("%d", a);//观察一下a本身的变化 return 0; }
运行结果:
24 6
结果分析:
将整形6左移两位后,得到的新的二进制序列表示的结果是:
0000 0000 0000 0000 0000 0000 0001 1000=24(十进制)
但是整形a的值并没有改变因为位移操作符并没有重新赋值,就如同:
printf("%d", -a);//打印结果虽然是-6,但是a本身的值并没有改变,还是6.
左移负数:
例如:将整形-6左移两位
#include <stdio.h> int main() { int a = -6; printf("%d\n", a << 2);//将操作数a的二进制位向左移动两位 printf("%d", a);//观察一下a本身的变化 return 0; }
运行结果:
-24 -6
效果分析图:
通过上述示例,2我们不难发现,一般情况下,左移有翻倍的效果,左移一位的结果是原来的二倍,左移两位是原来的四倍.
(2) 右移操作符(‘>>’)
右移操作符即将操作数的二进制位向右移动
移位规则:
首先右移运算分两种:
- 逻辑移位
左边用0填充,右边丢弃
- 算术移位(一般使用这个)
左边用原该值的符号位填充,右边丢弃
右移正数
示例:
#include <stdio.h> int main() { int a = 10; printf("%d\n", a >> 1);//将操作数a的二进制位向右移动一位 printf("%d", a);//观察一下a本身的变化 return 0; }
通过上面学习了操作符左移,那正数的操作符右移应该不难吧。试着猜一下结果吧。
运行结果;
5 10
这里采用的是算术右移,补位为符号位0.
右移负数:
#include <stdio.h> int main() { int a = -10; printf("%d\n", a >> 1);//将操作数a的二进制位向右移动一位 printf("%d", a);//观察一下a本身的变化 return 0; }
-5 -10
这里采用的是算术右移,补位为符号位1.这里可以看出逻辑右移与算术右移的区别,如果采用逻辑右移,那么符号位补的就是0,负数就会变成正数,一般我们编译器采用的是算术右移.即左边抛弃,右边补符号位
总结:
左移有翻倍的效果,因为从效果图中可以看出,向左移动,数据位1代表的权重就会增加一倍,同样右移会减少到原来的二分之一.
注意:!!!
**其一:无论是左移还是右移,移动的位数不要太过火了,移动33位或者更多电脑表示无能为力
其二: 移动的位数不要是负数,否则是不是太奇怪了?
例如:<<-3是表示右移3位吗?并没有这种表示方法.**不要破坏规则哦.
三、位操作符
位操作符的分类:
& //按位与 | //按位或 ^ //按位异或
注意:!!!
他们的操作数必须是整数。
同样这里的位也是指二进制位.
1)& (按位与操作符):只有两边的操作数都为真的时候才为真,否则都为假.
2)’ | '(按位或操作符):只要一边为真则为真.
3)’ ^ '(按位异或操作符):相同为假,相异为真.
我要晕了😂,其实二进制只有0和1,咱只需要知道:
1)& (按位与操作符):只有都为1时才是1,其它都为0.
2)’ | '(按位或操作符):只要有1就是1,除非你都是0.
3)’ ^ '(按位异或操作符):相同(同0或同1)则就是0,不同就是1.
试着读代码算出结果吧!
#include <stdio.h> int main() { int x = 78, y = 23; int a = x & y; int b = x | y; int c = x ^ y; printf("a=%d\nb=%d\nc=%d", a, b, c); return 0; }
运行结果:
a=6 b=95 c=89
学会位操作符和移位操作符后,试着练习一下两道经典的题目吧!
四、赋值操作符
赋值操作符并没有什么要讲解的,一句话:你让我不满意,我就换了你!
讲两点要注意的内容吧
1)连续赋值容易使人误解,建议分开赋值.
#include <stdio.h> int main() { int a = 0, b = 0,c=0; a=3,b = 4; c = a = b + 1;//连续赋值 printf("%d %d %d", a, b, c); //建议写成如下形式: a = b + 1; c = a; return 0; }
2)可以使用复合赋值符,简化赋值的代码量.
#include <stdio.h> int main() { int a = 2, b = 3; a += b;//等价于a=a+b a -= b;//等价于a=a-b a *= b;//等价于a=a*b a /= b;//... a %= b; a >>= b; a <<= b; a &= b; a |= b; a ^= b; return 0; }
五、单目操作符
单目运算符;单目操作符的意思是操作数只有一个
! 逻辑反操作 - 负值 + 正值 & 取地址 sizeof 操作数的类型长度(以字节为单位) ~ 对一个数的二进制按位取反 -- 前置、后置-- ++ 前置、后置++ * 间接访问操作符(解引用操作符) (类型) 强制类型转换
(1) ‘!’ (逻辑反操作):
将逻辑结果取反,即真的变为假的,假的变为真的.
在c语言中,逻辑假用0表示,非0位真.
#include <stdio.h> int main() { int a = 1, b = 0; printf("a=%d\n", !a);//0 printf("b=%d", !b);//1 return 0; }
(2)‘&’ (取地址操作符)
‘&’ (取地址操作符):用于得到变量,数组等的地址.
在C语言中,变量,常量字符串,数组,结构体包括指针等在内存中都是有地址的,需要在内存中分配一块空间来存储这些值,而内存的编号就是内存地址.
但是字面常量(如常数 6)在内存中是没有地址的,因为它本身并不需要在保存下来.
(3)sizeof()操作符与数组的联系
sizeof()用于计算操作数所占空间大小,单位是字节,可以以类型、指针、数组和函数等作为参数。
返回值类型为unsigned int
#include <stdio.h> void test1(int arr[]) { printf("%d\n", sizeof(arr)); } void test2(char arr[]) { printf("%d\n", sizeof(arr)); } void test3(float arr[]) { printf("%d\n", sizeof(arr)); } void test4(double arr[]) { printf("%d\n", sizeof(arr)); } int main() { int arr1[10] = { 0 }; char arr2[10] = { 0 }; float arr3[10] = { 0 }; double arr4[10] = { 0 }; printf("%d\n", sizeof(arr1)); printf("%d\n", sizeof(arr2)); printf("%d\n", sizeof(arr3)); printf("%d\n", sizeof(arr4)); test1(arr1); test2(arr2); test3(arr3); test4(arr4); return 0; }
结果分析:
我们知道,在数据类型篇已经了解c语言中各数据类型占用多少字节.
所以当sizeof(数组名)操作符在计算不同类型的数组的时候.得到的结果不同,为相应数组中元素总和所占用的字节数.
当我们在数组传参时,传的是数组首元素的地址,而计算地址的大小只有两种结果
32位机器是4字节 64位机器是8字节
运行结果:
40 10 40 80 8 8 8 8
&数组名:这里的数组名表示的是整个数组,即这里取的是整个数组的地址
#include <stdio.h> int main() { int arr[10] = { 0 }; printf("&arr=%p\n",&arr) ; printf("&arr+1=%p\n", & arr + 1); printf("arr=%p\n", arr); printf("arr+1= %p\n", arr + 1); return 0; }
细节来了:
#include <stdio.h> int main() { char a = 2; int b = 3; printf("%d\n", sizeof(a = b + 3)); printf("%d\n", a); return 0; }
运行结果:
1 2
结果分析,sizeof()操作符括号里面的表达式是不进行计算的.所以a=b+3是没有执行的.这是因为sizeof()操作符在编译过程中就已经完成了,而计算需要在运行过程中完成,当运行时,这里已经是sizeof(a)的结果2了.并没有计算.
总结:
数组名一般表示的是数组首元素的地址,但有两个情况是例外的!
1.sizeof(数组名)——这里数组名表示的是整个数组,用于计算整个数组所占空间的大小
2.&数组名-----这里的数组名表示的是整个数组,即这里取的是整个数组的地址数组+1:
1.数组的地址----以整个数组的大小为整体,+1就是跳过整个数组
2.数组首元素的地址-----数组第一个元素的地址,+1就是下一个元素的地址
数组传参传的是数组首元素的地址----计算地址的大小,32位机器是4,64位机器是8
(4)’ ~ ’ (按位取反操作符)
顾名思义,就是将操作数的二进制位按位取反.
例如:
#include <stdio.h> int main() { int a = 7; printf("%d", ~7); return 0; }
(5)前置++和后置++操作符
前置++:操作数先自增(+1),后再被使用.
后置++:操作数先被使用,后自增(+1).
🌰上栗子
#include <stdio.h> int main() { int a = 5, c = 0; //前置++ c = ++a;//先a自增1使得a的值变为6,然后再被赋值到c. printf("%d\n", c);//6 printf("%d\n", a);//6 //后置++ a = 5, c = 0; c = a++;//先使a被赋值到c,此时a=5,赋值完成后,a再自增1,变为6. printf("%d\n", c);//5 printf("%d\n", a);//6 return 0; }
试着看两段代码练练手吧!
代码1:
#include <stdio.h> int main() { int i = 0; while (i++ < 5) { printf("%d ", i); } return 0; }
代码2:
#include <stdio.h> int main() { int i = 0; while (++i < 5) { printf("%d ", i); } return 0; }