指针与内存

1,014 阅读5分钟

1、指针概念

指针:一个对象的 内存地址。即:一个对象在内存中的地址,被称为该对象的指针。

指针变量: 可以把指针变量看做是一个对象,这个对象中存储了两个数据:一个是自己的内存地址,一个是指向目标内存的地址

举例:

int a = 23;
int *b = &a; 

分别输出 `&a`、`&b`、`b`、`*b` 的值:
&a :  0x000000016ceb9b6c
&b :  0x000000016ceb9b60
b  :  0x000000016ceb9b6c
*b :  23


&: 取地址符   也就是拿出某对象在内存中的地址 
*: 解地址符 根据某内存地址找到这块地址存储的值。 

tips : 在上述示例中,int aint *b的区别是:

int a: a 是一个基本数据类型,句义为“定义一个整数变量a”。

*int a: a是一个指针,句义为“定义一个指针变量a,指向的内存数据块中存储的数据类型是int”

2、它们占用的内存

sizeof() 可以查看对象占用的内存。

基本数据变量占用:

基本数据类型句式结果(内存占用大小,单位/字节)
intsizeof(int)4
NSIntegersizeof(NSInteger)8
longsizeof(long)8
floatsizeof(float)4
doublesizeof(double)8
charsizeof(char)1

指针变量占用:

指针变量类型句式结果(内存占用大小,单位/字节)
int*sizeof(int*)8
NSInteger*sizeof(NSInteger*)8
long*sizeof(long*)8
float*sizeof(float*)8
char*sizeof(char*)8
NSString*sizeof(NSString*)8

指针变量类型占用内存大小均为8个字节

在C语言中,指针变量的“类型”只是用来表明这个指针变量指向的那块内存区域中存储的那段二进制数据是什么类型的,别无它意。不管什么类型的指针变量,它仍然仅仅是指针变量,所以仍然占用 8 字节。

为什么占用8个字节在于现在所用的计算机基本都是64位操作系统,64位地址线的不同状态的二进制数据组成了内存单元中的“地址”,2^64 bit 即为 8 Byte。

3、寻址——“按图索骥”

数据对象的地址我们很容易拿到,那我们怎么查看它在内存单元中具体的数据形式呢?

实例依然用上面的两句代码,我们先通过 Xcode 的“View Memory”查看a 和 b 在内存中的样子:

把上图择出重要信息重新整理一下,见下图:

3.1 “按图”

知道了a 的地址是 0x000000016ceb9b6c,又知道这块内存存储的数据要被解析成int类型,那就从 0x000000016ceb9b6c 开始“顺藤摸瓜” 找到连续的4个字节的二进制数据,也就是上图所示的十六进制形式的从内存低地址位到高低地址位的17 00 00 00,换算成二进制结果是多少呢?

385875968。这...好像不太对啊?!明明应该是23才对啊。

这里涉及到字节序中big-endian和little-endian的内容,这里采用little-endian的方式,也就是采用高地址向低地址拓展的方式来读写数据的,所以,这块的数据正确的应该是解析00 00 00 17 才对,换算成int 类型数据正是a的值 23。

3.2 “索骥”

在系统中我们通过使用指针变量其实是一种对数据的间接操作,因为我们先需要找根据这个指针变量的地址(指针变量的指针你)找到这个指针变量存储的值,而他存储的值又是目标数据的地址,即b中存储的值是a在内存中的地址,如果我对b进行解地址的话,系统会做些什么呢?

① 指针变量p的地址是:0x000000016ceb9b60,指针变量占用的内存大小为8个字节,那么按照上面示意图从0x000000016ceb9b60起始位"顺藤"摸8个字节为6C 9B EB 6C 01 00 00 00

② 注意高低地址为,择这块区域存储的数据应该是00 00 00 01 6C EB 9B 6C

③ 由于此块数据块被声明为一个指针变量,意思就是系统需要根据这块的数据去当做地址继续“索骥”,也就是去找地址位为0x000000016ceb9b6c 的数据块继续解析数据

④ 由于目标地址0x000000016ceb9b6c处的数据被声明告知为要被解析成int类型,那么系统将摸取四个字节的数据解析为int数据。

⑤ 至此,对 *p 解地址得到的数据为 a 的值:23

4、小结

4.1 字节序

字节序顾名思义就是字节的顺序,有litt-endian 和 big-endian之分。

little-endian:就是将数据的首端(高位字节)存放于高地址位,数据的末端(低位字节)存放于低地址位。

big-endian:就是将数据的首端(高位字节)存放于低地址位,数据的末端(低位字节)存放于高地址位。

目前大多数CPU都是使用X86架构,采用little-endian方式。ARM处理器是可以配置的。