OC底层原理探索文档汇总
以基本数据类型、引用类型、数组为例分析指针偏移的过程
1、&和*的理解
&和* 是两种指针运算符,&是取地址运算符,得到操作数的内存地址,取出内存地址功能,比如i 是一个int变量,则&i是这个i的地址。 *是间接寻址运算符,返回操作数所指定地址的变量的值。
代码:
/*
&是取地址运算符
*是间接寻址运算符
*/
void test11(){
int a = 1;
int *b = &a;
int c = *b;
NSLog(@"wenyi--a:%d,b:%p,c:%d",a,b,c);
}
2、基本数据类型
代码:
void baseDataTypeTest(){
int a = 9;
int b = 10;
int *f = &a;
NSLog(@"基本数据类型的变量a:%d -- 变量地址:%p",a,&a);
NSLog(@"基本数据类型的变量b:%d -- 变量地址:%p",b,&b);
NSLog(@"基本数据类型的指针a:%p -- 指针b:%p",f,f-1);
NSLog(@"指针变量f所指向的a变量的内容:%d -- 变量b的内容:%d",*f,*(f-1));
NSLog(@"指针变量f所在的内存地址:%p",&f);
}
运行结果:
基本数据类型
结果:
2021-10-12 12:29:14.880387+0800 指针偏移[70684:2791244] 基本数据类型的变量a:9 -- 变量地址:0x1040bb2bc
2021-10-12 12:29:14.880773+0800 指针偏移[70684:2791244] 基本数据类型的变量b:10 -- 变量地址:0x1040bb2b8
2021-10-12 12:29:14.880818+0800 指针偏移[70684:2791244] 基本数据类型的指针a:0x1040bb2bc -- 指针b:0x1040bb2b8
2021-10-12 12:29:14.880848+0800 指针偏移[70684:2791244] 指针变量f所指向的a变量的内容:9 -- 变量b的内容:10
2021-10-12 12:29:14.880872+0800 指针偏移[70684:2791244] 指针变量f所在的内存地址:0x1040bb2b0
分析:
- 1、基本数据类型存储在栈中,因此直接将10数值存储在栈中
- 2、栈的存储方式是从高地址到低地址,所以变量a的地址值比变量b的地址值要高
- 3、因为类型为int型,a占有4个字节,所以b地址比a地址低了4个字节
- 4、&a是将变量a的地址取出来
- 5、int *f = &a是将变量a的地址赋值到指针变量e上
- 6、打印f和f-1可以看到分别打印的是a和b的地址,也可以证明指针变量存储的就是地址
- 7、为什么是f-1,而不是f+1,这是因为栈的存储方式是从高地址到低地址,所以得到b的指针需要通过f-1
- 8、*f是对指针变量使用 *,可以得到指针变量存储的地址所存储的内容,因此 * f, *(f-1)分别到的a和b变量的内容
- 9、也可以对指针变量f取地址,取到的地址就是指针变量的地址,被b地址小了8个字节
图示:
3、引用类型
代码:
void quoteTest(){
NSperson *person1 = [NSperson alloc];
NSperson *person2 = [NSperson alloc];
NSLog(@"引用类型的指针person1:%@ -- 变量地址:%p",person1,&person1);
NSLog(@"引用类型的指针person2:%@ -- 变量地址:%p",person2,&person2);
}
运行结果:
引用类型
指针是8个字节,所以相差8个字节
结果:
2021-10-12 12:29:14.881025+0800 指针偏移[70684:2791244] 引用类型的指针person1: -- 变量地址:0x1040bb2b8
2021-10-12 12:29:14.881069+0800 指针偏移[70684:2791244] 引用类型的指针person2: -- 变量地址:0x1040bb2b0
分析:
- 指针是在栈中,对象是在堆中
- 一个指针占8个字节,所以指针按地址空间来说&p1和&p2二者之间相差8个字节
- 而指针本身是紧挨着的,也就是说&p1的下一个指针就是&p2
图示:
4、数组类型
代码:
void arrayTest(){
int a = 10;
int aa = 12;
int c[4] = {1,2,3,4};
int b = 20;
int *d = c;
NSLog(@"数组所在地址:%p -- 数组首元素地址:%p -- 数组第二元素地址:%p",&c,&c[0],&c[1]);
NSLog(@"数组所在地址:%p -- 数组第二元素地址:%p -- 数组第三元素地址:%p",d,d+1,d+2);
NSLog(@"数组第一个元素:%d -- 数组第二元素地址:%d -- 数组第三元素地址:%d",*d,*(d+1),*(d+2));
NSLog(@"基本数据类型a:%p -- 基本数据类型b:%p -- aa:%p",&a,&b,&aa);
}
运行结果:
结果:
2021-10-12 12:29:14.881097+0800 指针偏移[70684:2791244] 数组所在地址:0x1040bb2a0 -- 数组首元素地址:0x1040bb2a0 -- 数组第二元素地址:0x1040bb2a4
2021-10-12 12:29:14.881122+0800 指针偏移[70684:2791244] 数组所在地址:0x1040bb2a0 -- 数组第二元素地址:0x1040bb2a4 -- 数组第三元素地址:0x1040bb2a8
2021-10-12 12:29:14.900159+0800 指针偏移[70684:2791244] 数组第一个元素:1 -- 数组第二元素地址:2 -- 数组第三元素地址:3
分析:
- 数组名不是指针
- &c是获取数组的空间地址,&c[0]是获取数组的第一个数据的空间地址,他们两个是一个地址
- 因为数据是int型,每个数据占用4个字节,所以数据的地址都相隔四个字节,而指针本身是紧挨着的
- d获取的是数组的指针,d+1是&c[1]地址空间的指针,指针的+1就会走到下个指针,我们可以通过指针的偏移来获取数据,下一个指针就是下一个数据的地址空间。
- 数组的数据从前到后顺序存储,而不是从后到前
图示: