在C语言中,有着众多的操作符,如果不能正确认识,那么在书写C语言代码时候,将会遇到这样那样的错误,甚至对于自己写的代码,都不知道bug在哪?更何况,去找bug呢??
因此,我们需要正确的去认识,并且知道每一个C语言操作符所代表的具体含义是什么!这样我们看待代码时候,才不会两眼抓瞎!
下面,笔者将带领大家认识一下,笔者所认识,及所感悟到操作符!!
1.算数操作符:
+ - * / %
在这里面,算术操作符,算是大家较为了解的操作符,毕竟每一个代码中,或多或少都会用到算术操作符!
但是我们运用时候,还要注意一下几点!
(1).除了%取除操作符之外,其他几个操作符,都可以应用于整数和浮点数
(2).对于/除法操作符,如果两个操作数都为整数,执行整数除法,而只要有小数(浮点数),执行的就是浮点数除法
(3).%取余操作符的两个操作数必须是整数!(很重要)
笔者亲测,这样将会进行报错!所以不能有这样的写法!
(4)./除法中,要想得到小数(浮点数),则必须保证在除数和被除数之间必须有一个小数(浮点数)
(5),我们还需要注意,加减乘除取余运算符之间的优先级!
2.移位操作符
《 左移位操作符 ; 》 右移位操作符
在这里,我们需要注意的是,移位操作符的操作数,只能是整数(小数,负数都不行),移位负数将没有意义
移位操作符:移动的是二进制位!
下面,我们需要浅浅介绍一下:二进制如何去表达??
如数值15:
在我们计算机中平常输入加使用的都是十进制形式!
在十进制中:15=1*10的一次幂+5*10的0次幂
在二进制中:15=1*2的3次幂+1*2的2次幂+1*2的一次幂+1*2的0次幂
在八进制中:15=1*8的1次幂+7*8的0次幂
至于其他的进制,由于篇幅原因,笔者将不再进行详细解答!
需要注意的是:10进制的表示为:0~9;
8进制的表示为0~7;
2进制的表示为0,1;
在二进制中:15=1*2的3次幂+1*2的2次幂+1*2的一次幂+1*2的0次幂
因此15的二进制表示为:00000000000000000000000000001111(一共32位)
原因为:15 是个整数,在C语言中可以存放在int 类型的变量中,而int类型的变量占4个字节(32个比特位)
上面我们已经了解到了进制的表达形式!但是,整型在计算机中的二进制的表达形式.............
整型的二进制的表示有三种:原码,反码,补码!
原码:直接根据数值写出的二进制序列就是原码
反码:原码的符号位不变,其余位按位取反就是反码
补码:反码+1就是补码
符号位:
开头的第一位就是符号位!
符号位位0:表示正数
符号位位1:表示负数
因此,对于15来说:(正数的原码,反码,补码相同)
00000000000000000000000000001111 15的原码
00000000000000000000000000001111 15的反码
00000000000000000000000000001111 15的补码
对于-15来说:(注意符号位的改变)
10000000000000000000000000001111 -15的原码
111111111111111111111111111111110000 -15的反码(原码的符号位不变,其余位按位取反就是反码)
111111111111111111111111111111110001 -15的补码(反码+1)
移位操作符:移动的是存储在内存中的补码!
当a=4时:
#include <stdio.h> int main() { int a = 4; //a的补码00000000000000000000000000000100 int b = a << 1; //把a向左移动1位 printf("a=%d b=%d\n", a, b); return 0; }
在这里,我们来看一下代码的运转结果:
对于这个结果:我们发现:移位运算符不改变原数值的大小!
00000000000000000000000000000100 4的(原码,反码,补码)
在移位运算符中,移动的是存储在内存中的补码!
因此,我们可以看出来,左移操作符规则:左边丢弃,右边补0;
当a=-4时候:
#include <stdio.h> int main() { int a = -4; //a的原码10000000000000000000000000000100 int b = a << 1; //把a向左移动1位 printf("a=%d b=%d\n", a, b); return 0; }
我们需要知道-4的原码,反码,补码
因此:
10000000000000000000000000000100 -4的原码
111111111111111111111111111111111011 -4的反码
111111111111111111111111111111111100 -4的补码
然后在根据刚才序列进行左移一位,得到的结果就是:
111111111111111111111111111111111000 补码
111111111111111111111111111111110111 反码(补码-1)
10000000000000000000000000001000 原码(反码符号位不变,其余位按位取反)
因此该数值为-8
因此,由上面两个代码,我们可以看出:左移操作符有乘2的效果!
注意,补码在移动过程中,如果将符号位移丢了,:那么,移丢就移丢,后面还能补回来!
右移操作符 《
当a=-4时候:
#include <stdio.h> int main() { int a = -4; //10000000000000000000000000000100 - 4的原码 //111111111111111111111111111111111011 - 4的反码 //111111111111111111111111111111111100 - 4的补码 int b = a >> 1; //把a向右移动1位 printf("a=%d b=%d\n", a, b); return 0; }
下面我们就a=-4来分析右移操作符:
对于右移操作符:左边空出来的一位:有两种补法!(在C语言中卖淫给出明显的绝对答案,只能根据编译器得来计算答案)
右移操作符:
a.逻辑右移:
右边丢弃,左边补0;
b.算术右移:(绝大多数是这样的)
右边丢弃,左边补原符号位(正数补0,负数补1)
对于该运算结果,结合二进制的右移结果,我们可以看出来用了算术右移!
因此,我们可以看出来,右移操作符有除2的效果!
3.位操作符(二进制的条件下)
& 按位与
| 按位或
^ 按位异或
(1). & 按位与
下面,笔者来结合此代码来进行分析:
#include <stdio.h> int main() { int a = 3; int b = -5; int c = a & b; printf("c=%d\n", c); return 0; }
00000000000000000000000000000011 3的补码
10000000000000000000000000000101 -5的原码
111111111111111111111111111111111010 -5的反码
111111111111111111111111111111111011 -5的补码
因此,对于:
00000000000000000000000000000011 3的补码
111111111111111111111111111111111011 -5的补码
由& 按位与,可以得出:
00000000000000000000000000000011 补码(原码)
按位与规则:有0则为0,都1则为1
则打印结果为c=3
(2). | 按位或
下面,笔者来结合此代码来进行分析(对上面代码进行浅浅改造)
#include <stdio.h> int main() { int a = 3; int b = -5; int c = a | b; printf("c=%d\n", c); return 0; }
还是在补码上进行操作:
00000000000000000000000000000011 3的补码
111111111111111111111111111111111011 -5的补码
对于 | 按位或 ,可以得出:
11111111111111111111111111111111011 补码(负数)
则进补码-1到反码,在到原码的操作,可以得出该数字!
因此: | 按位或规则为:只要有1则为1,两个为0则为0;
最后的打印结果为:
(3) ^ 按位异或
下面,笔者来结合此代码来进行分析(对上面代码进行浅浅改造)
#include <stdio.h> int main() { int a = 3; int b = -5; int c = a ^ b; printf("c=%d\n", c); return 0; }
我们仍然需要3跟-5的补码:
00000000000000000000000000000011 3的补码
111111111111111111111111111111111011 -5的补码
由 ^ 按位异或得出:
111111111111111111111111111111111000 补码(负数)
则进补码-1到反码,在到原码的操作,可以得出该数字!
因此 ^ 按位异或的运算规则为:
相同为0,不同为1;
因此,该代码的运算结果为:
另外需要注意的是:
^ 按位异或:
1,相同的数字按位异或结果为0;即3^3=0;
2,按位异或支持交换律;即3^5^6等于6^3^5;
4.赋值运算符
=
赋值操作符是一个很棒的操作符,它可以让你得到一个你之前不满意的数值,也就是你可以给自己重新赋值
int weight=120; weight=89;//不满意就赋值
下面介绍连续赋值
#include <stdio.h> int mian() { int a = 10; int b = 0; b = a = a + 3; printf("a=%d b=%d\n", a, b); return 0; }
在这里,b=a=a+3;是连续赋值的结果,最后的打印结果为:a=13,b=13;但是不建议这样去写。程序运转错误以后,没有办法去深入该表达式进行调试!
5.赋值运算符
+= -= *= /= %=
>>= <<= &= |= ^=
6.单目操作符
!逻辑反操作符
- 负值
+ 正值
& 取地址
sizeof 求操作符的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置,后置--
++ 前置,后置++
* 间接访问操作符(解引用操作符)
(类型) 强制类型转化
1. ! 逻辑反操作符
笔者将用下面代码来解析:
#include <stdio.h> int main() { int flag = 0; if (!flag) { printf("hehe\n"); } return 0; }
在if语句中,用了 !逻辑反操作符,
运转结果为:打印了hehe
但是笔者前面定义了flag=0,按照if语句中的,0表示假,是不会进入if语句,直接什么都不进行输出!但是最后的运转结果却是输出了hehe ,因此,! 逻辑反操作有取反的意思
2. & 取地址操作符
& 取地址操作符 常常与 * 间接访问操作符(解引用操作符) 在指针中联用!
int a=10; int *pa=&a; //在这里int指a的类型,*指pa为指针变量 #include <stdio.h> int main() { int a = 10; int* pa = &a; printf("%d\n", a); printf("%d\n", *pa); //由地址找到该数 printf("%d\n", pa); //打印pa的地址 return 0; }
代码的运转结果为:
*pa——》解引用操作符,最后得到a的值10;
pa——》得到a的地址
3.sizeof 操作数的类型长度(以字节为单位)
在多处都有涉及!
#include <stdio.h> int main() { short s = 10; int a = 2; printf("%d\n", sizeof(s = a + 5)); //2 printf("s=%d\n", s); //10 return 0; }
借助此代码,笔者提醒大家,sizeof(表达式) 表达式内部不进行计算!
代码的运行结果为:short类型占2 个字节!在这里s 的值仍然为10;
注意数组传参时候:
#include <stdio.h> void test1(int arr[]) { printf("%d\n", sizeof(arr)); //8 } void test2(char ch[]) { printf("%d\n", sizeof(ch)); //8 } int main() { int arr[10] = { 0 }; char ch[10] = { 0 }; printf("%d\n", sizeof(arr)); //40 printf("%d\n", sizeof(ch)); //10 test1(arr); test2(ch); return 0; }
在这里,我们需要注意的是:数组传参时候,传递的是首元素地址 ,占据4个(32位条件下)或者8个字节(64位条件下)
因此最后的打印结果为:
之前笔者就这这里栽过,因此需要读者强加注意!
4.数组名
数组名是数组首元素地址
但是有两个列外:
1.sizeof(数组名),在这里数组名表示的是整个数组,不是首元素地址
sizeof(数组名)计算的是整个数组的大小,单位是字节
2. &数组名,在这里数组名表示的是整个数组,不是首元素地址,
&数组名,取出的是整数组的地址!
5. ~ 对一个数的二进制按位取反
下面笔者将用代码来进行讲解:
#include <stdio.h> int main() { int a = 0; printf("%d\n", ~a); return 0; }
在这楼里,我们仍然需要最大a=0的二进制
00000000000000000000000000000000 0的补码
~ 对一个数的二进制进行按位取反(包过符号位)
11111111111111111111111111111111 补码(负数)
11111111111111111111111111111110 反码(补码-1)
1000000000000000000000000001 原码(反码符号位不变,其余位按位取反)
即得到的结果为-1;
7,逻辑操作符
&& 逻辑与操作符
|| 逻辑或操作符
下面笔者将用代码来进行讲解:
#include <stdio.h> int main() { int i = 0; int a = 0; int b = 2; int c = 3; int d = 4; i = a++ && ++b && d++; printf("a=%d b=%d c=%d d=%d\n", a, b, c, d); return 0; }
在该段代码中,用了前后置++运算符,因此我们需要注意:++i;先++,后输出,i++,先使用,后++;
&& 逻辑与操作符 只要前面有0,就不进行后面的运算
|| 逻辑或操作符 只要前面有1,后面也就不用计算
对于a++先使用后++,因此,a=0,然后在进行后面.........;但是:&& 逻辑与操作符 只要前面有0,就不进行后面的运算,因此,后面的b,c,d,都不进行运算,然后a在++,然后输出a=1;
8.条件操作符(唯一一个三目运算符)
exp1?exp2:exp3
a>5?3:8
exp1用来判断条件是否成立,成立则用exp2,否则用exp3
9.逗号表达式
逗号表达式就是用逗号隔开的多个表达式;
逗号表达式从左到右依次执行(将前面的结果赋值给后面的字母相同的表达式),表达式的结果为最后一共表达式的结果;
#include <stdio.h> int main() { int a = 1; int b = 2; int c = (a > b, a = b + 10, a, b = a + 1); printf("a=%d b=%d c=%d\n", a, b, c); return 0; }
在int c = (a > b, a = b + 10, a, b = a + 1);,我们可以看出来最后c的结果等于最后一个表达式b=a+1的结果!从前面依次计算表达式,可以得出a=12,b=13
运算结果为: