傳遞二級指針,修改指針指向)
#includestdio.hvoidtry_change_ptr(int*p){// 發(fā)現(xiàn)p指向的地址和ptr指向的地址一樣但是p本身的地址和ptr本身的地址不一樣printf(Inside function, p %p, p %p\n,(void*)p,p);// 所以可以修改p指向的內(nèi)容*p1;// 但修改不了ptr的指向地址因為p是一個拷貝p本身的地址和ptr本身的地址不一樣pNULL;// 修改的是函數(shù)內(nèi)部的 p副本printf(Inside function, p %p, p %p\n,(void*)p,p);}intmain(){inta10;int*ptra;printf(a %p\n,a);printf(%d\n,*ptr);// 打印ptr的指向地址和ptr本身的地址printf(Before call, ptr %p, ptr %p \n,(void*)ptr,ptr);//這里會創(chuàng)建副本就像int fun(int a) 傳入a一樣如果要修改a的地址就要傳a的地址try_change_ptr(ptr);printf(After call, ptr %p, ptr %p \n,(void*)ptr,ptr);// 仍然是 a沒變printf(%d\n,a);return0;}/* a 0000002274F4FB60 10 Before call, ptr 0000002274F4FB60, ptr 0000002274F4FB68 Inside function, p 0000002274F4FB60, p 0000002274F4FB40 Inside function, p 0000000000000000, p 0000002274F4FB40 After call, ptr 0000002274F4FB60, ptr 0000002274F4FB68 1 *//*如果你不僅想修改內(nèi)容還想在函數(shù)內(nèi)部改變原指針的指向你需要使用二級指針指針的指針。 這就像你不僅拿到了鑰匙還拿到了“存放鑰匙的保險箱的鑰匙”。*///void changePointer(int **p) {// **p 200; // 依然可以修改內(nèi)容// *p NULL; // 成功修改了外部指針的指向//}//int main() {// int a 10;// int *ptr a;// changePointer(ptr); // 注意這里傳的是 ptr 的地址// // 此時 ptr 已經(jīng)變成了 NULL// return 0;//}/* * 輸出打印 Before call, ptr 0060FE98 Inside function, *p 10 Inside function, p 00000000 After call, ptr 0060FE98 *///void really_change_ptr(int **pp)//{// //和a的地址相同// printf(Inside function, *pp %p\n, *pp);// printf(Inside function, **pp %d\n, **pp);// *pp NULL; // 通過 pp 修改它指向的那個指針變量// printf(Inside function, pp %p\n, (void *) pp);// printf(Inside function, *pp %p\n, *pp);//}//int main()//{// int a 10;// printf(a add: %p\n, a);// int *ptr a;// printf(Before: %p\n, (void *) ptr);// //這里要修改指針的地址就要通過指針類型傳指針的地址// really_change_ptr(ptr); // 傳 ptr 的地址// printf(After: %p\n, (void *) ptr); // 現(xiàn)在變成 NULL 了//}/* a add: 0060FE9C Before: 0060FE9C Inside function, *pp 0060FE9C Inside function, **pp 10 Inside function, pp 0060FE98 Inside function, *pp 00000000 After: 00000000 */在 C/C 中*ptr是一個非常經(jīng)典且高頻使用的表達式。它的核心邏輯可以總結(jié)為一句話先取當前指針指向的值然后將指針向后移動一個單位。為了讓你徹底弄懂我們從底層原理到實際代碼進行拆解1. 底層原理運算符優(yōu)先級與結(jié)合性在這個表達式中同時出現(xiàn)了*解引用和后置自增。根據(jù) C/C 的語法規(guī)則后置的優(yōu)先級高于*。當優(yōu)先級相同時結(jié)合方向是從右向左。因此*ptr在編譯器眼中等價于*(ptr)。2. 具體執(zhí)行步驟假設(shè)ptr是一個指向數(shù)組的指針*(ptr)的執(zhí)行過程分為兩步取值先對當前的ptr進行解引用獲取它當前指向的內(nèi)存中的值。移動指針隨后ptr自身的地址發(fā)生偏移指向下一個元素步長取決于指針的類型例如int*會向后移動 4 個字節(jié)。?? 核心注意點這個表達式只改變了ptr的指向并沒有修改原來內(nèi)存位置里的數(shù)據(jù)值。3. 代碼演示我們來看一段直觀的代碼#includestdio.hintmain(){intarr[]{10,20,30};int*ptrarr;// ptr 初始指向 arr[0]// 使用 *ptrintval*ptr;printf(取出的值 val %d\n,val);// 輸出: 10printf(當前指向的值 *ptr %d\n,*ptr);// 輸出: 20return0;}結(jié)果解析val拿到了舊值10而ptr已經(jīng)悄悄向后移動現(xiàn)在指向了20。4. 易混淆對比避坑指南初學者經(jīng)常把*ptr和下面這兩個表達式搞混它們的區(qū)別非常大表達式等價形式作用對象結(jié)果*ptr*(ptr)指針本身取出舊值指針向后移動數(shù)據(jù)不變(*ptr)(*ptr)指向的數(shù)據(jù)取出舊值數(shù)據(jù)加 1指針不動*ptr*(ptr)指針本身指針先向后移動再取出新位置的值 總結(jié)與應用*ptr這種“先取值后移動”的特性非常適合用來順序遍歷數(shù)組。在底層 C 語言開發(fā)中它能讓遍歷數(shù)組的代碼變得非常簡潔優(yōu)雅不需要像arr[i]那樣單獨寫一行ptr。