需求:通过封装的函数使指针 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; }