多级指针与指针数组
指针的指针
指针记录着目标数据对象的首地址和类型。
那么能不能有一个指针它记录一个指针的首地址和类型呢?
我们对一个指针再次取地址,如果能取到 &指针 的地址 那么就会有指针指向一个指针
#include <stdio.h>
int main()
{
int n = 123;
int *pn = &n;
printf("pn = %u\n", pn);
printf("&pn = %u\n", &pn);//对指针 再次进行取地址
return 0;
}
我们对整型n变量取地址,获取到一个 int * 类型的指针。将指针存储到指针变量pn中。
之后,我们再对pn取地址。 这就获得了一个存放指针数据的指针
指针的指针是什么类型
int n = 123;
int *pn = &n;
类型 pnn = &pn
那么对存放指针的指针 用什么类型表示呢
int ** 就是 存放指针的指针 的类型
int **p; // 正确
int**p; // 正确
int* *p; // 正确
int * *p; // 正确
int * * p; // 正确
对于空格 没有要求
多级指针
int ** 是一个 int * 类型数据对象的指针,所以被称之为二级指针。
#include <stdio.h>
int main()
{
int n = 123;
int *pn = &n;
int **pnn = &pn;
printf("**pnn = %d\n", **pnn);
return 0;
}
取地址过程:
对n使用取地址运算符,获得n的指针pn,类型为 int * 。
对pn使用取地址运算符,获得pn的指针pnn,类型为 int ** 。
取值过程:
对pnn使用取值运算符,将 int ** 还原为 int * 。
对*pnn使用取值运算符,将 int * 还原为 int 。即,还原为n
那么 既然存在 存放指针的指针 那能不能 在对二级指针进行再次的取地址
#include <stdio.h>
int main()
{
int n = 123; // int
int *oneStar = &n; // int *
int **twoStar = &oneStar; // int **
int ***threeStar = &twoStar; // int ***
int ****fourStar = &threeStar; // int ****
int *****fiveStar = &fourStar; // int *****
printf("n = %d\n", *****fiveStar); // 五次取值,还原为int
return 0;
}
指针数组
从普通的数组 存放元素为 int 类型的数据
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {11, 22, 33, 44, 55};
int arr3[5] = {111, 222, 333, 444, 555}
那么可不可以 弄一个数组 里面放着都是指针
[指针 ,指针 ,指针…] 这就是指针数组
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {11, 22, 33, 44, 55};
int arr3[5] = {111, 222, 333, 444, 555}
//创建 一个指针数组
int * arr[3]; //类型 就是 int * [3] 和int [3] 区别在于一个用于放指针 一个放整数
arr[0]=arr1;
arr[1]=arr2;
arr[2]=arr3;
//arr[ arr1,arr2,arr3] //数组名存放的是指向首元素的指针
//arr[ arr1首指针,arr2首指针,arr3首指针]
Arr的类型为 int *[3] ,是一个数组。
它有3个元素,每个元素的类型为 int * 。
由于元素类型为指针,所有它也被称为指针数组
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {11, 22, 33, 44, 55};
int arr3[5] = {111, 222, 333, 444, 555}
//创建 一个指针数组
int * arr[3]; //类型 就是 int * [3] 和int [3] 区别在于一个用于放指针 一个放整数
arr[0]=arr1;
arr[1]=arr2;
arr[2]=arr3;
//arr[ arr1,arr2,arr3] //数组名存放的是指向首元素的指针
//arr[ arr1首指针,arr2首指针,arr3首指针]
for(int i = 0 ; i < 3; i ++)
{
//arr 是一个指针 **p 就是存放指针的指针 这个指针存放arr的第一个元素
int **p = arr + i;
for(int j = 0; j < 5; j++)
{
//(*p + j) *p 把**int 转为*int 获得arr[0]的指针
//arr1+1 就是arr1的第二个元素
//*(*p + j) (*p + j)是地址(某一个数组的下标) *(*p + j) 对地址取值*(*p + j)
printf("%d ", *(*p + j));
}
printf("\n");
}
p ,指向 pToArr 的第一个元素,类型为 int ** 。
*p ,指向 arr1 的第一个元素,类型为 int * 。
*p + j ,指向 arr1 中的第j个元素,类型为 int * 。
*(*p + j) ,为 arr1 中的第j个元素。
函数的返回值
#include <stdio.h>
int* func()
{
int n = 100;
return &n;
}
int main()
{
int* p = func();
printf("%d\n", *p);
return 0;
}
这个程序看似正确,并且可以通过编译。但是,却存在潜在问题。
这是因为函数结束后,函数内部的变量也会被回收。所以,变量 n 已经失效了。再去访问它有可能正
常,也有可能得到一些无意义的值或者引发错误。
这样设计的原因是因为函数与函数之间的变量是独立的,即使是同一个函数多次运行,这些变量也是独
立的。在函数返回后,函数内的变量没有继续存在的意义了。所以,函数内的变量将被回收,回收后的
内存空间将给接下来运行的函数使用。
如果你不想让变量被回收,那么可以在变量前加上关键词 static
int* func()
{
static int n = 100; // 关键词static让变量n不被回收
n++; // 变量n自增
return &n;
}
#include <stdio.h>
int main()
{
int* p = func();
printf("%d\n", *p);
func();
printf("%d\n", *p);
func();
printf("%d\n", *p);
func();
printf("%d\n", *p);
func();
printf("%d\n", *p);
return 0;
}