目錄
C語言允許有多級指針存在,在實際的程序中一級指針最常用,其次是二級指針。
二級指針就是指向一個一級指針變量地址的指針。
三級指針基本用不着。
二級指針
二級指針就是指向指針的指針,指向地址的地址,有點套娃...直接看下面的案例更好理解吧。
* p 、* * p、p[0]、p[0][0]
#include<stdio.h>
int main(void)
{
int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int c[] = { 7,8,9 };
//指針數組是一個特殊的二維數組模型
//指針數組對應於二級指針
int* arr[] = { a,b,c }; //這里不用取地址符號&,因為數組名就是數組的首地址
//指針數組和二級指針建立關系
int** p = arr;
printf("%p\n", a); //輸出:0xFF0000
printf("%p\n", b); //輸出:0xFF0032
printf("%p\n", c); //輸出:0xFF0064
printf("%p\n", arr); //輸出:0xFF0086
printf("%p\n", *p); //輸出:0xFF0000
printf("%d\n", **p); //輸出:1
printf("%p\n", p[0]); //輸出:0xFF0000
printf("%d\n", p[0][0]); //輸出:1
return 0;
}

**(p+1)、 * (*p+1)
#include<stdio.h>
int main(void)
{
int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int c[] = { 7,8,9 };
//指針數組是一個特殊的二維數組模型
//指針數組對應於二級指針
int* arr[] = { a,b,c }; //這里不用取地址符號&,因為數組名就是數組的首地址
//指針數組和二級指針建立關系
int** p = arr;
printf("%d\n",**(p+1)); //輸出4
return 0;
}

#include<stdio.h>
int main(void)
{
int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int c[] = { 7,8,9 };
//指針數組是一個特殊的二維數組模型
//指針數組對應於二級指針
int* arr[] = { a,b,c }; //這里不用取地址符號&,因為數組名就是數組的首地址
//指針數組和二級指針建立關系
int** p = arr;
printf("%d\n",*(*p+1)); //輸出:2
return 0;
}

* (*(p+1))+1)
#include<stdio.h>
int main(void)
{
int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int c[] = { 7,8,9 };
//指針數組是一個特殊的二維數組模型
//指針數組對應於二級指針
int* arr[] = { a,b,c }; //這里不用取地址符號&,因為數組名就是數組的首地址
//指針數組和二級指針建立關系
int** p = arr;
printf("%d\n",*(*(p+1))+1); //輸出:5
return 0;
}

p[i][j]、* (p[i]+j))、* (*(p+i)+j))
#include<stdio.h>
int main(void)
{
int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int c[] = { 7,8,9 };
//指針數組是一個特殊的二維數組模型
//指針數組對應於二級指針
int* arr[] = { a,b,c }; //這里不用取地址符號&,因為數組名就是數組的首地址
//指針數組和二級指針建立關系
int** p = arr;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
//printf("%d ",p[i][j]);
//printf("%d ",*(p[i]+j));
printf("%d ",*(*(p+i)+j));
}
puts(""); //相當於輸出一個換行\n
}
return 0;
}
輸出:
1 2 3
4 5 6
7 8 9
上面三個輸出的結果一樣!

變量的二級指針
#include<stdio.h>
int main(void)
{
int a = 10;
int b = 20;
int* p = &a;
int** pp = &p;
printf("%p\n",&a); //輸出:0095FA7C
printf("%p\n",&b); //輸出:0095FA70
printf("%p\n",p); //輸出:0095FA7C 這里存的是a的地址
printf("%d\n",*p); //輸出:10 這里取的是a的值
printf("%p\n",&p); //輸出:0095FA64
printf("%p\n",pp); //輸出:0095FA64 這里是二級指針pp存儲的地址(值)
printf("%p\n",&pp); //輸出:0095FA58 這里是二級指針pp自己的地址
*pp = &b; //等價於 p = &b; 把 指針的指針 pp 指向 b 的地址
printf("%d\n", *p); //輸出:20 因為前一步指向b的地址了,所以取出的也是b的值20
//*pp = 100; 野指針,合理修改的是地址,而不是值
**pp = 100;
// *pp 取的是 一級指針 的值(地址)0095FA70 ,這是變量b的地址,因為之前 *pp = &b; 操作了,
//**pp 相當於 *(0095FA70) 取得是變量b的值20;截止把數值100賦值給那個地址,也就是值覆蓋,變成了100
printf("%d\n", *p); //輸出:100
printf("%d\n", a); //輸出:10
printf("%d\n", b); //輸出:100
//printf("%p\n",a);
return 0;
}

參考:
[1]C基礎講義2018修訂版(黑馬程序員)
