C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > 函数传参问题(指针传参,值传参,引用传参)

关于函数传参问题(指针传参,值传参,引用传参)

作者:不是杠杠

这篇文章主要介绍了关于函数传参问题(指针传参,值传参,引用传参),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

形参和实参

什么是形参(parameter),什么是实参(argument)

在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据,所以称为形式参数,简称形参

给形参传递值的变量称为实际参数,简称实参

形参和实参关系

1) 形参变量只有在函数被调用时才会分配内存,调用结束后,立刻释放内存,所以形参变量只有在函数内部有效,不能在函数外部使用。 

2) 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的数据,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参,所以应该提前用赋值、输入等办法使实参获得确定值。 

3) 实参和形参在数量上、类型上、顺序上必须严格一致,否则会发生“类型不匹配”的错误。当然,如果能够进行自动类型转换,或者进行了强制类型转换,那么实参类型也可以不同于形参类型。

实参为值传值

代码:

#include<iostream>
using namespace std;
void swap(int a,int b)
{
    cout<<"a address1 = "<<&a<<endl;
    cout<<"b address1 = "<<&b<<endl;
    int temp = a;
    a = b;
    b = temp;
}
 
int main()
{
    int a = 10;
    int b = 20;
    cout<<"a address = "<<&a<<endl;
    cout<<"b address = "<<&b<<endl;
    cout<<"original "<<"a = "<<a<<" b="<<b<<endl;
    swap(a,b);
    cout<<"swaped "<<"a = "<<a<<" b="<<b<<endl;
    return 0;
}

执行结果:

分析结果:

实参a,b 和形参a,b的地址是不一样的,因为形参a,b是整型变量,他们在函数调用时分配内存,里面只是存放了和实参对应得整型值,所以改变形参变量a,b的值并没有改变实参a,b的值。形参a,b是临时变量,当函数运行结束时,他们的生命周期也就结束了。所以实参a,b的值并没有改变。

图解:

实参为指针传值

实参本身为普通变量

代码:

#include<iostream>
using namespace std;
void swap(int *a,int *b)
{
    cout<<"parameter a address1 = "<<&a<<endl;
    cout<<"parameter b address1 = "<<&b<<endl;
 
    cout<<"a value address1 = "<<a<<endl;
    cout<<"b value address1 = "<<b<<endl;
    int temp = *a;
    *a = *b;
    *b = temp;
}
 
int main()
{
    int a = 10;
    int b = 20;
    cout<<"a address = "<<&a<<endl;
    cout<<"b address = "<<&b<<endl;
    cout<<"original "<<"a = "<<a<<" b="<<b<<endl;
    swap(&a,&b);
    cout<<"swap "<<"a = "<<a<<" b="<<b<<endl;
    return 0;
}
 

执行结果:

分析结果:

*p 指的是 指针变量p所指向的地址所存放的内容

&p指的是指针本身的地址

p指的是指针所指向的内容的地址

实参传递的是实参a,b的地址,形参a,b为指针类型的变量,也就是对应存放的是实参a,b变量的地址,函数内交换形参a,b指针所指向地址的内容,也就是交换了实参a,b地址指向空间的内容,所以实参a,b的内容被交换。

图解:

 实参本身为指针

一级指针

代码:

#include<iostream>
using namespace std;
 
void newPoint(int *p)
{
    cout<<"parameter p address = "<<&p<<endl;
    p = new int;
    *p = 10;
}
 
 
int main()
{
    int *p = NULL;
    cout<<"argument p address = "<<&p<<endl;
    newPoint(p);
    cout<<"*p = "<<*p<<endl;
    delete p;
    return 0;
}
~           

执行结果:

分析结果:

实参指针p 没有指向任何类容为空,当实参给形参传递值时,传递的实际上是NULL,形参指针p 分配空间,仅仅只是给形参p分配了空间,当函数退出时,实参指针指向的内容还是为空,这时去访问实参p指向的内容,因为指针没有指向确切地址,就会产生段错误,同时因为函数new了空间没有释放,还会造成内存泄漏。

二级指针

代码:

#include<iostream>
using namespace std;
 
void newPoint(int **p)
{
    cout<<"parameter p address = "<<&p<<endl;
    *p = new int;
    cout<<"parameter p value = "<<p<<endl;
    cout<<"parameter *p value = "<<*p<<endl;
    **p = 10;
}
 
 
int main()
{
    int *p = NULL;
    cout<<"argument p address = "<<&p<<endl;
    newPoint(&p);
    cout<<"argument p value = "<<p<<endl;
    cout<<"*p = "<<*p<<endl;
    delete p;
    return 0;
}
~       

执行结果:

结果分析:

实参给形参传递的值是实参本身的地址 0x7ffe7feaa980,形参类型是二级指针,形参p存放的是一级指针实参p的地址,调用new之后,相当于是给实参指针p分配了空间,实参指针指向的地址为0x55d013b6d280,给**p赋值,相当于是给地址0x55d013b6d280指向的空间赋值,所以当函数返回时,实参指针指向了确定的地址0x55d013b6d280,并且地址0x55d013b6d280指向的空间值为10;

图解:

引用传值

代码:

#include<iostream>
using namespace std;
 
void swap(int& a,int& b)
{
    cout<<"parameter a address = "<< &a<<endl;
    cout<<"parameter b address = "<< &b<<endl;
    a = a+b;
    b = a-b;
    a = a-b;
 
}
 
int main()
{
    int a = 10;
    int b = 20;
 
    cout<<"argument a address = "<<&a<<endl;
    cout<<"argument b address = "<<&b<<endl;
    cout<<"original value"<<"a = "<<a<<" b ="<<b<<endl;
    swap(a,b);
    cout<<"swap value"<<"a = "<<a<<" b ="<<b<<endl;
    return 0;
}
~     

运行结果:

结果分析:

引用传值,函数形参并没有给形参分配内存,而是和实参相同的内存地址,节省了开销,建议能用引用传值的就用引用。

图解:

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文