一,案例
#include<iostream>
using namespace std;
void GetMemory(int *ptr, int size)
{
ptr = new int[size];
}
int main()
{
int *ptr = NULL;
cout<<"第一处,ptr="<<ptr<<endl;
GetMemory(ptr, 100);
cout<<"第二处,ptr="<<ptr<<endl;
delete[] ptr;
return 0;
}
简介:上述案例中,试图在自定义函数中为全局数组分配内存,但是失败了。
二,分析
在c++语言(c语言也是)当中,函数传参数时,都是为实参创建一个副本(也就是形参),然后拿着这个副本代替实参 在函数内部进行操作。
当代码运行到主函数的第一句的时候,指针变量ptr指向了NULL。
当上述代码运行到主函数的第三句时,也即:GetMemory(ptr, 100);
此时,实参是ptr。函数会生成一个ptr的副本代替ptr进入GetMemory函数中进行操作。这个副本和ptr的关联之处在于,它们的值是相同的。也就是说它们指向同一块内存。(但是它们的地址不相同)在GetMemory函数里面,上述代码给ptr的副本重新分配内存,也即:让ptr的副本指向另一块内存。执行完之后,ptr和ptr的副本指向的内存就不同了。到最后,ptr的值还是不变。
这就是值传递。
三,修改后
那么,该如何实现我们所需的目标呢?请看下面的代码(实现方法之一):
#include<iostream>
using namespace std;
void GetMemory(int **ptr, int size)
{
*ptr = new int[size];
}
int main()
{
int *ptr = NULL;
cout<<"第一处,ptr="<<ptr<<endl;
GetMemory(&ptr, 100);
cout<<"第二处,ptr="<<ptr<<endl;
delete[] ptr;
return 0;
}
这个办法就是使用二级指针作为形参。
在运行到主函数的第三句时,也即GetMemory(&ptr, 100);
这时候,程序就会生成一个&ptr的副本,这个副本的值和&ptr的值相同,都是ptr的地址。
当进入GetMemory函数后,程序将执行*ptr = new int[size];
对于这里的*ptr,我们将其记为*p,就是换个名称,不然容易搞混。
那么,p代表形参,*p代表形参的值,也就是&ptr的副本的值,也就是ptr的地址。对它操作相当于对ptr操作。
这样就改变了ptr的地址。
这就是址传递。
四,题外话
有人可能会问,数组名作实参时,传递的不就是它本身吗?并不是什么副本啊?
数组名其实就是数组的首地址。
数组名作实参时,程序会生成一个数组首元素地址的副本传给形参。
形参和实参共同指向同一段内存,在自定义函数里对形参的操作均会影响到外部的实参。
如果你觉得这篇文章对你有帮助的话,点个赞再走吧。