论文部分内容阅读
[摘 要]函数是C程序基本构造模块,是构造结构化程序的基础。对C函数的调用做全面的分析和研究,总结主调函数调用被调函数时的数据传递有值传递方式、地址传递方式以及值传递和地址传递并存方式,并对每一种调用方式的调用过程从内存分配给予说明和解释。
[关键词]函数形参 函数实参 值传递 地址传递 单向 双向
中图分类号:TP311.11 文献标识码:A 文章编号:1671-7597(2008)1010068-01
一、引言
C语言程序是由函数组成的,函数是程序的基本单位。设计C程序时,通常将一个大的程序按功能分成若干个较小的模块,每个模块编写成结构清晰、接口简单、容易理解的程序函数。并且这种方法就叫模块化程序设计方法,而在划分模块时要求模块的“内聚性”强,与其他模块的“耦合性”弱,所以一般要求把C程序中的函数做成一个封闭体,函数之间的联系渠道主要由函数的参数承担。因此在C程序设计中函数的参数是不容忽视的角色。
二、函数的参数
在C程序中,函数之间存在调用与被调用的关系,当被调函数是有参函数时,主调函数和被调函数间通过参数有数据传递关系。函数的参数有形参和实参之分,定义函数时的参数称为形式参数,简称形参。形参在该函数未被调用时没有确定的值,只是形式上的参数,常用变量表示;调用函数时的参数称为实参,实参可以是变量、常量或表达式,有确定的值,是实实在在的参数。函数定义时的形参不占内存,只有发生调用时,形参才被分配内存单元,接受实参传来的值。
函数的形参与实参个数要求相等,对应类型一致,且顺序相同。形参和实参可以同名,形参是局部于该函数的变量,即使形参和实参同名,也是两个不同的变量,占不同的内存单元,因此形参也需要类型说明,函数可不带参数,也可以带多个参数,当有多个参数时,每个参数之间用逗号分隔。例如:
float max(float a,float b)
{……}
main()
{float x,y;
……
max(x,y);}
以上a、b是形参,x、y是实参。在程序执行时,形参与实参之间存在着数据传递的关系。
为了论述函数的参数传递方式,先看一个简单的程序。调用交换两数的函数 swap( ),观察程序的运行结果。
#include
void swap(int a,int b)
{int t;
t=a;a=b;b=t;
printf(“调用中:a=%d ,b=%d\n”,a,b);}
main( )
{int a=1,b=2;
printf(“调用前:a=%d,b=%d\n”,a,b);
swap(a,b );
printf(“调用后:a=%d,b=%d\n”,a,b);}
程序运行的结果是:调用前:a=1,b=2
调用中:a=2,b=1
调用后:a=1,b=2
运行结果表明,尽管形参a、b在 swap( )函数中交换了,但主函数main( )在调用swap( )的前后,实参a、b的值都没有改变。那么,为什么形参a、b的交换,并不影响实参a、b的值,实参与形参之间的数据到底是如何传递的呢?这是由参数的单向值传递方式决定的。
三、参数的“值传递”方式
在c中,参数的值传递具有如下特点:(1)实参与形参各自占据独立的存储单元。(2)调用时,将实参的值传入形参单元。(3)在被调用的函数内,访问相应的形参单元。ⅳ)函数调用结束后,释放形参单元。
因此,在被调用函数中改变形参的值不会改变实参的值。函数调用时,是把实参的值拷贝到相应的形参中去,这样,被调用函数得到的是实参的拷贝,而不是实参本身。例如上例中调用函数swap( )时,函数参数传递过程可用图1形象地表示出来。
方框表示一个特定的存储单元,箭头表示将一个存储单元的值复制到另一个存储单元中。
由于一个数组元素相当于一个同类型的变量,即在c语言中,简单变量或数组元素作为函数参数都是按“值传递”方式处理的,数据传递是单向的,即只能把实参的值传递给形参,而不能将形参的值传递给实参,形参值的改变
不影响实参。
四、参数的“地址传递”方式
从上例中可以看出,由于以简单变量作为函数的形参和实参时是“值传递”,且是“单向”的,也就是说,对被调用函数来说,参数值只能“传入”不能“传出”。其实这只是表面现象,实际上实因为形实参分别对应于不同的存储单元。
如果将程序修改为用指针变量作为函数的形参,以变量的地址作为实参来调用swap( )函数,情况就不一样了。程序修改如下:
#include
void swap(int *x,int *y)
{int t;
t=*x;*x=*y;*y=t;}
main( )
{int a=1,b=2;
printf(“调用前:a=%d,b=%d\n”,a,b);
swap( &a,&b);
printf(“调用后:a=%d,b=%d\n”,a,b);}
程序运行的结果是:调用前:a=1,b=2
调用后:a=2,b=1
从输出结果看出,实现了a,b的交换。原因是指针作为函数参数,形参 x,y不再是简单变量而是指针变量,实参是变量a,b的地址,即传递的是变量a,b的地址&a,&b,而不再是a,b的值。换句话说,采用的不是“值传递”方式,而是“地址传递”参数传递如图2所示。
图2(c)中的存储单元中有两个值,斜线前是交换前的值,斜线后是交换后的值,从图中可以清楚地看出,本程序中的swap( )函数通过指针间接访问了实参a、b,即swap( )函数中实际交换的是实参a、b的值。
C 语言中还可以使用数组名作为函数参数,在函数间传递数据。我们知道数组在内存中占有一段连续空间,这块空间有一个首地址,数组名不但代表数组元素的共同名字,而且代表数组的首地址,即数组中第一个元素的地址。所以,数组名作为参数传递时,传给形参的是实参数组的首地址,从而使形参数组与实参数组共用同一段内存空间,形参数组元素的值发生变化使,即实参数组元素的值发生变化。比如甲、乙二人住同一宿舍,如果甲的
宿舍重新装修,那么乙的宿舍也被重新装修。从而认为“地址传递”的方式是“双向”的。
五、“值传递”和“地址传递”方式并存
一般情况下,函数调用时参数的“值传递”和“地址传递”方式并存,如以下程序:
main()
{int a[10],i;
for(i=0;i<10;i++)scanf(“%d”,&a[i]);
sort(a,10);
for(i=0;i<10;i++)printf(“%d ”,a[i]);}
Sort(int x[],int n)
{int i,j,k,t;
for(i=0;i {k=i;
for(j=i+1;jx[k])k=j;
if(k!=i){t=x[i];x[i]=x[k];x[k]=t;}}}
此时数组a 与数组x之间是“地址传递”方式,10与n之间是“值传递”方式。
六、结束语
通过以上分析,可以看出当参数是一般普通变量或数组元素时,函数间采用的是“值传递”方式,传递的是内存单元里的内容。当参数是指针变量或数组名时,函数间采用的是“地址传递”方式,传递的是内存单元的地址,实质上就是共享了内存。
参考文献:
[1][美]Herbert Schildt.最新C语言精华[M].3版.王子恢译.北京:电子工业出版社,1997.
[2]谭浩强.C程序设计[M].2 版.北京:清华大学出版社,1999.
[3]田淑清.C语言程序设计[M].北京:高等教育出版社,2005.
作者简介:
贺爱香,女,安徽省宿松县人,助教,学士,研究方向为计算机应用。
注:“本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。”
[关键词]函数形参 函数实参 值传递 地址传递 单向 双向
中图分类号:TP311.11 文献标识码:A 文章编号:1671-7597(2008)1010068-01
一、引言
C语言程序是由函数组成的,函数是程序的基本单位。设计C程序时,通常将一个大的程序按功能分成若干个较小的模块,每个模块编写成结构清晰、接口简单、容易理解的程序函数。并且这种方法就叫模块化程序设计方法,而在划分模块时要求模块的“内聚性”强,与其他模块的“耦合性”弱,所以一般要求把C程序中的函数做成一个封闭体,函数之间的联系渠道主要由函数的参数承担。因此在C程序设计中函数的参数是不容忽视的角色。
二、函数的参数
在C程序中,函数之间存在调用与被调用的关系,当被调函数是有参函数时,主调函数和被调函数间通过参数有数据传递关系。函数的参数有形参和实参之分,定义函数时的参数称为形式参数,简称形参。形参在该函数未被调用时没有确定的值,只是形式上的参数,常用变量表示;调用函数时的参数称为实参,实参可以是变量、常量或表达式,有确定的值,是实实在在的参数。函数定义时的形参不占内存,只有发生调用时,形参才被分配内存单元,接受实参传来的值。
函数的形参与实参个数要求相等,对应类型一致,且顺序相同。形参和实参可以同名,形参是局部于该函数的变量,即使形参和实参同名,也是两个不同的变量,占不同的内存单元,因此形参也需要类型说明,函数可不带参数,也可以带多个参数,当有多个参数时,每个参数之间用逗号分隔。例如:
float max(float a,float b)
{……}
main()
{float x,y;
……
max(x,y);}
以上a、b是形参,x、y是实参。在程序执行时,形参与实参之间存在着数据传递的关系。
为了论述函数的参数传递方式,先看一个简单的程序。调用交换两数的函数 swap( ),观察程序的运行结果。
#include
void swap(int a,int b)
{int t;
t=a;a=b;b=t;
printf(“调用中:a=%d ,b=%d\n”,a,b);}
main( )
{int a=1,b=2;
printf(“调用前:a=%d,b=%d\n”,a,b);
swap(a,b );
printf(“调用后:a=%d,b=%d\n”,a,b);}
程序运行的结果是:调用前:a=1,b=2
调用中:a=2,b=1
调用后:a=1,b=2
运行结果表明,尽管形参a、b在 swap( )函数中交换了,但主函数main( )在调用swap( )的前后,实参a、b的值都没有改变。那么,为什么形参a、b的交换,并不影响实参a、b的值,实参与形参之间的数据到底是如何传递的呢?这是由参数的单向值传递方式决定的。
三、参数的“值传递”方式
在c中,参数的值传递具有如下特点:(1)实参与形参各自占据独立的存储单元。(2)调用时,将实参的值传入形参单元。(3)在被调用的函数内,访问相应的形参单元。ⅳ)函数调用结束后,释放形参单元。
因此,在被调用函数中改变形参的值不会改变实参的值。函数调用时,是把实参的值拷贝到相应的形参中去,这样,被调用函数得到的是实参的拷贝,而不是实参本身。例如上例中调用函数swap( )时,函数参数传递过程可用图1形象地表示出来。
方框表示一个特定的存储单元,箭头表示将一个存储单元的值复制到另一个存储单元中。
由于一个数组元素相当于一个同类型的变量,即在c语言中,简单变量或数组元素作为函数参数都是按“值传递”方式处理的,数据传递是单向的,即只能把实参的值传递给形参,而不能将形参的值传递给实参,形参值的改变
不影响实参。
四、参数的“地址传递”方式
从上例中可以看出,由于以简单变量作为函数的形参和实参时是“值传递”,且是“单向”的,也就是说,对被调用函数来说,参数值只能“传入”不能“传出”。其实这只是表面现象,实际上实因为形实参分别对应于不同的存储单元。
如果将程序修改为用指针变量作为函数的形参,以变量的地址作为实参来调用swap( )函数,情况就不一样了。程序修改如下:
#include
void swap(int *x,int *y)
{int t;
t=*x;*x=*y;*y=t;}
main( )
{int a=1,b=2;
printf(“调用前:a=%d,b=%d\n”,a,b);
swap( &a,&b);
printf(“调用后:a=%d,b=%d\n”,a,b);}
程序运行的结果是:调用前:a=1,b=2
调用后:a=2,b=1
从输出结果看出,实现了a,b的交换。原因是指针作为函数参数,形参 x,y不再是简单变量而是指针变量,实参是变量a,b的地址,即传递的是变量a,b的地址&a,&b,而不再是a,b的值。换句话说,采用的不是“值传递”方式,而是“地址传递”参数传递如图2所示。
图2(c)中的存储单元中有两个值,斜线前是交换前的值,斜线后是交换后的值,从图中可以清楚地看出,本程序中的swap( )函数通过指针间接访问了实参a、b,即swap( )函数中实际交换的是实参a、b的值。
C 语言中还可以使用数组名作为函数参数,在函数间传递数据。我们知道数组在内存中占有一段连续空间,这块空间有一个首地址,数组名不但代表数组元素的共同名字,而且代表数组的首地址,即数组中第一个元素的地址。所以,数组名作为参数传递时,传给形参的是实参数组的首地址,从而使形参数组与实参数组共用同一段内存空间,形参数组元素的值发生变化使,即实参数组元素的值发生变化。比如甲、乙二人住同一宿舍,如果甲的
宿舍重新装修,那么乙的宿舍也被重新装修。从而认为“地址传递”的方式是“双向”的。
五、“值传递”和“地址传递”方式并存
一般情况下,函数调用时参数的“值传递”和“地址传递”方式并存,如以下程序:
main()
{int a[10],i;
for(i=0;i<10;i++)scanf(“%d”,&a[i]);
sort(a,10);
for(i=0;i<10;i++)printf(“%d ”,a[i]);}
Sort(int x[],int n)
{int i,j,k,t;
for(i=0;i
for(j=i+1;j
if(k!=i){t=x[i];x[i]=x[k];x[k]=t;}}}
此时数组a 与数组x之间是“地址传递”方式,10与n之间是“值传递”方式。
六、结束语
通过以上分析,可以看出当参数是一般普通变量或数组元素时,函数间采用的是“值传递”方式,传递的是内存单元里的内容。当参数是指针变量或数组名时,函数间采用的是“地址传递”方式,传递的是内存单元的地址,实质上就是共享了内存。
参考文献:
[1][美]Herbert Schildt.最新C语言精华[M].3版.王子恢译.北京:电子工业出版社,1997.
[2]谭浩强.C程序设计[M].2 版.北京:清华大学出版社,1999.
[3]田淑清.C语言程序设计[M].北京:高等教育出版社,2005.
作者简介:
贺爱香,女,安徽省宿松县人,助教,学士,研究方向为计算机应用。
注:“本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。”