思维导图:
1.整型
整型的分类:
char(字符型)//因为字符对应的ASSIC码也是整型数字
int(整型)
long (长整型)
long long(长长整型)
2.浮点型
浮点型;
float(单精度浮点型)
double(双精度浮点型)
3.构造类型
构造类型:
数组:int arr[10]
结构体类型:struct
枚举类型:enum
联合类型:union
4.指针类型
指针类型分类:
int *
char*
float*
void*//void*可以转换为任何指针类型
5.空类型
空类型就是void类型,
通常用于表示函数,指针类型
6.三码:原码,反码,补码
6.1补码的意义:
在内存中,计算机存储的是补码。你可能觉得麻烦,但存在即合理。那为什么计算机内存的是补码呢?原来是因为cpu只会算加法。只会算加法就要用补码?我们可以来分析一下:
int main() {
int a = 1;
int b = 1;
int c = a - b;
printf("%d\n", c);
return 0;
}
比如上面的代码,cpu计算:a-b=1-1=1+(-1);
原码计算:
1: 00000000 00000000 00000000 00000001
-1: 10000000 00000000 00000000 00000001
1+(-1): 10000000 00000000 00000000 00000010//-2
计算的结果就是-2.显然不对。
现在我们用补码试一下,看看能不能得到正确的结果:
-1: 10000000 00000000 00000000 00000001//原码
11111111 11111111 11111111 11111110//反码
11111111 11111111 11111111 11111111//补码
1: 00000000 00000000 00000000 00000001//正数的原码,反码,补码相同
1+(-1):00000000 00000000 00000000 00000000//进位,只保留前三十二位。
可以看到在采用了补码的处理方式以后就可以得到正确的结果了。
7.大小端
大端存储:高数据存在低地址(在我们普通人的眼中觉得较为正常的存储方式)
小端存储:低数据存在低地址,高数据存在高地址。
在这里,我闷可以看看vs2019编译器是使用那种类型的存储方式;
可以看到vs2019使用的是小端存储方式。
但是这是我们自己通过调试的方法查到的,那我们能不能通过一段代码来查找一下呢?
在这里先讲一下思路:比如你将一个1输入进去,1的二进制码是;
00000000 00000000 00000000 00000001,可以看到二进制码里面只有一个1。假如这时,我们再定义一个字符型指针变量来接收内存里的1的二进制码,因为char型变量只接受一个字节。如果是小端存放的话,那字符型变量内就存的是0了。如果是大端存放的话,存的就是1。通过这两个区别我们就可以来设计代码了,代码如下:
int main() {
int a = 1;
char *b = (char*)&a;//强制类型转换一下,因为int型与char*不兼容
if (*b == 1) {
printf("小端\n");
}
else {
printf("大端\n");
}
return 0;
}
在这里还可以把代码升级一下:
int check() {//写成函数的形式
int a = 1;
return *(char*)&a;
}
int main() {
int ret = check();
if (ret == 1)
printf("小端\n");
else
printf("大端\n");
return 0;
}
8.代码练习,加强理解
8.1:
int main() {
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("%d %d %d\n", a, b, c);
return 0;
}
各位看官可以猜一下这段代码的结果是什么?
相信很多人会迷惑,不就是打印-1吗?有什么好猜的?现在来看看结果是否如各位所料:
可以看到结果似乎不是这样子的。
这是为什么呢?
分析:
整型-1:11111111111111111111111111111111//补码
字符型-1:11111111//只有八位,因为字符型只有一个字节的大小。
a:11111111 整型提升:11111111 11111111 11111111 11111111
//在前面补符号位,补够32个比特位
b:11111111 整型提升:11111111 11111111 11111111 11111111
//在前面补符号位,补够32个比特位
c:11111111 整型提升:00000000 00000000 00000000 11111111
//因为c是无符号变量,没有符号位,所以在前面补零
可以看到,在发生整型提升以后,c就与a,b变量不同了。也就是这个不同,导致了c变量的结果的不同。
8.2:
int main() {
char a = -128;
printf("%u\n", a);//打印无符号形式的a
return 0;
}
各位看官可以来猜一猜这一段代码打印的又是什么呢?
看看答案:
可以看到打印的竟然不是-128而是一个奇奇怪怪的数字,那这是怎么来的呢?
-128:10000000 00000000 00000000 10000000
//原码
11111111 11111111 11111111 01111111
//反码
11111111 11111111 11111111 10000000
//补码
现在用一个字符型接收-128:100000000//发生截断只接收8个比特位
打印时发生整型提升:11111111 11111111 11111111 10000000
//要打印时就是打印这个,%u这个变量的原码,
反码,补码相同,打印的值就是这个二进制的值
这个二进制对应的就是那个奇怪的值。
8.3:
int main() {
unsigned int i = 0;
for (i = 9;i >= 0;i--) {
printf("%u\n", i);
}
return 0;
}
聪明的你在将这个代码输入到聪明的vs编译器以后会发现这个代码是执行不了的:
unsigned int:一直大于0,导致上面的那段代码会无限进行下去。所以会报错。
8.4:
#include<string.h>
int main() {
char a [1000];
for (int i = 0;i < 1000;i++) {
a[i] = -1 - i;
}
printf("%d\n", strlen(a));
return 0;
}
这段代码的答案会是1000吗?
答案是:不会。
为什么呢?
//1.我们都知道,strlen()遇到'\0'时才会停下所以我们只要找到'\0'
在哪里就可以了。
//2.字符型变量里的0就是'\0',那我们找到0就行了。
找到0:
因为char型变量的范围是-127~128,所以-1-i,在剪完一圈以后,也就是上面的圈圈逆时针走一圈就找到0了。这一圈的长度就是255。
8.5:
int main() {
unsigned char i = 0;
for (i = 0;i <= 255;i++) {
printf("Hello wolrd!!!");
}
return 0;
}
猜猜会发生什么?
死循环,没错,就是死循环。因 unsigned char变量的范围是0~255一定不会超过255。
好了,今天的分享就到这里了,如有错误,感谢指正。