int a = 0;
int* p = &a; //p作为指针指向了a, p 保存的是a 变量的内存地址,
// p 这个指针本质是变量,这个变量有没有内存地址?
// 有内存地址,为什么?
// 因为它作为变量,肯定要占用内存空间的
// p 这个变量的地址如何拿到?
// 使用取地址操作符作用于 p 这个变量 ------- &p 其结果就是 p 这个变量的内存地址
// 这个内存地址( &p ) 如何保存?
// 显然,要保存一个内存地址,只能定义指针?
// 那么,怎么定义指针指向另一个指针呐?
在 c 语言里面有多级指针的概念,多级指针就是指针。这种指针用来保存其他指针的地址,换句话说,也就是指向指针的指针
Type * ---- 表示一个指针类型 , 指针类型后面再加一个 * 号,是另一个指针类型,是不同的指针类型,于是,这个 ppv 就是一个指针,这个指针用来指向 这个类型的变量 ---- Type*,而Type*类型的变量是什么?是另一个指针,所以有了这样的初始化写法 ---- Type** ppv = &pv;
使用 pv ,也就是 Type* 类型的变量的地址来初始化 ppv ,这样的话 ppv 是一个二级指针。这个二级指针的本质还是变量,只有是指针本质就是变量
ppv 这个二级指针还是变量,肯定有地址,怎么获得它的地址 ------- &ppv
怎么保存 ppv 这个二级指针变量的地址?
再定义指针,
ppv 它的类型是 : Type**
它的地址类型是 : 就是 ppv 的类型再加一个 * 号
#include <stdio.h>
int main()
{
int a = 0;
int b = 1;
int* p = &a; //定义一级指针 p ,让一级指针p ,指向 a
int** pp = &p; 定义二级指针 pp,并使得它指向一级指针 p
**pp = 2; // a = 2;
*pp = &b; // p = &b;
*p = 3; // b = 3;
printf("a = %d, b = %d\n",a, b);
return 0;
}
既然是二级指针,意味着我们调用这个函数的时候,第一个参数必须是 一个一级指针的地址
就是在函数里面,申请一片堆空间,通过函数外的指针指向这片堆空间
#include <stdio.h>
#include <stdlib.h>
int getDouble(double** pp, unsigned n)
{
int ret = 0;
double* pd = malloc(sizeof(double) * n);
if(pd != NULL)
{
printf("pd = %p\n",pd);
*pp = pd;
ret = 1;
}
return ret;
}
int main()
{
double* p =NULL;
if(getDouble(&p, 5))
{
printf("p = %p\n",p);
free(p);
}
}
我们应用了二级指针,在函数内部改变了函数外部指针变量的值
b 的类型是什么?
C 语言里面没有多维数组,只有一维数组,我们所看到的多维数组,其实就是数组的数组
实验结论 : 一维数组的数组名是一个 一级指针类型
二维数组的数组名是一个 也是一个一级指针类型,绝非二级指针类型
#include <stdlib.h>
int* func()
{
int var = 100;
return &var;
}
int main()
{
int* p = func(); //OPPS!!!!
// p 指向了不合法的地址,这个地址处没有变量存在
// p 是一个野指针,保存不合法地址的指针都是野指针
printf("*p = %d\n", *p);
*p = 200; //改变 func 函数中局部变量 var 的值,是不是非常奇怪???
printf("*p = %d\n", *p);
return 0;
}
可以定义指针的指针 ,来保存另一个指针的地址
想要在函数返回之后,操作函数内部的局部变量,这显然不合法,因为函数返回之后,局部变量和函数参数都被销毁了,所以返回的地址就不合法了,于是导致我们在main 函数中操作了野指针