C++函数调用时的参数传递-3中传递方式

参数传递即实参向形参传递信息,使形参获得对应的存储空间及初值,C++中函数传递主要有3种方式:

1、按值传递。

以按值传递方式进行参数传递的过程为:首先计算出实参的值,然后给它所对应的形参变量分配存储空间,该空间大小等于该形参类型的长度,然后把实参值存入到为形参分配的存储空间里去,该值即为形参的初值,在函数被调用时使用。而这种方式被调用的函数对实参的值改变不会有任何的影响,也就是说,即使形参的值在函数中被改变,也不会对实参值产生任何影响,实参值仍为被调用之前的值。究其原因还是实参和形参各占独立的存储单元,彼此之间互不影响。

按值传递引例:
#include <iostream>
using namespace std;
void swap(int a,int b);
int main(void)
{
    int a=1,b=2;
    cout<<"a="<<a<<",b="<<b<<endl;
    swap(a,b);
    cout<<"a="<<a<<",b="<<b<<endl;
    return 0;
}
void swap(int a,int b)
{
    int c=a;
    a=b;
    b=c;

}

运行结果为:

a=1,b=2

a=1,b=2

注意,虽然形参和实参都是a b,但它们是被分配到了不同的存储空间,这涉及到作用域问题。

总结:(1)只有在函数被调用时,才为形参分配内存空间并赋予初值,当函数调用结束后,形参的内存空间被释放,同时函数返回值(如果有的话);

(2)调用函数时形参实参类型必须一致,int型对应int型,同理double型对应double型,以此类推,否则程序会出错;

(3)C++中函数参数的求值顺序也即传递顺序从右向左,例如:

#include <iostream>
using namespace std;
int sum(int x,int y);
int main(void)
{
    int a,b;
    a=1;b=2;
    cout<<sum(++a,a+b)<<endl;
    a=1;b=2;
    cout<<sum(a+b,++a)<<endl;
    return 0;
}
int sum(int x,int y)
{
    return x+y;
}

运行结果为:

5

6

2,、地址传递。

在定义函数的时候如果将形参值定义为指针变量,则调用该函数的时候实参应为地址,这种传递方式即为地址传递。与按值传递不同的是,地址传递是将实参的存储地址传递给对应形参,从而使形参指针和实参的指针都指向同一个地址,所以被调用函数中形参指针指向的地址中内容的改变同时会造成实参内容的改变。

地址传值引例:

#include <iostream>
using namespace std;
void swap(int *,int *);
int main(void)
{
    int a=1,b=2;
    cout<<"a="<<a<<",b="<<b<<endl;
    swap(&a,&b);
    cout<<"a="<<a<<",b="<<b<<endl;
    return 0;
}
void swap(int *,int *)
{
    int c=*a;
    *a=*b;
    *b=c;
}

运行结果:

a=1,b=2

a=2,b=1

注意:此时的实参和形参仍然占用不同的存储单元,只是它们的指针指向的是同一个地址。

3、引用传递

引用是C语言所没有而C++提供的一种新特性,引用可以看做是变量或者对象的别名,当建立引用的时候,程序用一个变量或者对象的名字初始化它,这样引用就可以当做该变量或者对象的别名所使用,因此对引用的改变就是对变量或者对象本身的改变。引用的语法格式如下所示:

变量类型& 引用名=变量名;

例如定义一个整型变量的引用:

int a;

int& refa=a;     \\refa作为a的别名

refa=10;

a-=40;

cout<<a<<endl;

输出结果为-30。此时系统没有为refa分配存储空间,它和a代表了相同的内存空间,对refa进行改变就是对a进行改变。引用的建立和使用引例:

#include <iostream>
using namespace std;
int main(void)
{
    int a=3,b=2;
    int &a=refa,&b=refb;
    refa=a+2;
    b=refa+1;
    cout<<refa<<" "<<a<<endl;
    cout<<refb<<" "<<b<<endl;
    refa=b;
    cout<<refa<<" "<<a<<endl;
    return 0;
}
运行结果为:

5 5

3 3

3 3

注意:(1)引用在定义的时候必须被初始化,必须指定是哪个变量或对象的别名,类型对应一致;

(2)引用仅仅是变量或者对象的别名,系统不会为它分配内存空间;

(3)引用一旦建立就不能被改变,即它已跟定了该变量或者对象,不能作为其它变量或对象的别名。

按值传递易理解但改变形参不能对实参产生影响,地址传递虽可以,但是在函数中多次用指针进行间接访问会使程序难以阅读,且易产生错误,而引用完美解决了上述两个问题。引用传递是在函数定义时在形参前面加上“&”。

引用传递引例:

#include <iostream>
using namespace std;
void swap(int &,int &);
int main(void)
{
    int a=1,b=2;
    cout<<"a="<<a<<",b="<<b<<endl;
    swap(a,b);
    cout<<"a="<<a<<",b="<<b<<endl;
    return 0;
}
void swap(int &,int &)
{
    int c=a;
    a=b;
    b=c;
}

以上即为C++函数调用时的三种传递方式。

C++函数调用时的参数传递

时间: 2024-10-05 23:50:15

C++函数调用时的参数传递-3中传递方式的相关文章

函数调用时的帧变化

[原文] 函数调用另一个词语表示叫作过程.一个函数调用包括将数据和控制从代码的一部分传递到另一部分.另外,它还必须在进入时为函数的局部变量分配空间,并在退出时释放这些空间.而数据传递,局部变量的分配和释放是通过操纵程序栈来实现的. 我们先来了解一个概念,栈帧.机器用栈来传递过程参数,存储返回信息等.为单个过程(函数调用)分配的那部分栈成为栈帧.栈帧其实是两个指针寄存器:寄存器%ebp为帧指针,寄存器%esp为栈指针.当程序运行时,栈指针可以移动,大多数的下线访问都是通过帧指针进行的.总之简单一句

ssh下:系统初始化实现ServletContextListener接口时,获取spring中数据层对象无效的问题

想要实现的功能:SSH环境下,数据层都交由Spring管理:在服务启动时,将数据库中的一些数据加载到ServletContext中缓存起来. 系统初始化类需要实现两个接口: ServletContextListener,系统初始化时调用contextInitialized方法缓存数据: ApplicationContextAware,获取Spring的ApplicationContext对象,以获取spring容器管理的service对象. 系统初始化类如下: 1 package com.liz

OpenCV访问Mat对象中数据时发生异常---Mat中的数据访问

7.1和7.1.1由于越狱不成熟,半完美越狱后电脑上无法访问系统越狱目录,如var usr 等等. 今天有些意外地发现,可以在电脑上使用手机的越狱目录我手机 i4 7.1.1 联通 半完美越狱,没装Afc2Add,也没装Appsync 附上  --->我的半完美越狱过程 好了,下面直接正题 一.前提,必须安装ifile! 打开ifile,并转到 /var/mobile/media 目录下,然后点击右上角的 [ 编辑 ]如图: 二.点左下角的 + 号创建,如图: 三.点 [ 类型],选择[符号链接

使用spring rest插入数据库时发生了 前言中不允许有内容 错误

该错误一般是编码带来的问题,比如在请求post的时候,使用了application/x-www-form-urlencoded的content type 那么请求传过来的string则需要用urlDecoder进行decode.否则就会报上述错误 body = java.net.URLDecoder.decode(body, "UTF-8"); Source source = new StreamSource(new StringReader(body)); 使用spring rest

spring -mvc 将对象封装json返回时删除掉对象中的属性注解方式

spring -mvc 将对象封装json返回时删除掉对象中的属性注解方式 在类名,接口头上注解使用在 @JsonIgnoreProperties(value={"comid"}) //希望动态过滤掉的属性 例 @JsonIgnoreProperties(value={"comid"}) public interface 接口名称{ } @JsonIgnoreProperties(value={"comid"}) public class 类名{

exchange 2010 EMC创建邮箱时无法同步AD中新建的账号

最近客户公司exchange 2010出现了一个奇怪的现象,在AD中创建一个新的账号,然后在exchange 2010 EMC中新建邮箱时,在向导中选择现有用户时却发现找不到这个用户,同样,在exchange 2010 EMC中直接创建邮箱,同时新建AD账号后,在AD用户和计算机中也无法找到这个账号. 客户的环境比较简单,是单林单域多站点的情况,分别为bj.sz.tw,每个站点各有两台DC和一台exchange. 经过检查,发现这种情况并没有在bj和tw出现,而且各站点的DC都复制正常,我尝试在

笔记-返回到前一个页面时显示前一个页面中ajax获取的数据

笔记第一部分:http://www.cnblogs.com/zczhangcui/p/6869219.html 在第一部分遇到的问题是,用ajax获取了一系列列表信息后,拼接好html后插入到了原有页面中,类似于一系列新闻列表,点击查看详情后再返回到这一页,会出现所有ajax获取并插入页面的结构都没有了,经过调研,决定尝试从history对象入手. 我使用了history.replaceState方法来改变当前页面的state,每次ajax获取信息后,将页面中希望保留的内容放入state中,当返

能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么

不能向编译后得到的类中增加实例变量!能向运行时创建的类中添加实例变量! 因为编译后的类已经注册在runtime中,类结构体中的objc_ivar_list 实例变量的链表和instance_size实例变量的内存大小已经确定,同时runtime 会调用class_setIvarLayout 或 class_setWeakIvarLayout来处理strong weak引用,所以不能向存在的类中添加实例变量. 运行时创建的类是可以添加实例变量,调用 class_addIvar 函数,但是得在调用 

MVC4.0中项目发布遇到IE11时session存入URL中,导致记不住密码的问题

///MVC4.0中项目发布遇到IE11时session存入URL中,导致记不住密码的问题,在webconfig中配置<system.web><authentication mode="Forms">      <forms loginUrl="~/Account/Login" timeout="2880" cookieless="UseCookies" />    </authent