目录写文章一定要有自己的思路,文章中包含多个知识点,对于知识点的讲解,也要有自己的思路。
- 一、条件操作符
- 二、逗号表达式
- 三、下标引用操作符
- 四、函数调用操作符
- 五、逻辑运算符
- 1、逻辑与
- 2、逻辑或
- 六、单目操作符
- 1、取地址操作符
- 2、解引用操作符
- 3、sizeof
- 3、按位取反操作符
- 4、++和- -
- 七、移位操作符
- 1、左移操作符
- 2、右移操作符
- 八、位操作符
- 1、按位与 &
- 2、按位或 |
- 3、按位异或 ^
- 九、练习题
- 1、将4这个正整数存放在内存中的二进制数的第4位二进制数换成1。(0->1)
- 2、将4这个正整数存放在内存中的二进制数的第3位二进制数换成0。(1->0)
条件操作符
条件操作符又称为三目操作符,它是操作三个表达式的操作符
被三目操作符操作的三个表达式组成一个总的表达式
总的表达式的运算规则:
如果第一个表达式的值为非0,则为真,为假则整个表达式的运算结果是第二个表达式的值,
如果第一个表达式的值为0,则为假,为假则整个表达式的运算结果是第三个表达式的值。
也就是总的表达式的运算结果要根据第一个表达式的真假来决定。
练习题:
int a = 0;
int b = 0;
b = (a>5? b = 3:b = 4)
printf("%d",b);
输出的b的值是4.
二、逗号表达式三、下标引用操作符逗号表达式
逗号是操作符,用来操作多个表达式,多个表达式之间用逗号隔开,组成一个总的表达式,总的表达式称为逗号表达式。
逗号表达式的运算规则:
从左到右运算每一个表达式,最后的逗号表达式的结果是表达式中的最后一个表达式的值。
四、函数调用操作符下标引用操作符
[]
操作数是数组名和指定数组大小的值
举个例子:
3+5 可以写成5+3,则arr[7]也可以写成7[arr],这两个操作数可以交换位置。
五、逻辑运算符函数调用操作符
()
函数调用操作符的操作数是函数名和传给函数的参数。
逻辑运算符
分为逻辑与和逻辑或
逻辑运算符只关注操作数的真假,和按位与,按位或有本质的区别。
操作数什么时候为真?
当操作数的值是非0的值的时候,则为真。
操作数什么时候为假?
当操作数的值是0的时候,则为假。
运算之后的结果,如果为真,则返回1,如果为假,则返回0。
2、逻辑或逻辑与
运算规则:只要操作数有一个为假,则结果为假,只有操作数全都为真,结果才为真。
打个比方:逻辑与相当于并且,下课之后,老师让张三并且李四都去办公室,如果张三不去,李四去了,不符合要求,张三去了,李四没去,也不符合要求。
值得注意的是:编译器的特性:当编译器编译只有逻辑与的表达式时,由于编译器按照顺序从左到右编译的,如果发现有一个操作数为假,就不会在向右执行,得出结果为假,返回0。如果发现从左到右编译完,没有一个操作数为假,得出结果为真,返回1。
也可以想象当只有逻辑与操作符时,编译器对逻辑与的操作数的假很痴情,不遇到假,编译器不会停止,只要遇到一个为假,编译器就会立刻停止。
运算规则:只要操作数有一个为真,则结果为真,只有操作数没有一个为真,全为假,结果才为假。
打个比方:逻辑或相当于或者的关系,张三或者李四去一趟办公室,两人有一个去就符合要求。
值得注意的是:编译器的特性:当编译器编译只有逻辑或的表达式的时候,由于编译器按照顺序从左到右编译的,如果发现有一个操作数为真,就不会再向右执行了,得出结果为真,返回1,如果从左到右编译完,没有一个操作数为真,则结果为假,返回0
也可以想象当只有逻辑或操作符时,编译器对逻辑或的操作数的真也很痴情,不遇到真,编译器不会停止,只要遇到一个为真,编译器就会立刻停止。
练习题:
#includeint main() { int i = 0, a = 0, b = 2, c = 3, d = 4; i = a++ && ++b && d++; //i = a++||++b||d++; printf(" a = %dn b = %dn c = %dn d = %dn", a, b, c, d); return 0; }
编译 i = a++ && ++b && d++;时,发现第一个操作数的值为0,为0则为假,就停止编译,后面的表达式不会在编译,得出结果为假,返回0,i的值为0。
#includeint main() { int i = 0, a = 0, b = 2, c = 3, d = 4; //i = a++ && ++b && d++; i = a++||++b||d++; printf(" a = %dn b = %dn c = %dn d = %dn", a, b, c, d); return 0; }
当一行代码只有逻辑或时,编译器对逻辑或的操作数的真很痴情,不遇到真,不会停止,只要遇到真,就会立刻停止编译,发现第一个表达式为假,则继续编译第二个,第二个为真,得出结果为真,返回1,后面的表达式不会在进行编译。
2、解引用操作符取地址操作符 &
&的意思是:取出操作数的地址。
int a = 0;
&a :取出a的地址,具体来说,取出的是a变量占有的四个字节中的第一个字节在内存中所对应的地址。
具体细节理解:
a变量是如何占有的四个字节大小的空间?
通过int类型,创建的a变量,向内存申请四个字节大小的空间,此时空间的名字是a,a占有了四个字节大小的空间。
什么是第一个字节在内存中所对应的地址?
a空间为四个字节大小的空间,一个字节对应一个地址编号,所以a空间有四个地址编号,取地址时,取出的是第一个字节在内存中所对应的地址。
解引用操作符 *
3、sizeof*的意思是:对操作数解引用,通过操作数里面存放的地址,找到地址所对应的对象。
为什么会有 * 这个操作符?
将一个变量的地址放到另一个变量,有朝一日,我们希望可以通过这个地址,找到它所指向的对象,所以就有了*,它的功能就是完成它的期望,对变量解引用,通过地址,找到它所指向的对象。
int a = 0;
int* p = &a;
p = 1;
具体细节理解:
将a的地址存放到p变量里面,使用解引用操作符,对p解引用,通过p里面存放的地址编号,找到地址编号所指向的对象。此时p找到了对象,*p等价于a,将1赋值给a。
3、按位取反操作符sizeof是计算变量(类型)在内存中所占空间的大小。
当计算指针变量时,求出的大小可能是4个字节也有可能是8个字节。
指针变量是存放地址的,地址编号可能由32位二进制数组成,也有可能由64位二进制数组成。
当存放32位二进制数的地址编号时,存放一位二进制数需要一个比特位,存放32位二进制数需要32个比特位,一个字节=八个比特位,存放32位二进制数需要4个字节,所以向指针变量存放32位二进制数的地址编号时,需要向内存申请4个字节大小的空间,所以这时的指针变量的大小是4个字节。
当存放64位1二进制数的地址编号时,同理,需要8个字节的空间,所以向指针变量存放64位二进制数的地址编号时,需要向内存申请8个字节,所以此时指针变量的大小是8个字节。
4、++和- -按位取反操作符:~
意思是:对二进制位上的二进制数取反
注意:按位取反操作符操作的是一位二进制数
int a = 0;
a = ~a;
求此时a的值
第一步:求出a变量存放的二进制数
必须是32位的,且是整数的补码
为什么是32位的?
a是整型变量,向内存申请四个字节的空间,一个字节=8个比特位,四个字节=32个比特位,一个比特位可以存放一位二进制数,所以申请四个字节,要存放32位二进制数。
为什么是整数的补码?
整型变量存放的是整数,整数向里面存放时,存放的是这个整数的补码。
第二步:对每一位二进制数取反,原来是0的变成1,原来是1的变成0。
第三步:求出取反之后的整数
取反之后,得到新的二进制数,二进制数是补码的形式,要得到整数,需要对原码进行转换。
如果符号位是0,则代表新的二进制数对应的整数是正数,正数的补码=反码=原码,所以可以直接使用补码进行转换。
如果符号位是1,则代表新的二进制数对应的整数是负数,负数的补码不等于反码,也不等于原码,所以要求得原码,原码由补码-1得到反码,反码在按位取反得到,对原码操作之后得到的是负整数。
++和- -都只有一个操作数
++分为前置++和后置++
前置++的意思是:将++放在操作数之前,先对操作数+1,在使用操作数,让操作数去做的任务。
后置++的意思是:将++放在操作数之后,先使用操作数,让操作数做别的任务,在对操作数+1。
- - 也分为前置- - 和后置- -
前置- -的意思是:将- -放在操作数之前,先对操作数-1,在使用操作数,让操作数去做别的任务。
后置- -的意思是:将- -放在操作数之后,先使用操作数,让操作数做别的任务,在对操作数-1。
练习题:
int a = 3;
int b = a++;
printf("%d",b);
b的值是3,后置++,先使用操作数,在对操作数+1,所以先将a的值赋给b,在+1。
七、移位操作符分为左移操作符和右移操作符
注意:移位操作符操作的是整个二进制数。
左移操作符:
左移操作符的意思是对存放在内存中的二进制数向左,左移n位二进制数,移出去的二进制数丢弃,空出来的n位比特位的空间,用0填上去。
2、右移操作符假如求a<<1的运算结果
a是整型变量
第一步:求出变量a中存放的二进制数
求出的二进制数必须是32位,且必须是整数的补码
为什么求出的二进制数必须是32位的?
a是整型变量,向内存申请四个字节空间,一个字节=8个比特位,一个比特位存放一位二进制数,所以一个整型变量占用32个比特位,存放32位二进制数。
为什么求出的二进制数是整数的补码
a是整型变量,在里面存放的是整数,整数向里面存放的时候,将它的补码存放进去。
第二步:将求出的二进制数左移
左移之后,一位二进制数被丢弃,则一个比特位的空间将会空出来,则用0补上去。
第三步:得到最后的结果
左移之后,得到的新的二进制数,是补码,
如果符号位为1,则代表结果是负整数,则对补码-1,在按位取反,得到原码,通过原码,得到新的负整数。
如果符号位为0,则代表结果是正整数,正整数的原码=反码=补码,直接通过补码,得到正整数。
值得注意的是:将a变量存放的二进制数改变之后,将改变后的二进制数存到哪个变量,哪个变量的值就会是这个结果,如果不将结果存到a变量里面,是不会改变a变量的值的。
右移操作符:
右移操作符的意思是将内存中存放的二进制数,向右移n位二进制数,移出的那n位二进制数被丢弃,此时n个比特位的空间会空出来,补上原符号位的二进制数。
八、位操作符假如 int a = 4;a>>1;,求最后的结果
第一步:求出a变量的二进制数
求出的二进制数必须是32位,必须是整数的补码
为什么是
位操作符 &,| 和 ^
注意:
1:位操作符的操作数只能是整数,浮点数不能使用位操作符。
2:位操作符操作的是一位二进制数。
& 按位与的意思是:对二进制位上的二进制数进行与运算。
2、按位或 |假如a和b是整型变量
求a&b的运算结果时:
第一步:分别求出两个变量中的32位二进制数
求得的二进制数必须是32位,并且是整数的补码。
为什么是求得的二进制数是32位?
a和b是整型变量,向内存申请四个字节的空间,一个字节=8个比特位,一个比特位存放一位二进制数,所以一个整型变量占用32个比特位,存放32位二进制数。
为什么求得的二进制数是整数的补码?
a和b是整型变量,向里面存放的是整数,整数向里面存放时,存放的是它的补码。
第二步:对求出的二进制数进行与运算
求得两组二进制数,进行与运算时,是对两组数的对应的二进制位上的二进制数进行与运算,这对应位置上的二进制数可以看作一对,一对中如果有0,则运算结果为0,一对中如果都是1,则运算结果为1。
第三步:求出最后结果
与运算之后,得到的一组新的二进制数是结果的补码
如果补码的符号位是0,则代表结果是正整数,整数要根据原码求得,此时补码=原码,所以直接根据补码求出正整数。
如果补码的符号位是1,则代表结果是负整数,由于整数要根据原码求得,并且负整数的补码不等于原码,补码是由反码+1得来的,反码是由原码按位取反得来的,所以要求得原码,要对补码-1,求出反码,再对得出的反码,按位取反,得到原码。
| 按位或的意思是:对二进制位上的二进制数进行或运算
3、按位异或 ^假如a和b是整型变量
求a | b的运算结果
**第一步:**求出两个变量中存放的二进制数
二进制数必须是32位,并且是整数的补码
为什么求出的二进制数必须是32位?
a和b是整型变量,向内存中申请了四个字节的空间,一个字节=8个比特位,一个比特位存放一位二进制数,所以一个整型变量占用32个比特位,存放32位二进制数。
为什么求出的二进制数必须是整数的补码?
a和b都是整型变量,向里面存放的是整数,整数在存放时,存放的是它的补码。
第二步:进行或运算
对求得两组二进制数,进行或运算时,是对两组数的对应的二进制位上的二进制数进行或运算,这对应位置上的二进制数可以看作一对,一对中如果有1,则运算结果为1,一对中如果都是0,则运算结果为0。
第三步:求出最后结果
或运算之后,得到的一组新的二进制数是结果的补码。
如果补码的符号位是0,则代表结果是正整数,整数要根据原码求得,此时补码=原码,所以直接根据补码求出正整数。
如果补码的符号位是1,则代表结果是负整数,由于整数要根据原码求得,并且负整数的补码不等于原码,补码是由反码+1得来的,反码是由原码按位取反得来的,所以要求得原码,要对补码-1,求出反码,再对得出的反码,按位取反,得到原码。
^ 按位异或的意思是:对二进制位上的二进制数进行异或运算
第一步: 求出两个变量中的二进制数
求出的二进制数必须是32位的,并且是整数的补码
为什么求出的二进制数必须是32位?
a和b是整型变量,向内存申请四个字节的空间,一个字节=8个比特位,一个比特位存放一位二进制数,则一个整型变量申请了32个比特位,存放32位二进制数。
为什么求出的二进制数必须是整数的补码
a和b是整型变量,向里面存放的是整数,整数存放的时候,将它的补码存放进去。
第二步: 对求出的两组二进制数进行异或运算
求得两组二进制数,进行异或运算时,是对两组数的对应二进制位上的二进制数进行异或运算,这对应位置上的二进制数可以看作一对,一对中如果数字相同则运算结果为0,不同则运算结果为1。
第三步: 求出最后结果
异或运算之后,得到的一组新的二进制数是结果的补码。
如果补码的符号位是0,则代表结果是正整数,整数要根据原码求得,此时补码=原码,所以直接根据补码求出正整数。
如果补码的符号位是1,则代表结果是负整数,由于整数要根据原码求得,并且负整数的补码不等于原码,补码是由反码+1得来的,反码是由原码按位取反得来的,所以要求得原码,要对补码-1,求出反码,再对得出的反码,按位取反,得到原码。
练习题:
不创建临时变量,交换a和b中的值。
要明白的知识点:
1:0与任何值进行异或,最后的结果都是那个值本身;两个相同的值异或,最后的结果是0
2:进行异或的值,满足交换律,例如a^b ^c的值和a ^ c ^ b的值是一样的。
思路:
两个变量的值进行交换,就是将一个变量的值赋给另一个变量
通过异或操作得到一个变量的值,再赋给另一个变量。
#includeint main() { int a = 3; int b = 4; a = a ^ b; b = a ^ b; a = a ^ b; printf(" a = %dn b = %d", a, b); return 0; }
由于不能创建临时变量,所以将a先作为临时变量
b里面要放3,3可以a和0异或得到,0可以由两个b异或得到,也就是需要 3 4 4 这三个数 进行异或才能成功赋值
a里面要放4,4可以由b和0异或得到,0可以由两个a得到,也就是需要 4 3 3 这三个数进行异或才能成功赋值
我们知道如果b成功赋值为3,则a就不能成功赋值,缺少了4这个值,因为b赋值为3了。
所以可以将a作为一个临时变量,将3和4放进去。怎么放呢,将a和b异或放进a。
先对b赋值 它需要 3 4 4 ,这三个数异或,a提供 3和4,b提供3.
再对a赋值,它需要4 3 3,这三个数赋值,a提供3和4,a提供3.
九、练习题 1、将4这个正整数存放在内存中的二进制数的第4位二进制数换成1。(0->1)ps:二进制位是计算机中数据存储的最小单位,用来表示0或者1;二进制数是由n个0或者1组成的。
要改变第n位上的二进制数,将第n位上的0变成1
第一步:
对整数1的二进制位左移n-1位,得到的新的二进制数
第二步:
使得到的新的二进制数和要改变的二进制数按位或,就可以成功将0换成1。
为什么要对1的二进制位左移n-1位?
根据题意:要改变一位二进制位上的0变成1,但其他位的二进制数不能改变,
所以将要改变的那一位的二进制数或上一个1,就可以改变成1,其他位为了保持不变,或上一个0,那么要改变的二进制数按位或上一个由31个0和1个1组成的二进制数,就可以成功改变那一位的二进制数,这一组二进制数和1的二进制数形式一样,1的二进制数也是由31个0+1个1组成的,但是1的位置不固定,新的二进制数1的位置要和要改变的二进制数的位置对应,所以对1的二进制数使用左移操作符,改变二进制数中1的位置,就可以得到新的二进制说,要改变的二进制位是第几位,则对1的二进制数使用左移操作符左移n-1位,得到我们想要的二进制数。
所以就是借助1这个整数的二进制数,将它作为一个跳板,得到我们想要的数。
代码:
int a = 4; a = a | (1<<3);2、将4这个正整数存放在内存中的二进制数的第3位二进制数换成0。(1->0)
要改变第n位的二进制数,将第n位上的二进制数的1换成0。
第一步:
对1的二进制数左移n-1位,得到的新的二进制数
第二步:
将得到的新的二进制数按位取反再次得到新的二进制数
第三步:
新的二进制数与要改变的二进制数按位与,就可以成功将第n位上的二进制数换成0。
代码:
int a = 4; a = a &( ~(1<<2));



