一.操作符的分类
• 算术操作符: + - * / %
• 移位操作符: << >>
• 位操作符: & | ^ ~
• 赋值操作符: = += -= *= /= %= <<= >>= &= |= ^=
• 单目操作符:! ~ ++ -- + - & * sizeof (类型)
• 关系操作符: > >= < <= == !=
• 逻辑操作符: && || !
• 条件操作符: ? :
• 逗号表达式: ,
• 下标引用: []
• 函数调用: ()
• 结构成员访问: . ->
二.算术操作符
1.+- 完成加法和减法,位于操作符两端的就是他们的操作数,这种操作符也叫双目操作符。
2.*完成乘法
3./完成除法,除号的两端是整数执行整数乘法,得到的结果为整数,自动舍弃小数部分。(即向下取整)如果希望得到浮点数,两个运算数中必须有一个是浮点数。
举个例子
int score=5;
score=(score/20)*100;
输出的结果为0,要想得到25,必须将20改为20.0。
4.%完成取模运算,即两个整数相除的余数。只能用于整数之间,不可用于浮点数。
负数取模的原则:结果的正负号由第一个运算数的正负号决定。
#include <stdio.h>
int main()
{
printf("%d\n", 11 % -5); // 1
printf("%d\n",-11 % -5); // -1
printf("%d\n",-11 % 5); // -1
return 0;
}
三.逻辑操作符
1.&& 逻辑与运算符,就是并且的意思(两侧的表达式都为真,则为真,否则为假)

2.|| 逻辑或运算符,就是或者的意思(两侧⾄少有⼀个表达式为真,则为真,否则为假)

3.!逻辑取反运算符(改变单个表达式的真假)

C语言逻辑运算符还有一个特点,它总是先对左侧的表达式求值,再对右边的表达式求值,这个顺序是保证的。如果左边的表达式满足逻辑运算符的条件,就不再对右边的表达式求值。这种情况称为“短路”。对于&&操作符来说,左边操作数的结果是0的时候,右边操作数就不再执行。|| 操作符的左操作数的结果不为0时,就无需执行右操作数。
四.关系操作符
• > 大于运算符
• < 小于运算符
• >= 大于等于运算符
• <=小于等于运算符
• == 相等运算符 (判断两个字符串是否相等要使用strcmp)
• != 不相等运算符
注:多个关系运算符不得连用
i < j < k;//合法,但往往得不到想要的结果
int a=3,b=7,c=4;
if(a<b<c)//结果为真,因为关系运算符是从左往右计算,所以应该3<7为真(1),1<4为真。
//所以应该写成i<j&&j<k
五.移位操作符
操作数只能是整数,移动的是存储在内存中的二进制位(补码),也不可移动负数位,如n>>-1。
1.<< 左移操作符
原则:左边抛弃右边补0
#include <stdio.h>
int main()
{
int num = 10;
int n = num<<1;
printf("n= %d\n", n);
printf("num= %d\n", num);
return 0;
}

2.>> 右移操作符
原则:右移运算分两种:
1.逻辑右移:左边用0填充,右边丢弃
2.(通常)算术右移:左边用原来值的符号位填充(正数补0,负数补1),右边丢弃
#include <stdio.h>
int main()
{
int num = -1;
int n = num>>1;
printf("n= %d\n", n);
printf("num= %d\n", num);
return 0;
}
下面演示的是算术右移:
六.赋值操作符
在变量创建的时候给一个值叫初始化,变量创建之后,再给一个值叫赋值。
赋值=和相等==完全不同,例如if(x=3)不管x是不是3,都会给x赋值3,这个条件永远为真。必须写成if(x==3)才能判断它是否为3.
int a=100//初始化
a=200;//赋值
1.连续赋值(支持但不建议)
int a=3;
int b=5;
int c=0;
c=b=a+3;//顺序从右往左
2.复合赋值符 += -= *= /= %= >>= <<= &= |= ^=
例如(其余同理):
int a = 10;
a = a+3;//或a+=3;
a = a-2;//或a-=3;
七.单目操作符
1.前置++(--):先加(减)一,后使用
2.后置++(--):先使用,后加(减)一
例如:
int a=10;
a++;
printf("%d",a);//11
printf("%d",a++);//10
++a;
printf("%d",a);//11
printf("%d",++a);//11
3.+(-),+对正负值没影响,完全可以省略。-可以改变正负值,在正数前面加上-变负数,负数前面加-变正数。
4.!取反符号
5.&(取地址) *(解引用)可见我写的深度理解指针1.2
6.sizeof (类型) 后续深度指针5博客会详细结合笔试题讲解
八.位操作符(二进制位)
对应a,b补码的二进制的每一位
1.& 按位与:有0则为0,两个同时为1才为1
2. | 按位或:有1则为1,两个同时为0才为0
3.^ 按位异或:对应二进制位,相同为0,相异为1,得到补码,取反+1得到原码。
支持交换律
0^a=a;
a^a=0;
3^5^3=5^3^3;
4.~ 按位取反:对应每一个二进制位,0变1,1变0
举个例子:
#include <stdio.h>
int main()
{
int num1 = -3;
int num2 = 5;
printf("%d\n", num1 & num2);
printf("%d\n", num1 | num2);
printf("%d\n", num1 ^ num2);
printf("%d\n", ~0);
return 0;
}

一道很难的面试题:不能创建临时变量(第三个变量),实现两个整数的交换。
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a^b;
b = a^b;
a = a^b;
printf("%d %d",a,b);
return 0;
}
编写代码实现:求⼀个整数存储在内存中的二进制中1的个数
n&1就是找n最低位,n&(n-1)就是将n的二进制中的最低位由1变成0,把n的二进制序列中最右边的1去掉。
//方法一
#include<stdio.h>
int main()
{
int num=0;
scanf("%d",&num);
int count=0;
while(num)
{
if(num%2==1)
count++;
num/=2;
}
printf("%d",count);
return 0;
//方法二:
#include<stdio.h>
int main()
{
int num=0;
scanf("%d",&num);
int count=0;
for(int i=0;i<32;i++)
{
if((num>>i)&1==1)
count++;
}
printf("%d",count);
return 0;
}
//方法三
#include<stdio.h>
int main()
{
int num=0;
scanf("%d",&num);
int count=0;
while(num)
{
count++;
num=num&(num-1);//把num的二进制序列中最右边的1去掉
}
printf("%d",count);
return 0;
九.条件操作符

意思是表达式1为真,就执行表达式2,为假就执行表达式3.
十.逗号表达式

必须从左向右依次执行。整个表达式的结果是最后一个表达式的结果。

a>b为0,a=2+10=12,更新a的值,b=12+1=13,所以c=13。
十一.下标访问[]
操作数:⼀个数组名 + ⼀个索引值(下标)

十二.函数调用()
接受⼀个或者多个操作数:第⼀个操作数是函数名,剩余的操作数就是传递给函数的参数。
#include <stdio.h>
void test1()
{
printf("hehe\n");
}
void test2(const char *str)
{
printf("%s\n", str);
}
int main()
{
test1(); //这⾥的()就是作为函数调⽤操作符。
test2("hello bit.");//这⾥的()就是函数调⽤操作符。
return 0;
}
十三.结构成员访问操作符
1.直接访问:通过点操作符(.)访问
#include <stdio.h>
struct Point
{
int x;
int y;
}p = {1,2};
int main()
{
printf("x: %d y: %d\n", p.x, p.y);
return 0;
}
2.间接访问:结构体指针->成员名

十四.操作符的优先级和结合性
下⾯是部分运算符的优先级顺序(按照优先级从⾼到低排列),建议⼤概记住这些操作符的优先级就⾏,其他操作符在使用的时候查看下面表格就可以了。
• 圆括号( () )
• ⾃增运算符( ++ ),⾃减运算符( -- )
• 单⽬运算符( + 和 - )
• 乘法( * ),除法( / )
• 加法( + ),减法( - )
• 关系运算符( < 、 > 等)
• 赋值运算符( = )


1861

被折叠的 条评论
为什么被折叠?



