目录
一,基本操作符
加 + 、减 - 、乘 * 、除 / 、求余 %
注:
- 除了 % 操作符之外,其他的操作符都可以作用于整数和浮点数;
- 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除 法。
- % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
int main()
{
int a = 1;
int b = 2;
a + b;
a - b;
a * b;
a / b; //结果为0,两整数相除结果仍为整数,只要其中有浮点数即可得出小数
a % b; //左右边操作数需均为整数
return 0;
}
二,移位操作符(二进制位)
右移 >> ,左移 <<
1,>>,右移操作符(除2效果),右移有两种情况:
- 算数右移,右边丢弃,左边补原符号位(可能是0,也可能是1);
- 逻辑右移,右边丢弃,左边补0;
int main()
{
int a = 3;
printf("%d\n", a >> 1);
//0000 0000 0000 0000 0000 0000 0000 0011 - 3的内存二进制形式(正整数原反补相同)
//0000 0000 0000 0000 0000 0000 0000 0001 - 向右移一位,最左边补零
//结果为:1
return 0;
}
2,<<,左移操作符(乘2效果)
- 左边丢弃,右边补0;
//正整数
int main()
{
int a = 3;
printf("%d\n", a << 1);
//0000 0000 0000 0000 0000 0000 0000 0011 - 3的内存二进制形式(正整数原反补相同)
//0000 0000 0000 0000 0000 0000 0000 0110 - 向左移一位,最右边补零
return 0;
}
//结果为:6
//负整数
int main()
{
int a = -3;
printf("%d\n", a << 1);
//1000 0000 0000 0000 0000 0000 0000 0011 - 原码
//1111 1111 1111 1111 1111 1111 1111 1100 - 反码(符号位不变,其余取反)
//1111 1111 1111 1111 1111 1111 1111 1101 - 补码(反码+1),即内存中的二进制形式
//1111 1111 1111 1111 1111 1111 1111 1010 - 向左移一位,最右边补零
//1111 1111 1111 1111 1111 1111 1111 1001 - -1得到补码
//1000 0000 0000 0000 0000 0000 0000 0110 - 符号位不变,其余取反,得到原码
return 0;
}
//结果为:-6
注:
- 不要移负位数;
- 整数的二进制表示由原码、反码、补码;(-1的补码全为1);
三,位操作符(二进制位)
按位与 &,按位或 |,按位异或^
- & 按位与,有0即为0,都为1才为1;
- | 按位或,有1即为1,都为0才为0;
- ^ 按位异或,相同为0,相异为1;
注:操作数必须为整数;
int main()
{
int a = 0; //0000 0000 0000 0000 0000 0000 0000 0000
int b = 1; //1000 0000 0000 0000 0000 0000 0000 0001
printf("%d %d %d\n", a & a, b & b, a & b); //结果:0 1 0
printf("%d %d %d\n", a | a, b | b, a | b); //结果:0 1 1
printf("%d %d %d\n", a ^ a, b ^ b, a ^ b); //结果:0 0 1
}
例:点击链接
- 1,不创建变量,交换变量值(^);
- 2,打印整数二进制中奇数位和偶数位(移位循环打印);
- 3,统计整数二进制中1的个数(求余法,移位法,相邻按位与法);
- 4,求两整数二进制中不同位的个数(先异或两整数,在统计二进制中1的个数);
- 5,判断一数是否是2的N次方,只需判断num&(num-1)==0 --执行一次去掉一个1;
四,赋值操作符
赋值操作符 = ;
复合赋值操作符 +=,-=,*=,/=,%=, &=,|=,^=, >>=,<<=;
注:赋值,即是修改调整变量的值;
int main()
{
int a = 0;
int b = 0;
a = b = 1; //可连续赋值(不推荐)
a += 1; //等同于 a = a + 1;
a -= 1; //等同于 a = a - 1;
a *= 1; //等同于 a = a * 1;
a /= 1; //等同于 a = a / 1;
a %= 1; //等同于 a = a % 1;
a &= 1; //等同于 a = a & 1;
a |= 1; //等同于 a = a | 1;
a ^= 1; //等同于 a = a ^ 1;
a >>= 1; //等同于 a = a >> 1;
a <<= 1; //等同于 a = a << 1;
return 0;
}
五,单目操作符
- 逻辑反 !
- 负值 - 、正值 +
- 类型长度 sizeof
- 按位取反 ~
- 前置 ++a 、后置 a++
- 强制类型转换 (类型)
- 取地址 & 、解引用 *(NULL空指针不可解引用)
注:
- 单目操作符,即只有一个操作数;
- 双目操作符,即有两个操作数;
- 三目操作符,即有三个操作数;
int main()
{
int a = 0;
int arr[5] = { 0 };
//结果:20(5*4),相对于sizeof(int[5]),只统计类型所在空间字节大小
printf("%d %d ", sizeof(arr), sizeof(int[5]));
//结果:20,4
printf("%d %d ", sizeof arr, sizeof arr[5]);
//结果:4,因为sizeof括号内表达式不参与计算,只要识别a的类型即可
//sizeof在编译时已计算,a += 1在运行时才计算的
printf("%d ", sizeof(a += 1)); //a += 1并没有参与计算
printf("%d ", a); //结果:0
return 0;
}
//注:sizeof(变量)、sizeof(类型),变量时可省略括号;
//也因为sizeof(变量),括号可省略,证明sizeof是操作符不是函数;
//sizeof arr 和 &arr ,此两数组名表示整个数组;
int main()
{
int a = 0;
int b = ~a; //按位取反
//0000 0000 0000 0000 0000 0000 0000 0000 - a内存二进制形式
//1111 1111 1111 1111 1111 1111 1111 1111 - b内存二进制形式(补码,需还原为原码)
//1111 1111 1111 1111 1111 1111 1111 1110 - 反码(补码-1)
//1000 0000 0000 0000 0000 0000 0000 0001 - 原码(符号位不变,其余位取反)
printf("%d ", b); //结果:-1,
return 0;
}
//注:-1的内存补码形式全为1;
int main()
{
int a = 10;
int b = 10;
int a1 = a++; //后置++,是先使用,在本身+1
int b1 = ++b; //后置++,是先在本身+1,使用
printf("a=%d a1=%d\n", a, a1); //结果:a=11, a1=10;
printf("b=%d b1=%d\n", b, b1); //结果:b=11, b1=11;
return 0;
}
//注:int b = (++a)+(++a)+(++a),此代码没有意义,在window和Linux结果是不一样的;
int main()
{
int a = (int)3.14;
printf("%a ", a); //结果:3;
return 0;
}
int main()
{
int a = 1;
int* p = &a; //将变量a在内存中地址赋予给p(int*位指针类型)
int b = *p; //对指针变量p的解引用可找到变量a
printf("p=%p ", p); //结果:006FFD94 (此位十六进制格式,一个数表示4个位如f(1111))
printf("b=%d ", b); //结果:1;
return 0;
}
六,关系操作符
>,<,>=,<=,!=,==
注:==、=,不要写错,一个是关系操作符,一个是赋值操作符;
int main()
{
int a = 1;
if (1 == a) //注意书写形式
printf("判断a是否等于1");
return 0;
}
七,逻辑操作符
&&、||、!
注:
- && 逻辑且,左右操作数均为真时,才为真;如第一个操作符为假,第二个操作数将不在参与计算;
- || 逻辑或,左右操作数只要有一个为真时,即为真;如第一个操作符为真,第二个操作数将不在参与计算;
- !逻辑非;
- 注意与按位与&、取地址&,及按位或|的区别
int main()
{
int a = 0;
int b = 0;
if (!(a && ++b))
printf("a=%d,b=%d\n",a,b); // a=0,b=0 因为++b并未参与计算
if (++a || ++b)
printf("a=%d,b=%d\n", a, b); // a=1,b=0 因为++b并未参与计算
return 0;
}
八,条件操作符
exp1? exp2: exp3
注:
- 条件操作符,也是三目操作符;
- exp1表达式为真执行exp2,假exp3;
- exp2,exp3只会执行其中一个;
int main()
{
int a = 0;
int b = 0;
a = (0 == a) ? ++a : ++b;
printf("a=%d,b=%d\n", a, b); //a=1,b=0 因为++b并未参与计算
return 0;
}
九,逗号表达式
(exp1,exp2,...,expN)
注:
- 逗号表达式,就是用逗号隔开的多个表达式。
- 逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
int main()
{
int a = 0;
int b = 0;
printf("%d", (a++, b++, a + b)); //结果:2
return 0;
}
a = get();
count(a);
while (a > 0)
{
//... 业务处理
a = get();
count(a);
}
//如果使用逗号表达式,可改写:
while (a = get(), count(a), a > 0)
{
//... 业务处理
}
十,下标引用操作符
[ ]
注:
- 是针对数组的,即获取数组指定下标的元素值(下标从0开始);
- 操作数:一个数组名 + 一个索引值,如arr[5],操作数为arr和5;
int main()
{
int arr[6] = { 1,2,3,4,5,6 };
printf("%d", arr[5]); //结果:6
return 0;
}
十一,函数调用操作符
()
注:
- 是函数的,即调用指定的函数;
- 操作数可以一个或多个;第一个操作数是函数名,剩余的操作数就是传递给函数参数;
#include <stdio.h>
void print1()
{
printf("hehe\n");
}
void print2(char* str)
{
printf("%s\n", str);
}
int add(int x, int y)
{
return x + y;
}
int main()
{
print1(); //只有一个操作数print1
print2("C"); //有两个操作数print1和"C"
printf("%d\n", add(2, 3)); //有三个操作数add、2和3
return 0;
}
十二,结构成员
. 、->
. 注:
- 均是访问结构体成员的,结构体.成员名 、 结构体指针->成员名;
int main()
{
struct stu s = { "zhangsan",20,90.5 }; //初始化结构体变量s
struct stu* p = &s; //取地址
printf("%s\n", s.name); //结果:zhangsan
printf("%s\n", p->name); //结果:zhangsan
}