一、算数操作符
- 除了% 操作符之外,其他的几个操作符可以作用于整数和浮点数。
- 对于/ 操作符如果两个操作数都为整数,执行整数除法。而只要有浮点数执行的就是浮点数除
法。 - % 操作符的两个操作数必须为整数。返回的是整除之后的余数。
1、类型转换
C语言中整数除以整数还是整数,直接把小数部分给舍去了,如果两个不同类型的变量进行算数运算,就会触发隐式类型转换,有一个内置的转换规则,短的往长的转(int 和 double 这两个,double长)
- 例子1
#include<stdio.h>int main()
{//5 -> int//5.0 -> double//5.0f ->floatint a = 5;int b = 2;printf("%d\n",a / b);return 0;
}
- 例子2:
#include<stdio.h>int main()
{//5 -> int//5.0 -> double//5.0f ->floatdouble a = 5.0;int b = 2.0;printf("%f\n", a / b);return 0;
}
- 例子3
#include<stdio.h>int main()
{//5 -> int//5.0 -> double//5.0f ->floatint a = 5;int b = 2;printf("%f\n", (double)a / b);return 0;
}
这里涉及到了——强制类型转换(显示类型转换)
- 例子4——交换函数如果调用的时候没有解引用会发生什么?
void swap(int* x, int* y)
{int tem = *x;*x = *y;*y = tem;
}
int main()
{int a = 5;int b = 2;swap(a, b);
这里将swap(a,b)传入的的int型a,b,会在swap函数中隐式自动转换为int*
函数中就是(int * 5, int *2)下面 *5 和 2,表示将地址为5的内存进行解引用 和地址为2的内存解引用了——这两块内存我们是不能用的,只有自己申请的内存我们才能使用(自己创建变量才会申请空间~)
编译器没有报错,但是最后程序会崩溃,说明编译器会自动把int隐式转换为 int,这是一件非常让人讨厌的事情 。代码出错了但是并没有直接给出错误提示。
做出了这样的分类:
如果这个语言越支持隐式类型转换,称为类型越弱
如果这个语言越不支持隐式类型转换,称为类型越强~
一般总结——强类型好于弱类型;静态类型好于动态类型
2、运算符优先级
printf("%d\n",2+3*5);
结果是多少
二. 移位运算符
1.左移运算符 <<
#include<stdio.h>int main()
{int a = 10;printf("%d\n", a << 33);return 0;
}
2. 右移运算符 >>
三、位操作符
-
&
-
|
-
^
异或的重要特性:
a^0 -> a
a^a ->0 -
练习
#include<stdio.h>int main()
{int a = 1;int b = 2;//printf("%d\n", a^ b);printf("%x\n", ~a);return 0;
}
- 练习:
编写代码实现:求一个整数存储在内存中的二进制中1的个数。
#include<stdio.h>//如何计算一个数的二进制中有几个1
//转换为如何取出一个数字的每一位,判断是否为1
int bitoneCount(int num) {int count = 0;for (int i = 0; i < 32; i++){if (num & (1 << i)) {count++;}}return count;
}
四、 赋值操作符
注意区分一下赋值和初始化的区别~~
赋值:变量已经有了,进行修改
初始化:第一次创建变量,设置一个值
eg:
五、单目操作符
5.2 sizeof和数组
编译期间求值。
5.3 强制类型转换
1.在C语言中的使用
int a = 10;double b = (double)a;
int a = 0x11223344;short b = (short)a;//int 4个字节(-21亿~21亿也是0~42亿9千万) short 2个字节(0~65535 也是-32768-32768)printf("%x\n", b);
这里强制类型转换有一个从int强转为short ,会出现直接截断现象
反过来:
short a = 0xF122;int b = (int)a;//int 4个字节(-21亿~21亿也是0~42亿9千万) short 2个字节(0~65535 也是-32768-32768)printf("%x\n", b);
前面补的是符号位~short 0xF122-> 0000 0000 0000 0000 1111 0001 0010 0010
从short转到int 的时候 转换为 1111 1111 1111 1111 1111 0001 0010 0010
short a = 0x1122;int b = (int)a;//int 4个字节(-21亿~21亿也是0~42亿9千万) short 2个字节(0~65535 也是-32768-32768)printf("%x\n", b);
前面补的是符号位~short 0x1122-> 0000 0000 0000 0000 0001 0001 0010 0010
从short转到int 的时候 转换为 0000 0000 0000 0000 0000 0001 0010 0010
小结:
从长的往短的强转的时候,直接截断高位,
从短的往长的强转的时候,填充的都是符号位
把short强转为int的时候,前面高位两个字节,填充的都是符号位;
把int强转为short的时候,前面高位的两个字节,就直接舍去不要了。
隐射类型转换也是类似的规则~~
六、关系操作符
=
< >
<=
!= 用于测试“不相等”
== 用于测试“相等”
七、 逻辑操作符
&& 逻辑与
|| 逻辑或
八、条件操作符
九、逗号表达式
exp1, exp2, exp3, …expN
十、下标引用、函数调用和结构成员
1.[ ] 下标访问操作符
操作数:一个数组名 + 一个索引值
在我们C语言中数组和指针都可以进行[ ]操作。
- 对数组来说[ ] 的有效下标范围 是【0,length-1】,如果下标越界,就会出现未定义行为~
- 对于指针来说 【】范围就不好确定
2.( ) 函数调用操作符
接受一个或者多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。
- 函数指针:是一个变量,里面存了个整数,是一个内存地址 ,那我们创建一个函数,是如何到内存中去的?
- 分析一下这个过程:
- 编译:把.c文件变成二进制exe文件
- 运行:双击 exe 文件,让系统执行程序。(exe文件中包含了CPU运行时要执行的指令,以及依赖的数据,原来在.c文件中写的函数就被转换为二进制的机器指令存放到exe文件中)
3.访问一个结构的成员
. 结构体.成员名
-> 结构体指针->成员名
十一、 表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定。
同样,有些表达式的操作数在求值的过程中可能需要转换为其他类型。
12.1 隐式类型转换
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型
提升。
整型提升的意义:
表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度
一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长
度。
通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令
中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转
换为int或unsigned int,然后才能送入CPU去执行运算。
- 不同类型 的变量相互赋值的
- 不同类型的变量混合运算
一个16进制数是4个比特位,两个16进制数是8个比特位(一个字节),四个16进制是2个字节 也就是一个short