Hello各位老铁们,还记得我在 初识C语言(下) 中介绍的操作符吗?在初识部分,我向大家罗列了C语言中所有的操作符,并且选择性的讲解了一些常用操作符。本章在此基础之上,继续深入学习和使用操作符!
下面是C语言中所有的操作符种类:
- 算术操作符
- 移位操作符
- 位操作符
- 赋值操作符
- 单目操作符
- 关系操作符
- 逻辑操作符
- 条件操作符
- 逗号表达式
- 下标引用、函数调用和结构成员
在初识C语言(下)中,小编已经对部分操作符进行了详细介绍,这里就不在赘述。下面就对余下操作符进行讲解:
在介绍移位操作符和位操作符之前,我们有必要了解一下有符号整数在计算机中的存储方式:
📝例如:
正整数的原、反、补相同:
负整数的原反补需要转换:
<< 左移操作符
>> 右移操作符
注:移位操作符的操作数只能是整数。
移位规则:左边抛弃、右边补0
📝例如:以4和-4为例
注意:a<<1,当a的未被赋值的情况下,自身的值不会发生变化。右移同理
代码展示:
#include
int main()
{
int a = 4;
//00000000000000000000000000000100 - 4的补码
int b = a << 1;//把a向左移动一位
//00000000000000000000000000001000 - 8的补码
printf("a=%d b=%d\n", a, b);
return 0;
}
#include
int main()
{
int a = -4;
//10000000000000000000000000000100 - -4的原码
//11111111111111111111111111111011 - -4的反码
//11111111111111111111111111111100 - -4的补码
int b = a << 1;//把a向左移动一位
//11111111111111111111111111111000 - b中存储的补码
//11111111111111111111111111110111 - b的反码
//10000000000000000000000000001000 - b的原码
//-8
printf("a=%d b=%d\n", a, b);
return 0;
}
拓展:左移是把2进制向高位移动,每移动1位有扩大2倍的效果
移位规则:
- 逻辑移位 左边用0填充,右边丢弃
- 算术移位 左边用原该值的符号位填充,右边丢弃
在C语言中,C语言标准并没有规定有符号数应该使用那种类型的右移,而是取决于编译器。但是绝大多数编译器都采用算术右移。对于无符号数,自然采用逻辑右移。
📝例如:同样以4和-4为例
#include
int main()
{
int a = 4;
//00000000000000000000000000000100 补码
int b = a >> 1;
//00000000000000000000000000000010 补码
printf("a=%d b=%d\n", a, b);
return 0;
}
#include
int main()
{
int a = -4;
//10000000000000000000000000000100 - -4的原码
//11111111111111111111111111111011 - -4的反码
//11111111111111111111111111111100 - -4的补码
int b = a >> 1;
//11111111111111111111111111111100
//11111111111111111111111111111110 - b在内存中的补码
//11111111111111111111111111111101 - b的反码
//10000000000000000000000000000010 - b的原码
//-2
printf("a=%d b=%d\n", a, b);
return 0;
}
拓展:右移是把2进制向低位移动,每移动1位有缩小2倍的效果
& 按位与
| 按位或
^ 按位异或
~取反运算符
注:他们的操作数必须是整数。
规则: 有0则为0,两个同时为1才为1
规则: 有1则为1,两个同时为0才为0
规则: 相同为0,相异为1
规则: 0为1,1为0
📝一道变态的面试题:
不能创建临时变量(第三个变量),实现两个数的交换。
方法一:
int main()
{
int a = 3;
int b = 5;
a = a + b;//将(a+b)的和存到a中
b = a - b;//a的值为(a+b)的和-b,由于a=a+b即b=(a=a-b)
a = a - b;//b的值为(a+b)的和-a,由于a=a+b且b=a,即a=(b=a-b)
printf("a=%d b=%d\n", a, b);
return 0;
}
缺陷:两个整数加和可能越界
方法二:
//思路:
//a^a=0
//0^a=a
#include
int main()
{
int a = 10;
int b = 20;
a = a ^ b;
b = a ^ b;//b=a ^ b ^ b
a = a ^ b;//a=a^b^a
printf("a = %d b = %d\n", a, b);
return 0;
}
这道题在交换变量内容时一反常态,解题思路比较绕,建议大家反复观看,重在理解。
sizeof操作符的作用是:返回操作数的类型长度(以字节为单位)
注意:sizeof的操作数是变量名时可以不带括号,如果是类型名必须带括号
int main()
{
int a = 10;
int* p;
int arr[10];
//%zu专门打印sizeof的返回值
printf("%zu\n", sizeof(a));//int 4
printf("%zu\n", sizeof a);//int 4
printf("%zu\n", sizeof(int));//int 4
//printf("%zu\n", sizeof int);//err
printf("%zu\n", sizeof(p));//int* 4
printf("%zu\n", sizeof(arr));//(int [10])40去掉数组名剩下的就是数组类型
printf("%zu\n", sizeof(arr[10]));//int 4
return 0;
}
#include
void test1(int arr[])
{
printf("%d\n", sizeof(arr));
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n", sizeof(arr));//sizeof 数组名,计算的是整个数组的大小//40
printf("%d\n", sizeof(ch)); //10
test1(arr);//数组传参传递的是首元素的地址//8或4(取决于32位还是64位)
test2(ch);//数组传参传递的是首元素的地址 //8或4(取决于32位还是64位)
return 0;
}
注意:sizeof里面的表达式不参与计算
#include
int main()
{
short s = 10;
int a = 2;
s = a + 5;
//sizeof返回的是类型的大小,而表达式s=a+5返回的是s的类型。即short类型
//sizeof里面的表达式不参与计算
printf("%d\n", sizeof(s = a + 5));//2
printf("%d\n", s);//7
return 0;
}
//输出:2,7
&& 逻辑与
|| 逻辑或
! 逻辑非
&&与||使用和理解还是比较简单的,比如判断闰年:
#include
int main()
{
int year = 2000;
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
{
printf("是闰年");
}
return 0;
}
补充:&&与||在表达式计算时是会控制求值顺序的。例如下面一道360的笔试题:
#include
int main()
{
int i = 0,a=0,b=2,c =3,d=4;
i = a++ && ++b && d++;
//i = a++||++b||d++;
printf("a = %d\n b = %d\n c = %d\nd = %d\n", a, b, c, d);
return 0; }
//程序输出的结果是什么?
当i=a++&&++b&&d++时,由于a=0即为假,对于&&操作符,一旦有一个表达式为假,后面的表达式就不在计算,判定整体为假。所以只计算a++,求得:a=1,b=2,c=3,d=4
当i=a++||++b||d++时,a=0为假,++b=3为真,所以a++||++b整体为真,对于||操作符,有真则为真,所以表达式d++不在计算,求得:a=1,b=3,c=3,d=4
“逻辑非”就是指本来值的反值。
例如:" !0" 这个逻辑表达式的值为1.
" !1" 这个逻辑表达式的值为0.
exp1, exp2, exp3, …expN
逗号表达式,就是用逗号隔开的多个表达式。
逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
📝例如:
//代码1
int a = 1;
int b = 2;
int c = (a>b, a=b+10, a, b=a+1);//逗号表达式
//可求得:(a>b)==0,a=12,a=12,b=13,即c=13
//代码2
//用于判断
if (a =b + 1, c=a / 2, d > 0)
逗号表达式的其它用法:
逗号表达式在一定情境下还可以简化代码。
...
count_val(a);
while (a > 0)
{
//业务处理
a = get_val();
count_val(a);
}
//如果使用逗号表达式,改写:
while (a = get_val(), count_val(a), a > 0) {
//业务处理
}
//是不是简洁多了?
...
本章重点介绍了原、反、补码,移位操作符、位操作符、sizeof、逻辑操作符以及逗号表达式。最后希望看完本文能够对您有所帮助,如有疑问欢迎随时交流!铁汁们,我们下期再见!
下期预告:表达式求值——整形提升与算数转换