深度解析C语言中数据的存储
前言
在VS编译器里有release和debug两种形式,debug包含调试信息,release不包含调试信息,并会对程序进行优化
int main() { int i = 0; int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; for (i = 0; i <= 12; i++) { arr[i] = 0; printf("hehe\n"); } return 0; }
运行这个程序,结果是死循环打印hehe,为什么呢?
我们看内存
在循环到第13次时,把存储变量i的地方改为0,i<=12仍成立,形成死循环
这是debug下出现的情况,但是如果是release的配置下,就不会出现上面死循环的情况,原因在下面这个图里
在debug配置下,储存i变量的地址比储存arr数组的地址高,可能会越界到i的地址导致死循环
在release配置下,储存i变量的地址比储存arr数组的地址低,不会出现越界到i导致死循环
(如果你非写一个死循环那就真的死循环了,release优化没有那么万能)
数据类型介绍
类型 | 大小(单位为字节) |
---|---|
char (字符数据类型) | 1 |
short (短整型) | 2 |
int (整形) | 4 |
long (长整型) | 4或8 |
long long (更长的整形) | 8 |
float (单精度浮点数) | 4 |
double (双精度浮点数) | 8 |
long long是在C99增加的
long的大小和环境有关,32位平台上是4个字节,64位平台上是8个字节
这些都是C中内置的数据类型
类型的意义:
使用这个类型开辟内存空间的大小(大小决定了使用范围)
看待内存空间的视角
1就是不同类型可以开辟不同大小的内存空间
对于2,看下图理解
类型的基本归类
整型家族
char
unsigned char
signed char
short
unsigned short [int]
signed short [int]
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
在C99后又加了long long
long long
unsigned long long [int]
signed long long [int]
这些都是整型家族里的数据类型,都分有符号和无符号类型
为什么说字符数据类型也是整型呢?
因为字符的本质其实是ASCII 码值,是整型,所以划分到整型家族
一般我们都默认不加unsigned或signed的默认为是有符号的,但是char就有点特殊
char里有三个
- char
- signed char
- unsigned char
signed char就是有符号的char,unsigned char就是无符号的char,但是什么都不加的char是有符号的还是无符号的标准是未定义的,取决于编译器的实现,跟编译器有关
其他都不加的int,short,long等都是默认为有符号的
那么为什么会有unsigned和signed之分呢?
因为生活中本来就有很多数据是没有负数的,比如身高,体重,长度
也有很多数据是有正负之分的,比如温度,放出或吸收热量
所以我们需要用unsigned和signed来区分是否有正负之分
举例子
int a = 10;
a是整型,有符号的整型,一个整型4个字节,即32个bit
0000 0000 0000 0000 0000 0000 0000 1010 (原码)
int a = -10;
1000 0000 0000 0000 0000 0000 0000 1010(原码)
符号位上,0表示正数,1表示负数,而且符号位不算有效位,只表示正负
有符号的int可以存 (-231)~(231-1)大小的数字
unsigned int a = -10;
1111 1111 1111 1111 1111 1111 0110(-10的补码)
无符号的int可以存0~232大小的数
因此,对于有正负的数,我们就用有符号的signed
对于没有正负之分的数,我们就用无符号的unsigned
浮点数家族
(只要表示小数就可以使用浮点型)
float
double
float精度低,存储的数值范围较小
double精度高,存储的数值范围较大
构造类型
数组类型
例如:
类型
int arr1[5]; ——> int [5]
int arr2[8]; ——> int [8]
char arr3[5] ——> char [5]
结构体类型
struct
枚举类型
enum
联合类型
union
指针类型
int *pi; char *pc; float* pf; void* pv;
空类型
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型
举一个例子
void test(void); //第一个void 表示函数不会返回值 //第二个void 表示函数不需要传任何参数 void* //void用于指针类型,以后会详细讲解