1. 算术操作符
1.%:取模操作符,只能用于整数,其他几种可用于整数和浮点数
2./:当 / 两边都是整数时,执行的是整数除法,即:5/4=1,商只取整数部分
/ 两边只要有浮点数,就执行浮点数除法。
2. 移位操作符
2.1 左移操作符
移位原则:左边抛弃,右边补0
2.2 右移操作符
右移操作符分两种
(1)逻辑右移
右边抛弃,左边补0
(2)算术右移
右边抛弃,左边补符号位(正数的符号位是0,负数是1)
由上图的执行结果能够看出,由于两个右移共用一个>>符号,于是有对于signed类型的变量执行的是算术右移,而对于unsigned类型执行的是逻辑右移。
注意:
移位不能移负数位,因为在标准中未定义
3. 位操作符
按位与 &
按位或 |
按位异或 ^
三个操作符的操作数都只能是整数
应用:用按位与的方法,求一个整数存储在内存中的二进制中1的个数
int main()
{
int num = -1;
int i = 0;
int count = 0;//计数
for (i = 0; i < 32; i++)
{
if (num & (1 << i)) //1每与num按位与一次,向左移一位,只有num
count++; //二进制位是1时count+1;
}
printf("二进制中1的个数 = %d\n", count);
return 0;
}
4. 赋值操作符
赋值操作符:=
非常常用,也很容易理解
主要列举几点特殊之处
1.赋值操作符可以连续使用
例如:
int main()
{
int a = 10;
int b = 20;
int c = 0;
a = b = c + 1; //但很少使用,表达不够清晰
//a=c+1;
//b=c+1; 这样写更加清晰
}
复合赋值符:+=,-=,/=,%=,>>=,<<=,&=,|=,^=
int main()
{
int a = 10;
a = a + 10;
//可以写成x+=10;
}
其他复合赋值符类似
5. 单目操作符
int main()
{
int flag = 0;
//flag 为假的时候,打印呵呵
if (!flag)// !逻辑反运算符,flag为0,!flag等于1
{
printf("hehe\n");
}
return 0;
}
&a,取出变量a的地址
sizeof 操作符:计算变量所占字节空间的大小
int main()
{
int a = -10;
int* p = NULL;
printf("%d\n", !2); //0
printf("%d\n", !0); //1
a = -a;
p = &a;
printf("%d\n", sizeof(a)); //变量a为int型,所占字节空间4个字节
printf("%d\n", sizeof(int));//4
printf("%d\n", sizeof a);//求变量a所占字节大小时,可以不加()
//printf("%d\n", sizeof int);//err 求int类型所占空间大小时必须加()
return 0;
}
sizeof的疑惑点
这里需要先了解一下什么是整型提升:表达式中的字符型和短整型在使用之前会被转换成普通类型,这种转换就叫做整型提升
整型提升是按照变量的数据类型的符号位来提升的
看这个代码来理解一下
int main()
{
char a = 5;
//整数5在内存中以二进制形式存储:00000000000000000000000000000101
//将整数5存在char类型a中,截断取最后8位,00000101
char b = 126;
//00000000000000000000000001111110
//01111110
char c = a+b;
//计算a+b时,因为二者都是char类型,要进行整形提升
//a ->00000000000000000000000000000101
//b ->00000000000000000000000001111110
//a+b 00000000000000000000000010000011
//a+b放在c中又会发生截断,c 10000011
printf("%d", c);
//以%d形式打印c,c以char类型存储时,其符号位是1,故整型提升时前面补1 //整型提升c->11111111111111111111111110000011 补码
//c的原码1000000000000000000000001111101 -125
return 0;
}
了解了整型提升,在看下下面这段代码
int main()
{
char c = 1;
printf("%u\n", sizeof(c)); //1
printf("%u\n", sizeof(+c));//4
printf("%u\n", sizeof(-c));//4
return 0;
}
c只要参与表达式的计算,就会进行提升,表达式+c,所以sizeof(+c)是4个字节,sizeof(-c)同样的道理。
++和–操作符
++分为,前置++,后置++
int main()
{
int a = 10;
int x = ++a;
//先对a进行自增,自增后为11,然后对使用a,也就是表达式的值是a自增之后的值。x为11。
int y = --a;
//先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10;
return 0;
}
``int main()
{
int a = 10;
int x = a++;
//先对a先使用,再增加,这样x的值是10;之后a变成11
int y = a--;
//先对a先使用,再自减,这样y的值是11;之后a变成10;
return 0;
}
# 关系操作符
>,>=,<,<=,!=,==
对于这几个关系操作符,**注意==不要写成=**
# 逻辑操作符
&& 逻辑与
|| 逻辑或
&&:只有两边都不为0,表达式为真1,其余情况都是假0
||:任意一边不为0,则表达式结果为真1
&&与||的特殊之处
```c
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;
}
由执行结果我们能够看出,b,d的值并没有加1,因为a为0,在&&的左边的表达式结果为0的话,&&右边的表达式就不会继续执行。
6. 条件操作符
exp1 ? exp2 : exp3
int main()
{
int a = 10;
int b = 0;
if (a > 5)
b = 3;
else
b = -3;
//b=(a>5?3:-3); 两种写法等效
return 0;
}
7. 逗号表达式
exp1, exp2, exp3, …expN
逗号表达式:各表达式直接用逗号隔开,从左向右依次执行,表达式的结果是最右边表达式的结果
int main()
{
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
//c=13
}
8. 下标引用、函数调用、结构体成员
- 下标引用操作符
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", arr[7]);[]的两个操作数是arr和7
printf("%d\n", 7[arr]);//与arr[7]一样,因为[]只是一个操作符,跟操作数的顺序无关
}
- ( ) 函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
void test1()
{
printf("hehe\n");
}
void test2(const char* str)
{
printf("%s\n", str);
}
int main()
{
test1(); //实用()作为函数调用操作符。
test2("hello bit.");//实用()作为函数调用操作符。
return 0;
}
-
访问一个结构的成员
. 结构体名.成员名
-> 结构体指针->成员名
struct Stu
{
int age;
char name[10];
char sex[10];
};
int main()
{
struct Stu s;
struct Stu* ps;
s.age = 10;
s.name[10] = "bite";
s.sex[10] = "male";
ps->age = 20;
ps->name[10] = "bite";
ps->sex[10] = "female";
return 0;
}
操作符优先级表:引用,操作符优先级表