一. 操作符分类:
1.算术操作符(+、-、*、/、%)2.移位操作符(<<、>>)3.位操作符(&、|、^)4.赋值操作符(=、+=、-=、&=、*=……)5.单目操作符(!、-、+、&、*、sizeof、~、--、++)6.关系操作符(==、<、>)7.逻辑操作符(&&、||)8.条件操作符(?~:~)唯一的三目操作符9.逗号表达式(,)10下标引用、函数调用和结构成员([ ]、()、访问结构成员(.)、->)
二. 操作符介绍:
一.算术操作符(+、-、*、/、%)
加 减 乘 除 取余
1. 除了 % (取余) 操作符之外,其他的几个操作符可以作用于整数和浮点数。2. 对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。3. % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
//代码示例
#include <stdio.h>
int main() {
int a = 10, b = 5;
printf("a + b = %d\n", a + b); // 输出: 15
printf("a - b = %d\n", a - b); // 输出: 5
printf("a * b = %d\n", a * b); // 输出: 50
printf("a / b = %d\n", a / b); // 输出: 2
printf("a %% b = %d\n", a % b); // 输出: 0
return 0;
}
二.移位操作符(<<、>>)
左移操作符 右移操作符
注:移位操作符的操作数只能是整数!
以下介绍一下整数的二进制表示形式:
首先,整数的二进制表示形式有三种:原码,反码,补码。
原码:原码表示整数时,最高位(符号位)用于表示正负,0表示正数,1表示负数。其余位表示数值的绝对值。例如,8位原码中,正数+5的表示为00000101,负数-5的表示为10000101。
反码:反码是在原码的基础上,对负数的每一位取反,正数的反码与原码相同。例如,+5的反码是00000101,-5的反码是11111010(在原码基础上取反)。
补码:补码是在反码的基础上加1,用于解决计算中的一些问题,如零的唯一表示和简化加减运算。+5的补码是00000101,-5的补码是11111011(反码11111010加1)。
整数在内存中存储的都是补码的二进制序列,整数在计算的时候也是用补码
对于一个整数 4个字节(byte)=32个bit位
二进制序列:32个bit位 由32个1/0的二进制空组成(对于有符号的整数来说,最高位的1位为符号位)
符号位 | 正或负数 |
1 | 正数 |
0 | 负数 |
对于正的整数,原码,反码,补码相同无需计算
对于负的整数,原码,反码,补码相同需计算
2.1 移位操作符(<<)左移操作符
eg:
1.10的原码,反码,补码(正数,无需计算)
00000000000000000000000000001010 原码 |
00000000000000000000000000001010 反码 |
00000000000000000000000000001010 补码 |
2.-10的原码,反码,补码(负数,需要计算)
10000000000000000000000000001010 原码 |
111111111111111111111111111111110101 反码(在原码基础上除符号位,其他位取反) |
111111111111111111111111111111110110 补码(在反码基础上加一) |
10左移后 a=10<<1 得a的值应为20
00000000000000000000000000001010 |
00000000000000000000000000010100(整体左移后右端补0) |
2.1 移位操作符(>>)右移操作符
//代码示例
#include <stdio.h>
int main() {
unsigned int a = 5; // 二进制: 00000101
unsigned int b = 3; // 二进制: 00000011
printf("a << 1 = %u\n", a << 1); // 输出: 10 (00001010)
printf("a >> 1 = %u\n", a >> 1); // 输出: 2 (00000010)
return 0;
}
三.位操作符(&、|、^)
与 或 异或(操作数必须为整数)
计算之前需要转化为二进制 ,再分别按照每位进行对照计算
“&”\\按位与:两个位都为1时,结果才为1
“|”\\按位或:两个位都为0时,结果才为0
“^”\\按位异或:两个位相同为0,相异为1
//代码示例
#include <stdio.h>
int main() {
unsigned int a = 5; // 二进制: 00000101
unsigned int b = 3; // 二进制: 00000011
printf("a & b = %u\n", a & b); // 输出: 1 (00000001)
printf("a | b = %u\n", a | b); // 输出: 7 (00000111)
printf("a ^ b = %u\n", a ^ b); // 输出: 6 (00000110
用途:
例:不能创建临时变量(第三个变量),实现两个数的交换(一道变态的面试题)
对于这个问题要对于操作符有着强烈的印象和理解。在C语言中,可以通过使用异或(XOR)操作来实现两个变量的值交换,而不需要借用中间变量。这种方法利用了异或操作的性质:
1. **异或操作性质**:
- `a ^ a = 0`:任何数和自己异或的结果是0。
- `a ^ 0 = a`:任何数和0异或的结果是其本身。
- 异或操作具有交换律和结合律。
2. **交换原理**:
- 假设有两个变量 `a` 和 `b`,我们希望交换它们的值。
- 可以通过如下方式实现:
3. **执行步骤解析**:
- `a = a ^ b`:此时 `a` 存储了 `a` 和 `b` 的异或结果。
- `b = a ^ b`:由于 `a` 已经是 `a ^ b`,因此此操作将 `b` 更新为原始的 `a` 的值(即 `a ^ b ^ b = a`)。
- `a = a ^ b`:此时 `a` 存储了原始的 `b` 的值(即 `a ^ b ^ a = b`)。
通过以上三步操作,就完成了 `a` 和 `b` 的值交换,而不需要额外的中间变量。
#include <stdio.h>
void swap(int *a, int *b)
{
*a = *a ^ *b;
*b = *a ^ *b;
*a = *a ^ *b;
}
int main()
{
int x = 5, y = 10;
printf("Before swap: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("After swap: x = %d, y = %d\n", x, y);
return 0;
}
输出结果为:
Before swap: x = 5, y = 10
After swap: x = 10, y = 5
这样就成功地通过异或操作实现了变量 `x` 和 `y` 的值交换,而不借助中间变量。
四.赋值操作符(=、+=、-=、&=、*=……)
注意区分赋值(=)与关系操作符(==)
\\代码示例
#include <stdio.h>
int main()
{
int a = 10;
a += 5; // 等同于 a = a + 5
printf("a += 5: %d\n", a); // 输出: 15
a -= 3; // 等同于 a = a - 3
printf("a -= 3: %d\n", a); // 输出: 12
a *= 2; // 等同于 a = a * 2
printf("a *= 2: %d\n", a); // 输出: 24
a /= 4; // 等同于 a = a / 4
printf("a /= 4: %d\n", a); // 输出: 6
a %= 4; // 等同于 a = a % 4
printf("a %%= 4: %d\n", a); // 输出: 2
return 0;
}
五.单目操作符(!、-、+、&、*、sizeof、~、--、++)
! 逻辑反操作- 负值+ 正值& 取地址sizeof 操作数的类型长度(以字节为单位)~ 对一个数的二进制按位取反-- 前置、后置 --++ 前置、后置 ++* 间接访问操作符 ( 解引用操作符 )( 类型 ) 强制类型转换
注意:-- 和 ++ :他们都分为前置++(--)和后置++(--);
前置++(--)是先++,再赋值;
后置++(--) 是先赋值,再++(--);
\\++的代码示例
#include <stdio.h>
int main()
{
int a = 10;
printf("a++ = %d\n", a++); // 输出: 10
printf("a = %d\n", a); // 输出: 11
printf("++a = %d\n", ++a); // 输出: 12
printf("a = %d\n", a); // 输出: 12
return 0;
}
六.关系操作符(==、<、>)
>>=<<=!= 用于测试 “ 不相等 ”== 用于测试 “ 相等 ”
\\代码示例
#include <stdio.h>
int main()
{
int a = 10, b = 20;
printf("a == b: %d\n", a == b); // 输出: 0 (false)
printf("a != b: %d\n", a != b); // 输出: 1 (true)
printf("a > b: %d\n", a > b); // 输出: 0 (false)
printf("a < b: %d\n", a < b); // 输出: 1 (true)
printf("a >= b: %d\n", a >= b); // 输出: 0 (false)
printf("a <= b: %d\n", a <= b); // 输出: 1 (true)
return 0;
}
七.逻辑操作符(&&、||)
逻辑操作符有哪些:
1.&&(左边操作数若为假,右边无需计算)
逻辑与
2.|| (左边操作数若为真,右边无需计算)
逻辑或
区分逻辑与和按位与
区分逻辑或和按位或
1&2----->0
1&&2---->1
1|2----->3
1||2---->1
例 :请问以下程序输出的结果是什么?
#include <stdio.h>
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;
}
//程序输出的结果是什么?
在这段程序中,运算符
&&
是逻辑与运算符,而||
是逻辑或运算符。我们来看第一个i = a++ && ++b && d++;
的情况:
a++
是后缀递增,值为 0,但a
会变为 1。++b
是前缀递增,b
会先变为 3,然后使用这个值。d++
是后缀递增,值为 4,但d
会变为 5。由于逻辑与运算符
&&
的短路特性,整个表达式的值取决于第一个表达式的结果。具体来说:
a++
的结果是 0,a++
被计算为false
。- 由于
a++
是false
,逻辑与运算符的短路规则会使得++b
和d++
不再被计算。因此,最终的值
i
是 0。在
printf
语句中,a
已经变成 1,b
变成了 3(因为++b
被跳过),d
变成了 5(因为d++
被跳过),c
没有变化,仍然是 3。最终输出为:
a = 1 b = 3 c = 3 d = 5
八.条件操作符(?~:~)唯一的三目操作符
三目操作符:
exp1?exp2:exp3
真 计算 计算
假 不算 计算
\\代码示例
#include <stdio.h>
int main()
{
int a = 10, b = 20;
int max = (a > b) ? a : b; // 如果 a > b,max = a,否则 max = b
printf("max = %d\n", max); // 输出: 20
return 0;
}
九.逗号表达式(,)
exp1 , exp2 , exp3 , …… expn逗号表达式,就是用逗号隔开的多个表达式。逗号表达式,从左向右依次执行。整个表达式的结果是最后一个表达式的结果。
\\代码示例
#include <stdio.h>
int main()
{
int a = 1, b = 2;
int c = (a++, b++);
printf("a = %d, b = %d, c = %d\n", a, b, c); // 输出: a = 2, b = 3, c = 3
return 0;
}
十.下标引用、函数调用和结构成员([ ]、()、访问结构成员(.)、->)
1. [ ] 下标引用操作符操作数:一个数组名 + 一个索引值int arr [ 10 ]; // 创建数组arr [ 9 ] = 10 ; // 实用下标引用操作符。[ ] 的两个操作数是 arr 和 9 。
2. ( ) 函数调用操作符接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
3. 访问一个结构的成员. 结构体 . 成员名-> 结构体指针 -> 成员名
三.结尾
对于C语言的学习来说,操作符属于基础知识,需要大家反复实操在练习中了解真正的操作符用法,以解决各种难题,如本文中提到的各种面试题,或许很难想到,但我相信在大家的反复练习和学习中一定可以解决这种复杂的难题,提升自己。