1. 操作符分类
算术操作符
移位操作符
位操作符
赋值操作符
单目操作符
关系操作符
逻辑操作符
条件操作符
逗号表达式
下标引用、函数调用和结构成员
2. 算术操作符
运算符 | 意义 | 说明 |
---|---|---|
+ | 加法 | |
- | 减法 | 如果减去一个负数,则- 左右必须加空格 |
* | 乘法 | |
/ | 除法 | 两个整数相除结果是整数(小数部分被截取);两个数中有一个是浮点数,其结果就是浮点数 |
% | 取模 | 求整数除法的余数,其正负取决于被除数 |
-
除了 % 操作符之外,其他的几个操作符可以作用于整数和浮点数。
-
对于 / 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除法。
-
% 操作符的两个操作数必须为整数。返回的是整除之后的余数。
这五种运算符的运算优先级为*
=/
=%
>+
=-
,即 *、/、% 具有相同的优先级,它们的级别大于 + 和 -,+ 和 - 具有相同的优先级;优先级相同时按从左向右的顺序运算。使用括号可以打破上述优先级规则,括号具有最高的优先级。
在 C语言中的加、减、乘与通常数学运算中的定义完全相同,几乎可以用于所有数据类型;而除法运算在 C语言中较为特殊,详述如下。
1) 除法运算
C语言中使用/
对整型数据进行除运算时,结果的小数部分将被截掉,其被看成是“整除运算”;但若除数或被除数有一个是带小数位的实数,则被看成是“实数除法”,结果中的小数位将进行四舍五入处理。例如:
int Average = 8 / 3; //运行后变量 Average 的值为 2
float Average = 8 / 3; //运行后变量 Average 的值为 2.000000
float Average = 8 / 3.0; //运行后变量 Average 的值为 2.666667
float Average = 8.0 / 3; //运行后变量 Average 的值为 2.666667
float Average = 8.0 / 3.0; //运行后变量 Average 的值为 2.666667
另外,编写代码时,若除数或被除数有一个是带小数位的实数,有的编译器默认此数据类型是double,如果定义的是float类型,可能会有如下warning:
warning C4305: “初始化”: 从“double”到“float”截断
解决办法:
1.数字的后面加f标识转换为float数据类型,如:
float a = 8.0f / 3.0f;
2.把定义的float函数和参数改成double,如:
double a = 8.0 / 3.0;
2) 求模运算
用%
求除法余数的运算在编程中称为求模。求模运算只能用于整型数据。例如:
int a = 8 % 3; //运行后变量 a 的值为 2,即 8 除以 3 的余数 2
3) 字符型数据的算术运算
在 C语言中,字符型的数据也可以参加算术运算。前面讲过,字符在计算机中也是以数字的形式存在的,每一个字符都对应于一个数字(见 ASCII 标准字符代码表),因而字符参加算术运算实际上就是对应字符的十进制字符代码参加运算。例如:
int Su = 'A' + 'B' + 20; //运行后变量 Su 的值为 151
在“ASCII 标准字符代码表”中,字符 ‘A’ 的十进制字符代码是 65,字符 ‘B’ 的十进制字符代码是 66,因而上述语句的计算结果相当于以下语句:
int Su = 65 + 66 + 20;
3. 移位操作符
<< 左移操作符
>> 右移操作符
注:移位操作符的操作数只能是整数。
3.1 左移操作符
二进制左移运算符,将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。
移位规则:
左边抛弃、右边补0
3.2 右移操作符
二进制右移运算符,将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
移位规则:
首先右移运算分两种:
逻辑移位
左边用0填充,右边丢弃
算术移位
左边用原该值的符号位填充,右边丢弃
补充说明:
- 数据在内存中始终是以二进制形式存放的,数值是以补码表示的。
整数的二进制表示形式其实有三种:
- 原码:直接根据数值写出的二进制序列就是原码
- 反码:反码的符号位不变,其他位按位取反就是反码
- 补码:反码+1,就是补码
对于正整数来说,它的原码、反码、补码相同
例:负数 -1
原码:10000000000000000000000000000001
反码:11111111111111111111111111111110
补码:11111111111111111111111111111111
警告⚠ :
对于移位运算符,不要移动负数位,这个是标准未定义的。例如:
int num = 10;
num>>-1;//error
4. 位操作符
位运算符作用于位,并逐位执行操作。&、 | 和 ^ 的真值表如下所示:
p | q | p & q | p|q | p ^ q |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
0 | 1 | 0 | 1 | 1 |
1 | 1 | 1 | 1 | 0 |
1 | 0 | 0 | 1 | 1 |
假设如果 A = 60,且 B = 13,现在以二进制格式表示,它们如下所示:
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
下表显示了 C 语言支持的位运算符。假设变量 A 的值为 60,变量 B 的值为 13,则:
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与操作,按二进制位进行"与"运算。运算规则: 0&0=0; 0&1=0; 1&0=0; 1&1=1; | (A & B) 将得到 12,即为 0000 1100 |
| | 按位或运算符,按二进制位进行"或"运算。运算规则: 0|0=0; 0|1=1; 1|0=1; 1|1=1; | (A |B) 将得到 61,即为 0011 1101 |
^ | 异或运算符,按二进制位进行"异或"运算。运算规则: 0^0=0; 0^1=1; 1^0=1; 1^1=0; | (A ^ B) 将得到 49,即为 0011 0001 |
~ | 取反运算符,按二进制位进行"取反"运算。运算规则: ~1=-2; ~0=-1; | (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
- 注:他们的操作数必须是整数。
练习一下:
#include <stdio.h>
int main()
{
int num1 = 1;//1的二进制为00000000000000000000000000000001
int num2 = 2;//2的二进制为00000000000000000000000000000010
int a = num1 & num2;//1和2进行按位与操作后结果为00000000000000000000000000000000
int b = num1 | num2;//1和2进行按位或操作后结果为00000000000000000000000000000011
int c = num1 ^ num2;//1和2进行按位异或操作后结果为00000000000000000000000000000011
printf("a=%d\n", a);
printf("b=%d\n", b);
printf("c=%d\n", c);
return 0;
}
输出结果为:
a=0
b=3
c=3
一道变态的面试题:
不能创建临时变量(第三个变量),实现两个数的交换。
方法1:
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
a = a + b;
b = a - b;
a = a - b;
printf("a = %d b = %d\n", a, b);
return 0;
}
但是这种方法有缺陷,数值太大会溢出。
方法2:利用异或 ^ 来交换两个数的值
#include<stdio.h>
int main()
{
unsigned int a = 60; //0011 1100
unsigned int b = 13; //0000 1101
printf("a=%d,b=%d", a, b); //输出a,b的值
printf("\n");
a = a ^ b; //a=a^b=0011 0001
b = a ^ b; //b=a^b=0011 1100
a = a ^ b; //a=a^b=0000 1101
printf("a=%d,b=%d", a, b); //输出a,b的值
return 0;
}
运行结果:
a=60,b=13;
a=13,b=60;
仅用一行代码实现的方法:
a^=b^=a^=b;
这种利用位运算的交换方法只适用于整型变量,不能用于浮点型变量!
- 两个相同的数字异或后的结果是0,0和任何数字异或后还是这个数字本身;
- 两个数异或后的结果再与其中一个数异或可以得到另一个数。
这种方法不会溢出。
练习:
编写代码实现:求一个整数存储在内存中的二进制中1的个数。
参考代码:
//方法1
#include <stdio.h>
int main()
{
int