C语言对内存地址的封装
譬如在C语言中 int a; a = 5; a += 4; // a == 9;
结合内存来解析C语言语句的本质:
int a; // 编译器帮我们申请了1个int类型的内存格子(长度是4字节,地址是确定的,但是只有编译器知道,我们是不知道的,也不需要知道。),并且把符号a和这个格子绑定。
a = 5; // 编译器发现我们要给a赋值,就会把这个值5丢到符号a绑定的那个内存格子中。
a += 4; // 编译器发现我们要给a加值,a += 4 等效于 a = a + 4;编译器会先把a原来的值读出来,然后给这个值加4,再把加之后的和写入a里面去。
C语言中数据类型的本质含义
C语言中数据类型的本质含义是:表示一个内存格子的长度和解析方法。
数据类型决定长度的含义:我们一个内存地址(0x30000000),本来这个地址只代表1个字节的长度,但是实际上我们可以通过给他一个类型(int),让他有了长度(4),这样这个代表内存地址的数字(0x30000000)就能表示从这个数字(0x30000000)开头的连续的n(4)个字节的内存格子了(0x30000000 + 0x30000001 + 0x30000002 + 0x30000003)。
数据类型决定解析方法的含义:譬如我有一个内存地址(0x30000000),我们可以通过给这个内存地址不同的类型来指定这个内存单元格子中二进制数的解析方法。譬如我 (int)0x30000000,含义就是(0x30000000 + 0x30000001 + 0x30000002 + 0x30000003)这4个字节连起来共同存储的是一个int型数据;那么我(float)0x30000000,含义就是(0x30000000 + 0x30000001 + 0x30000002 + 0x30000003)这4个字节连起来共同存储的是一个float型数据;
之前讲过一个很重要的概念:内存单元格子的编址单位是字节。
(int *)0;
(float *)0;
(short)0;
(char)0;
int a; // int a;时编译器会自动给a分配一个内存地址,譬如说是0x12345678
(int *)(&a); // 等价于(int *)0x12345678
(float *)a;
C语言中,函数就是一段代码的封装。函数名的实质就是这一段代码的首地址。所以说函数名的本质也是一个内存地址。
用指针来间接访问内存
关于类型(不管是普通变量类型int float等,还是指针类型int * float *等),只要记住:
类型只是对后面数字或者符号(代表的是内存地址)所表征的内存的一种长度规定和解析方法规定而已。
C语言中的指针,全名叫指针变量,指针变量其实很普通变量没有任何区别。譬如int a和int *p其实没有任何区别,a和p都代表一个内存地址(譬如是0x20000000),但是这个内存地址(0x20000000)的长度和解析方法不同。a是int型所以a的长度是4字节,解析方法是按照int的规定来的;p是int *类型,所以长度是4字节,解析方法是int *的规定来的(0x20000000开头的连续4字节中存储了1个地址,这个地址所代表的内存单元中存放的是一个int类型的数)。
用数组来管理内存
数组管理内存和变量其实没有本质区别,只是符号的解析方法不同。(普通变量、数组、指针变量其实都没有本质差别,都是对内存地址的解析,只是解析方法不一样)。
int a; // 编译器分配4字节长度给a,并且把首地址和符号a绑定起来。
int b[10]; // 编译器分配40个字节长度给b,并且把首元素首地址和符号b绑定起来。
数组中第一个元素(a[0])就称为首元素;每一个元素类型都是int,所以长度都是4,其中第一个字节的地址就称为首地址;首元素a[0]的首地址就称为首元素首地址。