指針偏移的認(rèn)識(shí)

OC底層原理探索文檔匯總

以基本數(shù)據(jù)類型、引用類型、數(shù)組為例分析指針偏移的過程

1、&和*的理解

&和* 是兩種指針運(yùn)算符,&是取地址運(yùn)算符,得到操作數(shù)的內(nèi)存地址,取出內(nèi)存地址功能,比如i 是一個(gè)int變量,則&i是這個(gè)i的地址。 *是間接尋址運(yùn)算符,返回操作數(shù)所指定地址的變量的值。

代碼:

/*
 &是取地址運(yùn)算符
 *是間接尋址運(yùn)算符
 */
void test11(){
    int a = 1;
    int *b = &a;
    int c = *b;
    
    NSLog(@"wenyi--a:%d,b:%p,c:%d",a,b,c);
}

2、基本數(shù)據(jù)類型

代碼:

void baseDataTypeTest(){
    int a = 9;
    int b = 10;
    int *f = &a;
    
    NSLog(@"基本數(shù)據(jù)類型的變量a:%d -- 變量地址:%p",a,&a);
    NSLog(@"基本數(shù)據(jù)類型的變量b:%d -- 變量地址:%p",b,&b);
    NSLog(@"基本數(shù)據(jù)類型的指針a:%p -- 指針b:%p",f,f-1);
    NSLog(@"指針變量f所指向的a變量的內(nèi)容:%d -- 變量b的內(nèi)容:%d",*f,*(f-1));
    NSLog(@"指針變量f所在的內(nèi)存地址:%p",&f);
}

運(yùn)行結(jié)果:

基本數(shù)據(jù)類型
 
 結(jié)果:
 2021-10-12 12:29:14.880387+0800 指針偏移[70684:2791244] 基本數(shù)據(jù)類型的變量a:9 -- 變量地址:0x1040bb2bc
 2021-10-12 12:29:14.880773+0800 指針偏移[70684:2791244] 基本數(shù)據(jù)類型的變量b:10 -- 變量地址:0x1040bb2b8
 2021-10-12 12:29:14.880818+0800 指針偏移[70684:2791244] 基本數(shù)據(jù)類型的指針a:0x1040bb2bc -- 指針b:0x1040bb2b8
 2021-10-12 12:29:14.880848+0800 指針偏移[70684:2791244] 指針變量f所指向的a變量的內(nèi)容:9 -- 變量b的內(nèi)容:10
 2021-10-12 12:29:14.880872+0800 指針偏移[70684:2791244] 指針變量f所在的內(nèi)存地址:0x1040bb2b0

分析:

  • 1、基本數(shù)據(jù)類型存儲(chǔ)在棧中,因此直接將10數(shù)值存儲(chǔ)在棧中
  • 2、棧的存儲(chǔ)方式是從高地址到低地址,所以變量a的地址值比變量b的地址值要高
  • 3、因?yàn)轭愋蜑閕nt型,a占有4個(gè)字節(jié),所以b地址比a地址低了4個(gè)字節(jié)
  • 4、&a是將變量a的地址取出來
  • 5、int *f = &a是將變量a的地址賦值到指針變量e上
  • 6、打印f和f-1可以看到分別打印的是a和b的地址,也可以證明指針變量存儲(chǔ)的就是地址
  • 7、為什么是f-1,而不是f+1,這是因?yàn)闂5拇鎯?chǔ)方式是從高地址到低地址,所以得到b的指針需要通過f-1
  • 8、*f是對(duì)指針變量使用 *,可以得到指針變量存儲(chǔ)的地址所存儲(chǔ)的內(nèi)容,因此 * f, *(f-1)分別到的a和b變量的內(nèi)容
  • 9、也可以對(duì)指針變量f取地址,取到的地址就是指針變量的地址,被b地址小了8個(gè)字節(jié)

圖示:

基本數(shù)據(jù)類型的指針偏移.png

3、引用類型

代碼:

void quoteTest(){
    NSperson *person1 = [NSperson alloc];
    NSperson *person2 = [NSperson alloc];
    NSLog(@"引用類型的指針person1:%@ -- 變量地址:%p",person1,&person1);
    NSLog(@"引用類型的指針person2:%@ -- 變量地址:%p",person2,&person2);
}

運(yùn)行結(jié)果:

引用類型
 指針是8個(gè)字節(jié),所以相差8個(gè)字節(jié)
 
 結(jié)果:
 2021-10-12 12:29:14.881025+0800 指針偏移[70684:2791244] 引用類型的指針person1:<NSperson: 0x105014c50> -- 變量地址:0x1040bb2b8
 2021-10-12 12:29:14.881069+0800 指針偏移[70684:2791244] 引用類型的指針person2:<NSperson: 0x105013d90> -- 變量地址:0x1040bb2b0

分析:

  • 指針是在棧中,對(duì)象是在堆中
  • 一個(gè)指針占8個(gè)字節(jié),所以指針按地址空間來說&p1和&p2二者之間相差8個(gè)字節(jié)
  • 而指針本身是緊挨著的,也就是說&p1的下一個(gè)指針就是&p2

圖示:

引用類型的指針偏移.png

4、數(shù)組類型

代碼:

void arrayTest(){
    int a = 10;
    int aa = 12;
    int c[4] = {1,2,3,4};
    int b = 20;
    int *d = c;
    NSLog(@"數(shù)組所在地址:%p -- 數(shù)組首元素地址:%p -- 數(shù)組第二元素地址:%p",&c,&c[0],&c[1]);
    NSLog(@"數(shù)組所在地址:%p -- 數(shù)組第二元素地址:%p -- 數(shù)組第三元素地址:%p",d,d+1,d+2);
    NSLog(@"數(shù)組第一個(gè)元素:%d -- 數(shù)組第二元素地址:%d -- 數(shù)組第三元素地址:%d",*d,*(d+1),*(d+2));
    NSLog(@"基本數(shù)據(jù)類型a:%p -- 基本數(shù)據(jù)類型b:%p -- aa:%p",&a,&b,&aa);
}

運(yùn)行結(jié)果:

結(jié)果:
 2021-10-12 12:29:14.881097+0800 指針偏移[70684:2791244] 數(shù)組所在地址:0x1040bb2a0 -- 數(shù)組首元素地址:0x1040bb2a0 -- 數(shù)組第二元素地址:0x1040bb2a4
 2021-10-12 12:29:14.881122+0800 指針偏移[70684:2791244] 數(shù)組所在地址:0x1040bb2a0 -- 數(shù)組第二元素地址:0x1040bb2a4 -- 數(shù)組第三元素地址:0x1040bb2a8
 2021-10-12 12:29:14.900159+0800 指針偏移[70684:2791244] 數(shù)組第一個(gè)元素:1 -- 數(shù)組第二元素地址:2 -- 數(shù)組第三元素地址:3

分析:

  • 數(shù)組名不是指針
  • &c是獲取數(shù)組的空間地址,&c[0]是獲取數(shù)組的第一個(gè)數(shù)據(jù)的空間地址,他們兩個(gè)是一個(gè)地址
  • 因?yàn)閿?shù)據(jù)是int型,每個(gè)數(shù)據(jù)占用4個(gè)字節(jié),所以數(shù)據(jù)的地址都相隔四個(gè)字節(jié),而指針本身是緊挨著的
  • d獲取的是數(shù)組的指針,d+1是&c[1]地址空間的指針,指針的+1就會(huì)走到下個(gè)指針,我們可以通過指針的偏移來獲取數(shù)據(jù),下一個(gè)指針就是下一個(gè)數(shù)據(jù)的地址空間。
  • 數(shù)組的數(shù)據(jù)從前到后順序存儲(chǔ),而不是從后到前

圖示:

數(shù)組的指針偏移.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容