函数调用时的形参与实参

原创 2018年04月15日 18:31:11

    大多数人在进行学习编程时,对于函数调用时函数时的传递的内容是一个头大的问题。本人在学习后有了以下的见解请大家共同学习,若有失误,请指出!

基础知识

    1.系统堆栈(即栈区域)和堆区域。
        1.1、栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有FIFO的特性,在编译的时候可以指定需要的Stack的大小。在编程中,例如C/C++中,所有的局部变量都是从栈中分配内存空间,实际上也不是什么分配,只是从栈顶向上用就行,在退出函数的时候,只是修改栈指针就可以把栈中的内容销毁,所以速度最快。但是栈区域有一个很大的确定就是由于它通常只有1到2M大小的空间,这个大小相对于内存中的4G或者8G空间是很小的。所以编写递归程序时候,使用Stack是需要考虑到递归的深度。
      1.2、堆(Heap)是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程,C/C++分别用malloc/New请求分配Heap,用free/delete销毁内存。由于从操作系统管理的内存分配所以在分配和销毁时都要占用时间,所以用堆的效率低的多!但是堆的好处是可以做的很大,C/C++对分配的Heap是不初始化的。在没有垃圾回收机制的编程语言中如果程序员在编写一些长时间需要运行的程序时员(例如:服务器程序),对于堆的使用需要万分小心。如果某程序员在编写程序时候申请了堆区域的空间但没有去释放(即free/delete)且该程序需要长时间运行,这是很可怕的。这存在一个很大的问题内存泄漏!!!这是因为内存都被这个程序了。该程序在malloc/New用过后,扔在一边没有归还操作系统还不停的申请内存空间。长此以往,系统会被其消耗殆尽。

形参与实参的传递

        1、

            先举一个错误的新手容易犯的错误(该程序意用程序实现在交换两个空间的值)

#include <stdio.h> 

void exchange(int one,int another);

void exchange(int one,int another) {
	int tmp;

	tmp = one;
	one = another;
	num2 = tmp;
}

int main() {
  	int num1;
  	int num2;

  	scanf("%d%d",&num1,&num2);

  	printf("交换前的值为:%d %d\n",num1,num2);

  	exchange(num1,mun2);

  	printf("交换后的值为:%d %d\n",num1,num2);

        return 0;
}

结果如下:

    对于大多数的编程新手来说,第一次编写类似的代码很容易写成这种情况吧。下面我解释一下,这种方法中,看似交换了num1和num2的值,但实际上。这两个值并没有交换。在主函数中。在堆栈区域申请了两个整形变量空间即num1,和num2的空间。在调用exchange函数时候会现有现场信息(简称:主现)保存在堆栈区域,栈顶指针移动向上移动一定的距离。这是为了在此运行主函数时候恢复上次的状态。然后将num2复制一份入栈,another的值对应这个空间的值,栈顶指针向上移动一个整形空间,再将num1复制一份入栈,one的值对应这个空间的值。栈顶指针在向上移动一个整形空间。然后进入到exchange中在堆栈中申请一个整形空间,栈顶指针向上移动一个整形空间。然后进行交换one和another的交换。然后在将栈顶指针恢复到主现以前。然后运行主函数中的代码。上述文字如下图。



接下来我说一种正确代码

#include <stdio.h> 

void exchange(int* one,int* another);

void exchange(int* one,int* another) {
	int tmp;

	tmp = *one;
	*one = *another;
	*another = tmp;
}

int main() {
  	int num1;
  	int num2;

  	scanf("%d%d",&num1,&num2);

  	printf("交换前的值为 :%d %d\n",num1,num2);

  	exchange(&num1,&num2);

  	printf("交换后的值为 :%d %d\n",num1,num2);

        return 0;
}

执行结果为:



上面的代码成功的交换了num1和num2的数值。在主函数中,在堆栈区域申请了两个整形变量空间即num1,和num2的空间。在调用exchange函数时候会现有现场信息(简称:主现)保存在堆栈区域,栈顶指针移动向上移动一定的距离。这是为了在此运行主函数时候恢复上次的状态。然后将num2地址的值复制一份入栈,another的值对应这个空间的值,栈顶指针向上移动一个整形空间,再将num1地址的值复制一份入栈,one的值对应这个空间的值。栈顶指针在向上移动一个整形空间。然后进入到exchange中在堆栈中申请一个整形空间,栈顶指针向上移动一个整形空间。然后将one指向空间的值赋值给tmp,然后将another所指向空间的值赋值给one所指向空间,最后将tmp的值赋值给another所指向的空间。这就完成了num1和num2的交换。然后在将栈顶指针恢复到主现以前。然后运行主函数中的代码。上述文字如下图



总结提高

        在上面的两个例子中,在第一个从错误例子中,我们能发现一个问题,不论我们怎么操作传递到子函数的形参的值,都无法修改主调函数中变量的值。但在第二个例子中,我们可以通过传递主调函数变量的地址值并进行“*”操作就可以改变主调函数中变量的值。这给了我们一个启示:在调用函数中如果不需要修改主调函数中变量的值,传递那个变量的值。如果需要改变主调函数中变量的值,这时候就需要传递的就是该变量的地址的值。但由于传递的值是需要入栈,当传递的变量非常大的时候就会存在危险即栈溢出。所以当需要传递的内容比较大的时候,这时需要传递的仍然是变量的地址,但为了防止被调函数对变量操作。这时候需要加上const!!!

#include <stdio.h> 

void exchange(const int* one,const int* another);

void exchange(const int* one,constint* another) {
	int tmp;

	tmp = *one;
	*one = *another;
	*another = tmp;
}

int main() {
  	int num1;
  	int num2;

  	scanf("%d%d",&num1,&num2);

	exchange(&num1,&num2);
  	
    return 0;
}

编译会提示错误如下:


这就对主调函数中变量的值无法操作。






指针-形参与实参-函数传参

今天看到一篇博客:http://blog.csdn.net/a475701239/article/details/11179351 里面的函数...
  • jin615567975
  • jin615567975
  • 2014-10-01 11:15:01
  • 853

函数调用中形参实参关系的深度讲解

通过函数调用实现两个数交换会 有以下几种情况: 情况一 #include int main() { int a = 2,b = 3; void swap(int x, int y...
  • ruo_bing
  • ruo_bing
  • 2018-01-27 23:01:07
  • 103

关于函数调用过程中的实参和形参问题

关于函数调用过程中的实参和形参问题 作者:张老师,华清远见嵌入式学院讲师。 C语言是一种面向过程的语言,它的程序执行过程是按逻辑顺序执行,在函数的函数体的定于位置与程序执行无关,该函数必须在程序执行过...
  • yhf19881015
  • yhf19881015
  • 2013-08-25 10:18:49
  • 2031

形参和实参之间的三种传递方式

//形参和实参之间的三种传递方式 void fun(int i) {  i++;} void fun(int &i) {  i++;} void fun(int *i) {  *i=*i+...
  • WSF861559021
  • WSF861559021
  • 2011-11-28 19:39:42
  • 2623

函数的形参与实参的关系

函数的形参与实参实际上是一个“="的赋值关系,明白了这一点对于就更容易理解一些复杂的形实参的形式,如函数定义:int splitfloat(float x, int * intpart,float ...
  • SdustLiYang
  • SdustLiYang
  • 2011-07-07 08:43:10
  • 1177

形参与实参的区别。

1、形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。 2、实参可以是常量、变量、表达式、...
  • u012312103
  • u012312103
  • 2016-03-24 22:33:37
  • 362

形参与实参之间的值传递

先说形参与实参的数值传递:        函数调用时将实参数传递给形参称为参数传递。C语言中,参数的传递方式是“单向值传递”,形参和实参变量各自有不同的存储单元,被调用函数中的形参变量值的变化不...
  • u012218650
  • u012218650
  • 2013-10-09 11:45:20
  • 3657

JAVA基础之形参与实参的区别

形参定义:全称"形式参数",用于定义方法的时候使用的参数,目的用来接收调用该方法时传递的参数。说明:只有在被调用时才会分配内存单元,在调用结束,即刻释放所分配的内存单元。因此,只在方法内才有效。实参定...
  • qq_21806621
  • qq_21806621
  • 2017-03-15 22:23:42
  • 5084

Java中的形参和实参的区别以及传值调用和传引用调用

名词解析: 1.形参:用来接收调用该方法时传递的参数。只有在被调用的时候才分配内存空间,一旦调用结束,就释放内存空间。因此仅仅在方法内有效。 2.实参:传递给被调用方法的值,预先创建并赋予确定值。 3...
  • miniminiyu
  • miniminiyu
  • 2016-07-29 09:24:54
  • 13253

C的形参和实参的关系

形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量。在一般传值调用的机制中只能把实参传送给形参...
  • diwenzhi
  • diwenzhi
  • 2015-12-03 17:49:38
  • 2409
收藏助手
不良信息举报
您举报文章:函数调用时的形参与实参
举报原因:
原因补充:

(最多只允许输入30个字)