相信你遇到过指针传参、值传参、引用传参,这三个关系足够让你头脑爆炸,搞不清楚三者的区别。但是恭喜你,你看到了这篇文章,小编保证你看后茅塞顿开,一下子就顺畅了。
首先,我们要先知道什么是指针,是的,指针是C/C++独有的特色,并且它的指针还不会自动释放,不像Java、python那样的自动回收机制,所以还是需要程序员自己释放它。举个例子就是:你在饭堂吃饭,向饭堂申请了一个饭盒,然后装饭装菜,吃完饭,你要自己把饭盒拿到回收站,不然你就会被别人指指点点。
很多童鞋一看到指针就浑身发抖,因为你怕他指来指去的,不知道知道哪去了。其实不用它,你越怕它,它就越 “锋利”。其实指针也是一个变量,只不过这个变量的值存放了地址。
所以知道了指针,我们来看一下函数参数的指针传递和引用传递。
函数的参数是称之为形参,然后调用函数的参数叫做实参。指针传递其实就是开了指向要改变的值的形参,我们来看指针传递的几种情况吧:
一、指针传递
1. 指针传递改变单一变量值
将指针作为函数的参数,然后再调用该函数的时候将变量进行取址符号传递给指针。
/* 值传递函数,这里形参改变,实参是没有变化的*/
void Test_1(int a){
a = 2;
}
/* 指针传递函数,这里形参改变,实参会跟着变化的*/
void Test_2(int *a){
*a = 2;
}
int main()
{
int i = 1;
Test_1(i);
Test_2(&i); // 把i的地址传递给参数a指针的指向
return 0;
}
2. 指针传递改变指针变量的值
下面的代码是为指针变量分配一个随机地址
指针也是一个变量,只不过这个变量中存的值是一个地址
void Test_1(int **p){
*a = (int *)malloc(sizeof(int *));
// 这里的*a的含义是指向指针的指针的值
}
int main(){
int *a; // 定义一个指针变量
Test_1(&a); // 取出指针变量的地址(也就是存放指针a的地址)
// 括号里面不能写*a,因为此时定义的*a还没有指向,所以直接用*a会导致内存泄露
return 0;
}
3. 改变数组的值
数组的名字就是对应了它的首地址
void Test(int *a){
a[0] = 2;
a[1] = 3;
a[2] = 4;
}
int main(){
int a[3] = {0,1,2};
Test(a); // 数组的名称就是地址了
return 0;
}
总结: 指针传递其实就是开多了一个指针形参指向要改变的值的地址(只不过是不同时候要改变对象的类型不同),进而在调用函数中改变固定地址中的值。
二、引用传递
1. 引用传递单一变量值
void Test(int &a){
a = 2;
}
int main(){
int a = 1;
Test(a); // 直接将a传过去,不用取地址操作,就是直接实参去改变,没有形参之说
return 0;
}
2. 改变指针变量
下面代码为指针随机分配了一个地址(指针变量的值就是地址)
void Test(int* &a){ // 引用传递变量名前面的类型与传入的变量一致
a = (int *)malloc(sizeof(int *))
}
int main(){
int *a; // 定义了一个int指针类型的变量
Test(a);
return 0;
}
3. 改变数组的值
void Test(int (&a)[3]){ // 数组的传递方式除了&数组名之外还要指出其长度
a[0] = 2;
a[1] = 3;
a[2] = 4;
}
int main(){
int a[3]={0,1,2};
Test(a); // 直接传递数组名
return 0;
}
4. 引用传递动态开辟空间
用完free掉空间,这里先省略这个步骤
#define len 3
void Test(int* &a)
{
a=(int*)malloc(len*sizeof(int *));//动态开len长度空间;
a[0]=1;
a[1]=2;
a[2]=3;
}
int main()
{
int* a;
Test(a);
return 0;
}
总结:引用传递其实就是相当于直接把那个实参本身传过去,改的就是那个实对应的值,省去了开形参的步骤,也能提高效率,而且还不会被指针弄晕。
欢迎大家关注小编的公众号 “三贝勒文子”呀~~,每天更新关于C++和C的知识点。