1.算术操作符
加 + 减 – 乘 * 除 / 取模 %
1.%操作符的两个操作数必须为整数,返回的是整除之后的余数。
2.对于除号/,以下代码输出并不会是正确的小数2.500000,而是2.0000000。
int main()
{
double a;
a = 5 / 2;
printf("%lf", a);
}
要想得到正确的小数,则除号两端必须要有一个是浮点数,将5改为5.0或者2改为2.0。如果两个数为整数,依旧执行整数除法,即以上代码的到商2余1
2.移位操作符
<< 左移操作符 >> 右移操作符
移位操作符移动的是二进制位,右移规则为右边丢弃,左边补原符号位,左移规则为左边抛弃,右边补零
但是要注意的是移位操作符是对补码进行操作,如以下代码
int main()
{
int a = -1;
int b = a >> 1;
printf("%d", b);
}
输出的结果是-1,因为-1的补码全是1,右移补原符号位没有变化,倘若移位操作符移动的是原码,那输出结果应该为0。
3.位操作符
位操作符的操作数必须是整数
1.按位与 &
参与运算的两个数化为二进制数后,在同一位上都是1,则该位的结果为1;否则为0。
即有零为零,全一为一。
2.按位或 |
两个相应的二进制位中至少有一个为1,则结果位为1;否则结果位为0。
即有一为一,全零为零。
3.按位异或 ^
二进制位两个比较的位都是0或都是1,结果为0。如果两个比较的位一个是0另一个是1,结果为1。
即相同为零,相异为一。
异或有一个性质很重要,可能经常使用。即a^b=c,可以推出c^b=a,c^a=b。
4.赋值操作符
赋值操作符就是等号=,可以赋值给一个变量来初始化,不满意也可以后面再进行赋值对其修改。
还有复合赋值符,如下
+=
:加法赋值运算符,例如 x += 3
相当于 x = x + 3
。
-=
:减法赋值运算符,例如 x -= 3
相当于 x = x - 3
。
*=
:乘法赋值运算符,例如 x *= 3
相当于 x = x * 3
。
/=
:除法赋值运算符,例如 x /= 3
相当于 x = x / 3
。
%=
:取模赋值运算符,例如 x %= 3
相当于 x = x % 3
。
<<=
:左移赋值运算符,例如 x <<= 2
相当于 x = x << 2
。
>>=
:右移赋值运算符,例如 x >>= 2
相当于 x = x >> 2
。
&=
:按位与赋值运算符,例如 x &= 3
相当于 x = x & 3
。
^=
:按位异或赋值运算符,例如 x ^= 3
相当于 x = x ^ 3
。
|=
:按位或赋值运算符,例如 x |= 3
相当于 x = x | 3
。
5.单目操作符
逻辑非:!
,用于取反一个布尔值。如果操作数为0(假),则结果为1(真);如果操作数非0(真),则结果为0(假)。
负值:-,用于将操作数的符号取反,即求一个数的相反数。
正值:+,通常用于显式表示正数,但在表达式中不影响操作数的值。
取地址:&
,用于获取变量的内存地址。
大小:sizeof
,用于计算操作数的类型长度(以字节为单位)。需要注意的点是sizeof操作符内部的表达式是不会参与运算的,比如以下代码
short a = 0,b = 5;
int c =sizeof(a = 5 + b );
printf("a=%d",a);
//输出a=0
printf("c=%d",c);
//输出c=2,大小依旧由c的数据类型决定
按位取反:~,用于将操作数的每一位二进制数取反。
自增:++,分为前置和后置两种形式,用于将变量的值增加1。前置自增是先增加再返回值,而后置自增是先返回值再增加。这一点还是很容易弄错的,我们用代码来解释,下面的自减也是同理
int a = 6;
printf("a=%d\n", ++a);
//输出a=7
printf("a=%d\n", a++);
//输出a=7
printf("a=%d", a);
//输出a=8
自减:--
,同样分为前置和后置两种形式,用于将变量的值减少1。前置自减是先减少再返回值,而后置自减是先返回值再减少。
间接访问(解引用):*,它允许通过指针变量来访问和操作内存中的数据。当有一个指针变量p,它存储了一个地址,使用间接访问操作符*p可以访问该地址处的值。
强制类型转换:(类型),将变量从一种数据类型转换为另一种数据类型,放在被处理数据前。
6.条件操作符(三目操作符)
语法结构为:表达式1 ? 表达式2 : 表达式3;
首先计算表达式1的值,如果该值为真(非零),则计算并返回表达式2的值;如果表达式1的值为假(零),则计算并返回表达式3的值。三目操作符通常用于简化代码。
比如利用该操作符最基本的实现寻找两个数中较大的数,代码如下:
int a = 66, b = 65;
int c = a > b ? a : b;
printf("max=%d", c);
//输出max=65
7.逗号表达式
语法结构为:( 表达式1 , 表达式2 , 表达式3 , …… , 表达式n )
这些表达式会从左至右依次被计算,但整个逗号表达式的值是最后一个表达式的值。
用代码来说明:
int a = 66, b = 65;
int c = (a > b, b < a, a = a + b);
printf("c=%d", c);
//输出c=131
8.下标引用、函数调用操作符
下标引用操作符:[],操作数是数组名。下标引用操作符是C语言中用于访问数组元素的基本工具,它允许通过指定的索引值来获取或修改数组中的数据。
在某些情况下,下标引用操作符和间接访问表达式是等价的。例如,*(arr + i)
与arr[i]
在语义上是相同的。专门提这一点是因为,在IDA里面总是这样表示的,一开始对于我来说看的头昏眼花。
函数调用操作符:(),操作数是函数名。函数调用操作符在C语言中用于触发函数的执行。圆括号内可以包含传递给函数的参数列表,即使没有参数,调用函数时仍需保留圆括号,如functionName()
。
9.结构体操作符
点运算符:(.),用于访问结构体变量的成员。其左边的操作数是一个结果为结构体的表达式。例如,如果有一个结构体Student
和一个该类型的变量s
,可以使用s.name
来访问name
成员。
箭头运算符:(->)用于通过指向结构体的指针来访问结构体的成员。其左边的操作数是一个指向结构体的指针。例如,如果有一个指向Student
类型结构体的指针p
,可以使用p->name
来访问name
成员。
用代码来说明:
struct student
{
char name[20];
int age;
char id[20];
};
struct student a={"特伦特",66,"666666" };
struct student* p = &a;
printf("name=%s\n", (*p).name);
//输出name=特伦特
printf("age=%d\n", (*p).age);
//输出age=66
printf("id=%s\n", (*p).id);
//输出id=666666
printf("name=%s\n",p->name);
//输出name=特伦特
printf("age=%d\n", p->age);
//输出age=66
printf("id=%s\n",p->id);
//输出id=666666