C++语言中函数参数传递方式的图示说明

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C++语言中函数参数传递方式的图示说明

摘要:学习C++语言中函数参数传递方式的关键是给出函数调用过程中内存各段内容的变化图示。本文针对C++语言中三种函数参数传递方式,辅以代码段内容图示和堆栈段内容图示,从机理上详细解释了函数参数的传递过程。实践表明,这种图示说明的方法在教学中取得了非常良好的效果。

关键词:函数调用;参数传递;代码段;堆栈段

1背景

“C++程序设计”是高等学校计算机专业或非计算机专业学生的必修课。对于非计算机专业的学生,C++语言是他们真正学习和使用计算机语言进行编程的关键入门,对于以后在其专业应用开发中具有至关重要的作用。即使以后使用其他编程语言进行专业项目的开发,如VB、C和Java语言,C++语言由于其概念的广泛性和综合性,也能够使得他们很快学习并掌握这些编程语言。而对于计算机专业的学生来说,“C++程序设计”是“数据结构”、“算法设计”等核心课程的先修课,同时,“C++程序设计”中涉及的部分硬件知识也是其学习计算机原理的重要基础。

但是,C++作为入门程序语言课程,对于初学者来说确实难度较大。周立章对自己的教学实践进行总结,强调分层教学、案例教学和对计算机实验进行改革的思想[1];李新霞在C++的前驱语言C语言的教学实践中也表达了类似的思想[2]。因此,案例教学对C++语言来说是必不可少的。

对于大多数学生来说,C++程序设计学习中存在三个难点:(1)函数参数的传递;(2)指针变量的使用;(3)虚函数和多态性机制。

函数和类作为C++语言中的两种基本模块,分别支持C++语言进行面向过程的开发和面向对象的开发,而不论是何种开发方法,函数都是不可缺少的。一个完整的函数使用过程包括函数定义和函数调用,有时存在函数声明,而函数调用过程中,在主调函数和被调函数之间发生着数据的交互,表现为函数参数的传递和被调函数的返回值。

其中,对于函数参数传递方式及相关教学研究,得到了很多关注。马新将函数参数传递方式分为值传递方式和地址传递方式,并归纳总结了选用何种方式的条件[3];刘志华将函数参数传递方式分为简单变量作参数、指针作参数、引用作参数、数组作参数和字符串作参数共五种方式,并对每一种情况进行了实例描述[4];谭庆将函数参数传递方式分为传普通值调用、传地址值调用和引用调用三种方式,并对其使用方法进行了总结[5];王萍、谭浩强和陈志泊在其编写的相应教材中也对C++中函数参数传递方式给予了重点关注[6-8]。

本文就函数参数的传递方式,利用图示说明的方法进行研究,旨在搞清各种函数参数传递方式的本质,为函数的学习奠定坚实的基础。

2函数参数的传递方式

C++语言中函数参数的传递方式分为值传递、引用传递和指针传递。学生之所以不能正确掌握函数参数传递的相关内容,主要原因是不能了解函数参数传递过程中内存各段相关内容的变化,而解决这一问题的方法是给出函数调用过程中内存各段内容变化的图示。

2.1内存分段

程序在执行时,内存是分段使用的,可分为代码段(CS, Code Segment)、数据段(Data Segment)、附加段(ES, Extra Segment)和堆栈段(SS, Stack Segment),如图1所示。

代码段中存放程序执行代码,数据段由静态数据区和使用new请求分配数据的堆区组成,堆栈段中存放函数执行过程的各种数据,主要包括形式参数、局部变量和主调函数断点地址。主调函数断点地址指的是函数调用语句指令后的一条执行指令的地址。堆栈中每个函数的形式参数、局部变量和主调函数断点地址称为该函数的活动记录。

根据冯诺依曼原理,当执行程序时,必须将该程序指令代码加载到内存的代码段,同时将第一条指令代码的地址存入到PC寄存器,然后,每执行一条指令代码,PC的内容自动加1,如此顺序执行代码段中的指令。而当发生函数调用时,程序的执行发生了流程的转向。当流程转向到被调函数时,PC中的内容更新为被调函数第一条指令的地址;而当流程重新回到主调函数时,PC中的内容更新为主调函数的断点地址。函数调用过程的代码段图示说明,如图2所示。

2.2值传递

采用值传递(pass-by-value)方式时,在堆栈段中为被调函数的形参列表分配内存,主调函数的实参列表分别赋给形参列表。因此,内存中每个形式参数和实际参数都是不同的变量,只是在发生函数调用的时刻,对应实参和形参变量的值相同而已。值传递方式的特点是被调函数对形参的任何操作不会影响主调函数的实参的值。

以下面程序作图示说明。

int swap(int x, int y)

{

int temp;

temp = x; x = y; y = temp;

cout<<“x=“<

return temp;

}

void main()

{

int a = 10, b = 20;

swap(a, b);

cout<<“a=“<

}

当该程序提交给操作系统执行时,首先将程序代码加载到代码段,然后根据PC的内容来执行指令。由于PC存储的内容为main函数中第一条指令的地址,故从该地址处开始顺序执行。此时,执行的是main函数,也可以理解为操作系统调用main函数,操作系统相当于主调函数,main函数是被调函数。因此,堆栈段中为main函数分配活动记录:a和b。而当执行到swap(a,b);语句时,发生了swap函数调用。堆栈段中为swap函数分配活动记录: main函数断点地址,x、y和temp,并且将a和b的值分别赋给形参x和y。修改PC的内容为swap函数的第一条指令的地址,程序由此重新开始顺序执行。此时,对x和y的任何修改都不能影响到a 和b。当swap函数执行结束后,从堆栈中删除swap函数活动记录,并且修改PC 的内容为main断点地址,程序由此继续顺序执行。值传递过程的堆栈段图示说明,如图3所示。

(a) 函数调用前(b) 函数调用中(c) 函数调用后

图3值传递过程的堆栈段图示

上述程序的执行的结果是:

x=20,y=10

a=10,b=20

2.3指针传递

采用指针传递(pass-by-pointer)方式时,同样也需要在堆栈段中为被调函数的

相关文档
最新文档