前言:
对于初学者而言,C语言的大难点主要存在两大类,一个是变化复杂的指针类,另一个就是相关的数据存储内存分布。本篇文章重点介绍与C语言相关的数据存储
概述:
在C语言中,数据的类型有多种,既然是数据的存储,自然不能避免论及数据类型。在介绍各自类型之前,我们应该先了解C语言为什么要把数据按类型分类?
数据类型的意义:
- 该数据使用这个类型在内存空间中所开辟的空间的大小,而大小也决定了使用范围
- 我们通过不同的类型,所看待数据的视角也不同
数据类型的基本分类
我们把数据类型主要分类为:整型家族,浮点型家族,构造类型,指针类型,空类型。下面我们先浅谈下的类型大类涵盖的具体类型
整型家族
char | short | int | long |
---|---|---|---|
unsigned char | unsigned short | unsigned int | unsigned long |
signed char | signed short | signed int | signed long |
浮点型家族
float | double |
---|
构造类型-自定义类型
数组类型 | 结构体类型(struct) | 枚举(enum) | 联合体(union) |
---|
ps:数组类型也数组自定义类型:
eg:int arr[10] – 数据类型就是int [10],
int arr[5] – 数据类型就是int [5]
指针类型
int* pi | char* pc | float* pf | void* pv |
---|
空类型
void表示空类型(无类型) | 通常应用于函数的返回类型,函数的参数,指针类型 |
---|
数据在内存中的存储方式:
当我们了解了数据类型的基本分类后,接下我们需要明白一点:数据在计算机中都是以01的二进制进行存储的
1.数据的二进制表示形式有三种:原码,反码,补码
原码:直接按照数据数值直接写出二进制
反码:原码取反
补码:反码+1 — 一秒学会原反补码
数据的存储:
接下来进入本章的重点:数据的存储
- 数据在内存中以二进制的形式存储。
- 数据在内存中是以补码的形式存储的。详情见->C语言中只能存补码的原因
下面我们通过几个例题来详解整型家族在内存中的存储
例题一:
int main()
{
char a = -1;
//首先想到它在内存中存储的是补码
//先写出原码
//10000000000000000000000000000001
//取反+1得补码
//11111111111111111111111111111111
//又因为是char类型,只能存8个比特位
//11111111
//整型提升:有符号位的,前面补符号位
//11111111111111111111111111111111 --补码
//补码以%d形式打印的时候,要看的是它的原码 --打印-- -1
signed char b = -1;
//存入11111111
//有符号的char 和 a相同
unsigned char c = -1;
//存入11111111
//无符号的char
//整型提升:无符号位的前面补0
//00000000000000000000000011111111 --符号位是0,是正数,补码和原码相同 --打印-- 255
printf("a=%d,b=%d,c=%d", a, b, c);//因为要输出的是%d类型,也就是int类型,涉及整形提升
retrun 0;
}
补充:
1.char类型 到底是signed char 还是unsigned char?
2.C语言标准并没有规定,取决于编译器。
3.int 是signed int是C语言标准规定好的。
4.short也是signed short。
例题二
int main()
{
char a = -128;
//100000000000000000000000010000000
//111111111111111111111111101111111
//111111111111111111111111110000000 -补码
//10000000 -存入内存中的char
//按原来char的补码进行整型提升
//111111111111111111111111110000000
//%u打印无符号的整型,就是把整形提升后的二进制数看成正数
printf("%u", a);//429...168一个大值
return 0;
}
//char类型
//有符号的char的取值范围:-128~127
例题三
int main()
{
int i = -20;
//10000000000000000000000000010100 -原
//11111111111111111111111111101011 -反
//11111111111111111111111111101100 -补
unsigned int j = 10;
//00000000000000000000000000001010 -原-反-补
// 00000000000000000000000000001010 -- -10
// 11111111111111111111111111101100 -补-- -20
// 11111111111111111111111111110110 -- 相加后得
printf("%u\n", i + j);
return 0;
}
例题四
int main()
{
//死循环
unsigned int i = 0;//在此处i 恒 >=0,因为是一个无符号数,最小为0
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);//%u和%d决定了i最终被解析成什么样的值,
}
return 0;
}
例题五
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
//-1 -2 -3 .....-127 -128 127 126 125......3 2 1 0 -1 -2 ...-127 -128 127...
printf("%d", strlen(a));//找\0 -> 0(\0的ascii码值就是0)
//结果为225
return 0;
}
小结:
要想判断出不同类型的打印结果需要注意以下几个方面:
- 看待数据类型的角度,此数据是char,int,double…
- 注意输出的类型:%d,%u,%c…详情见->常见的输出操作符
- 是否存在整型提升
- 判断的切入点谨记一点:数据在内存中以补码形式存储
作者:@萝卜头kimi