前言
🌞🌞想要学好C语言,操作符是非常重要且必不可少的一部分内容,操作符分为算数运算符、移位操作符、位操作符、赋值操作符、单目操作符、关系操作符、逻辑操作符、条件操作符、逗号表达式、下标引用,函数调用和结构成员。
操作符的基本特性
每个操作符都有自己的语义
每个操作符都有对应的优先级,如果两个操作符挨在一块,先执行优先级高的操作符,如果优先级相同,取决于他们的结合性。
每个操作符都有结合性。 操作符的结合性定义了操作符对操作数执行操作的顺序,例如:右结合性表示该操作符对其操作数从右向左执行操作。
运算符优先级顺序表
1.算数运算符
- + - * / %
这是最常见的几个操作符,但还是有一些要注意的点:
(1)对于+、-、*、/来说,如果操作符的两个操作数其中一个操作数是小数,则执行小数运算,如果都为整数,则进行整数运算。
(2)%的两个操作数必须都为整数,否则会报错,其他四个操作符则都可以。
(3)的语言/、%,0不能当除数或者模数 (这应该是个数学问题)。
2.移位运算符
- << >> (<<是向左移位、>>是向右移位)
注意:移位操作符不能移动负数位
(1) 左移操作符:
移位规则:左边抛弃、右边补零。
移位操作符是对操作数的二进制位进行移位,比如对一个int型数据8进行移位的话:
(2)右移操作符:
移位规则:右边抛弃,左边用该值的原符号位填充
右移操作符同理也是对操作数的二进制位向右进行移动,如果是整数,符号位为0,则左面填充0,如果为负数,符号位为1,则左面填充1
3.位操作符
- &(按位与) |(按位或) ^(按位异或) (这些操作符的操作数必须为整数)
位操作符,如同名字一样,也是对操作数的二进制位进行对应的操作
一道小的练习题:
(可以根据上面表格进行运算)
\#include <stdio.h> int main() { int num1 = 1; //二进制00000000 00000000 00000000 00000001 int num2 = 2; //二进制00000000 00000000 00000000 00000010 num1 & num2; //0 num1 | num2; //3 num1 ^ num2; //3 return 0; }
.赋值运算符
- =
赋值运算符可以修改一个变量的值,如果你对变量的前一个值不满意可以用=给他赋予一个新的值
int a = 8; int b = 9; float c = 10; char d = 'v'; a = b = 10; //还可以连续赋值,不过不建议使用,因为不便于调试
赋值运算符可以与其他运算符结合,变成符合运算符,比如a+=1;就相当于a = a+1;
复合运算符有:+=、-=、*=、/=、%=、>>=、<<=、&=、|=、^=
int a = 0; int b = 8; a+=b; //相当于a = a+b 所有a=8 a-=b; //相当于a = a-b 因为a=8,a-b为0 //其他运算符同理,这种复合运算符可以使代码更加简洁
5.单目操作符
! (逻辑反操作)
- (负值)
+ (正值)
& (取地址)
sizeof (操作数的类型长度(以byte为单位))
~ (对数值的二进制位取反)
- (前置后置- -)
++ (前置后置++)
* (解引用操作符)
(类型) —强制类型转换
sizeof不关心他的操作数本身是什么,只关心操作数的数据类型
5.1 介绍
演示代码:
#include <stdio.h> int main() { int a = -10; int *p = NULL; printf("%d\n", !2); //逻辑反操作,逻辑上一个值不是真就是假,非0即为真,!就是对一个数进行反操作2是真,!2即为假就是0 printf("%d\n", !0); //0是假,!0为真,就是1 a = -a; //原来的a为-10,-a就是10 p = &a; //&就是取a的地址 printf("%d\n", sizeof(a)); //a的长度就是int类型的长度为4byte printf("%d\n", sizeof(int)); //int的长度为4byte printf("%d\n", sizeof a);//这样写行不行? //正确,sizeof后面跟变量可以不写括号 printf("%d\n", sizeof int);//这样写行不行? //错误,sizeof后面跟数据类型必须加括号 return 0; }
//++和--运算符 //前置++和-- #include <stdio.h> int main() { int a = 10; int x = ++a; //先对a进行自增,然后对使用a,也就是表达式的值是a自增之后的值。x为11。 int y = --a; //先对a进行自减,然后对使用a,也就是表达式的值是a自减之后的值。y为10; return 0; } //后置++和-- #include <stdio.h> int main() { int a = 10; int x = a++; //先对a先使用,再增加,这样x的值是10;之后a变成11; int y = a--; //先对a先使用,再自减,这样y的值是11;之后a变成10; return 0; }
#include <stdio.h> int main() { a = 10; int* b = &a; printf("%d",b); //在c语言中我们常常会用到指针,如果不对其进行解引用,那么输出的值是a的地址。 printf("%d",*b); //解引用后值为10 } int main() { float a = 10.3; printf("%d",(int)a); //在实际中如果某个数我们定义成一个类型,但是输出时又想用另一个类型输出,那么我们就可以对其进行强制类型转换,使其强转为你想要的值,但谨慎使用!!!容易出错!!! }
5.2 sizeof与数组
我们都知道一个数组名如果单拿出来是首元素地址,但是对sizeof(),如果里面放一个数组名字,那么这个数组名代表的是整个数组,sizeof(数组名)也就是整个数组的大小。
演示代码:
#include <stdio.h> void test1(int arr[]) { //这里arr被形参接手之后已经是首地址了,所以sizeof(arr)为8(在64位环境下,32位环境为4) printf("%d\n", sizeof(arr)); } void test2(char ch[]) { //同上,ch接受过来已经是首地址了,所以地址的大小为8(64位环境下,32位环境为4) printf("%d\n", sizeof(ch)); } int main() { int arr[10] = {0}; char ch[10] = {0}; printf("%d\n", sizeof(arr)); //整个数组的大小为40 printf("%d\n", sizeof(ch)); //整个数组的大小为10 test1(arr); test2(ch); return 0; }
6.关系操作符
> >= < <= !=(不等于) ==(等于)
- 关系运算符就是进行比较,没什么太多细节,结果为真返回1,结果为假返回。
但是有一点需要注意,==和=一定不要看走眼,经常会有题目对这两个操作符进行修改迷惑答题人,=是赋值, ==是等于。
7.逻辑操作符
&&(逻辑与) ||(逻辑或)
- 不要混淆逻辑操作符和位操作符,两者之间有很大区别,一个是对二进制位进行与操作,一个是对数值进行与操作
int main() { printf("%d",1&2); //0,对二进制进行与操作,对应的二进制位都为真,结果为真 printf("%d",1&&2); //1,对数值进行与操作,都为真,结果为真 printf("%d",1|2); //3,对二进制位进行或操作,对应的二进制位只要有一个为真,结果为真 printf("%d",1||2); //1,对数值进行或操作,只要有一方为真,结果为真 }
8.条件操作符
exp1 ? exp2 : exp3
- 表达式1结果为真,返回表达式2,表达式1为假,返回表达式3
int main { if(a>10) b = 5; else b = -1; //等价于 a>10 ? b=5 : b=-1; }
9.逗号表达式
(exp1, exp2, exp3, …expN)
- 逗号表达式只不过就是用逗号隔开的表达式,从左到右,依次执行,整个表达式的结果为最后一个表达式的结果,注意一定要用括号阔气老。
int main() { int a = 1; int b = 3; int c = (a++,b++,a+b); printf("%d",c); //c = 6 ,从左到右执行返回最右面的表达式 //等价于 //a++; //b++; //int c = a+b; }
10.下标引用、函数调用和结构成员
[]下标引用操作符 ()函数调用操作符 . 结构体。成员 -> 结构体指针->成员名
1.[ ] 需要两个操作数:数组名 [ 下标值 ]
int arr[10] = {0}; //定义数组 arr[8] = 8; //用于找到下标
2.()操作数最少要有一个函数名,剩下的操作数看形参的数量 : 函数名(形参1,形参2…)
void test() { printf("asdfa"); } void test(int a) { printf("%d",a); } int main() { int a=0; test(); //一个操作数 test test(a); //两个操作数 test、a //以此类推还可以有很多操作数,由形参的数量决定 }
- . -> 访问结构体的两个操作符
struct Stu { char name[10]; int age; }; void set_age1(struct Stu stu) { stu.age = 18; } void set_age2(struct Stu* pStu) { pStu->age = 18; //结构成员访问 } int main() { struct Stu stu; struct Stu* pStu = &stu; //结构成员访问 stu.age = 20; //结构成员访问 set_age1(stu); pStu->age = 20; //结构成员访问 set_age2(pStu); return 0; }