为什么要使用二级指针?

需求:通过封装的函数使指针 q的指向改变(以前指向a,现在要指向b)

           说的明白点:主函数中有个指针 int *q=&a; 把指针q作为参数传入自己写的函数

  •  int a=10,b=100;
  •  int *q=&a;
  • void func(怎么写q)
  • {
  • 怎么写
  • }

通过函数实现q=&b

错误案例1:

#include<iostream>

using namespace std;

int a= 10;
int b = 100;
int *q;

void func(int *p)
{
	p = &b;	
}

int main()
{	
	q = &a;	
	func(q);
	system("pause");
	return 0;
}

 分析:虽然我们是用指针传值,但是并不能改变参数的本质:p只是q的副本,副本p怎么变也变不了q的值。

 错误案例2:

#include<iostream>

using namespace std;

int a= 10;
int b = 100;
int *q;

void func(int *p)
{
	*p = b;	//把p=&b  改
}

int main()
{	
	q = &a;	
	func(q);
	cout<<a<<endl;
	system("pause");
	return 0;
}

 分析:*p=*q=*(&a)=a  也就是p的值对应地址的值改为100.所以外部a=100,但q的值不会变。

因为*p只是修改a地址的内容。

虽然p是q的副本(假如q=FF01,则p也=FF01),但是我们通过解引用直接修改了a的内存,使外部的a变了。

上例虽然错误,但我们得出

结论:通过解引用我们直接修改内存数据,则不论函数内部、外部、是不是副本,只要变量名、指针、引用与这块内存地址有关,全都改变。

 

 

从上图我们得到:对一级指针的解引用赋值就是对它下级的数据的修改,同理,二级的解引用就是对一级的数据的直接修改。

我们再看题目   一级指针q=&a  要变为q=&b  也就是要把q的数据(FF01,中间那个)换为&b

怎么换?就是通过它的上级指针(q1)的解引用赋值 即*q1=&b,      q1是一个二级指针。

 所以我们知道函数内部

void func(/*因为q1是二级指针,所以参数也就要二级指针接收*/int**q1)
{
	*q1 =&b;
}
正确代码1:
#include<iostream>
using namespace std;

int a= 10;
int b = 100;
int *q;

void func(int **p)  //2
{
	cout<<"func:&p="<<&p<<",p="<<p<<endl;
	*p = &b;  //3
	cout<<"func:&p="<<&p<<",p="<<p<<endl;
}

int main()
{
	cout<<"&a="<<&a<<",&b="<<&b<<",&q="<<&q<<endl;
	q = &a;
	cout<<"*q="<<*q<<",q="<<q<<",&q="<<&q<<endl;
	//下面2行可以换为一行  func(&q);
	//**************************
	int **q1=&q;
	func(q1); 
	//*******************
	//func(&q);  
	cout<<"*q="<<*q<<",q="<<q<<",&q="<<&q<<endl;

	system("pause");
	return 0;
}

其实在c++中还有一种方法就是用

指针的引用

 

#include<iostream>
using namespace std;

int a= 10;
int b = 100;
int *q;

void func(int *&p) //p就是q的别名 q是一级指针  所以参数要是int* 
{
	p = &b;  //改变p就是改变q
}

int main()
{
	q = &a;
	func(q);  
	system("pause");
	return 0;
}

 二、二级指针实际中的应用 

 需求:封装一个函数 从堆区 给str申请一个空间 并赋值为"hello world"
    也就是在封装的函数中在堆区申请空间,用函数外的指针维护申请的空间
#include<iostream>
using namespace std;

void my_str2(char**my_str)
{
    *my_str = new char[15];
    strcpy(*my_str, "hello world");
}

int main()
{
	char *str = NULL;
	my_str2(&str);
	cout<<"str = "<<str<<endl;
	delete[] str;
	str=NULL;
 
	system("pause");
	return 0;
}

  当然也可以用指针的引用

#include<iostream>
using namespace std;

void my_str2(char*&my_str)
{
    my_str = new char[15];
    strcpy(my_str, "hello world");
}

int main()
{
	char *str = NULL;
	my_str2(str);
	cout<<"str = "<<str<<endl;
	delete[] str;
	str=NULL;
 
	system("pause");
	return 0;
}

  

1、传参规则

  • 当二级指针作为函数形参时,能作为函数实参的是二级指针,指针数组,一级指针的地址
  • 当数组指针作为函数形参时,能作为函数实参的是二维数组,数组指针
  • 当二维数组作为函数形参时,能作为函数实参的是二维数组,数组指针
  • 当指针数组作为函数形参时,能作为函数实参的是指针数组,二级指针,一级指针的地址

2、实例验证:

#include <stdio.h>
#include <stdlib.h>

void fun1(int **pp)
{
    printf("fun1\n");
}
void fun2(int(*a_p)[5])
{
    printf("fun2\n");
}
void fun3(int t_d_a[][5])
{
    printf("fun3\n");
}
void fun4(int *p_a[5])
{
    printf("fun4\n");
}

int main()
{
    int *p_a[5];          //指针数组
    int **pp = NULL;      //二级指针
    int *p = NULL;        //一级指针
    int t_d_a[5][5];      //二维数组
    int a[5];             //一维数组
    int(*a_p)[5] = &a;    //数组指针

    fun1(p_a);
    fun1(pp);
    fun1(&p);
    //fun1(t_d_a);
    //fun1(a_p);
    printf("\n");

    //fun2(p_a);
    //fun2(pp);
    //fun2(&p);
    fun2(t_d_a);
    fun2(a_p);
    printf("\n");

    //fun3(p_a);
    //fun3(pp);
    //fun3(&p);
    fun3(t_d_a);
    fun3(a_p);
    printf("\n");

    fun4(p_a);
    fun4(pp);
    fun4(&p);
    //fun4(t_d_a);
    //fun4(a_p);
    printf("\n");

    return 0;
}

  

posted on 2020-12-01 14:51  大湾  阅读(872)  评论(0编辑  收藏  举报

导航