学了四年的计算机,一直让自己比较苦恼的问题是C语言的参数传递问题,之所以说是苦恼,是因为在某年的一个学期,不幸接触到数据结构,光一个链表就把自己弄得死去活来的,而且自已一直就楞以为在操作的过程中,传递参数的指针也在发生变化,结果可想而知,数据结构成了自己专业课里面险些挂彩的一门课程。

直至最近,拿出数据结构打算恶补一下前些年欠下的债,第一件事情,还是先解决好当时困扰自己半年之久的C语言参数传递问题吧。

C语言课堂上,自己明明记得参数传递问题我已经搞懂了,只不过当时没有接触过C plus plus,所以除了值传递和地址传递,我就根本不知道还有一种引用传递。现在想起来,自己那时候学的还是马马虎虎,太过自信认为自己已经完全掌握参数传递的实质。闲话少说,直入正题。

C语言中,函数参数传递有三种形式:值传递、地址传递和引用传递。

弄懂C语言参数传递之前,我们先要清楚以下几个概念:函数参数中的形式参数和实际参数

首先定义上面

形式参数:形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。

实际参数:实参出现在主调函数中,进入被调函数后,实参变量也不能使用。

形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。

函数的形参和实参具有以下特点:

1. 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。

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

3. 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。

4. 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。

对于函数参数值传递形式,其参数传递的过程是:

(1)行参与实参各占一个独立的存储空间。

(2)行参的存储空间是函数被调用时才分配的。调用开始,系统为行参开辟一个临时存储区,然后将各实参之值传递给行参,这时行参就得到了实参的值。

(3)函数返回时,临时存储区也被撤销。

传值的特点:单向传递,即函数中对行参变量的操作不会影响到调用函数中的实参变量。

示例:

 #include <stdio.h>

以下为值传递的被调函数

 void change_by_value( int x ){
//函数change_by_value接受的参数即为形参 x = x + ; //x的值为13,但其值的变化不会影响到a的值
}

主函数,调用被调函数并输出

 int main(){
int a = ;
printf( " a = %d\n" , a );
change_by_value( a ); // 此时的a作为实参传递给函数
printf( "a = %d\n",a ); //a的值并没有改变
return 0; }

程序的输出为:

a = 3

a = 3

void change_by_value(int x)内部发生的动作应当是当函数被调用时(堆栈调用)在堆栈上临时分配了一块区域,调用结束,出栈。其详细解释如下:

 void change_by_value( int x ){
int _x = x;  //拷贝一份传递给临时变量_x
_x = _x + ;  //改变的是_x,不是x
}

对于函数参数地址传递形式,其原理和值传递方式一样,当调用函数时也要为形式参数分配内存,被调函数执行完毕后也要回收内存。不同的是:地址传递传递的是实参变量地址的拷贝值,而不是实参变量的值。被调函数中对地址所指对象的操作会改变实参的值。例如:

 #include <stdio.h>

以下为地址传递的被调函数

 void change_by_address( int *x ){
*x = *x + ;
}

主函数,用于调用被调函数

 int main(){
int a = ;
printf( "a = %d\n", a );
change_by_address( &a ); //如果定义的不是指针变量或者数组,变量名前要加上取址符号
printf( "a = %d\n", a );
return ;
}

程序输出为:

a = 

a = 

地址传递方式:参数是地址

 void change_by_address( int *x ){
*x = *x + ;
}

实参和行参共享一个存储单元,对行参的操作相应的就改变了实参,此时参数传递是双向的。

小结:

值传递:作为参数的变量,传递给函数执行后,自己的变量值是不变的。它(实参)仅仅只是把值赋给了形参,自己实际上是没有参与函数运算的,参与的是形参,这个就是参数的值传递。值传递好比是你把文件复制一份,通过网络传给他,然后他可以在他本机上对文件做任何的修改,修改会保存下来,但是你机器上的文件不会发生任何的变化。即形参与实参是两个不同的变量,各自占用不同的存储单元。
地址传递:地址传递跟值传递也没有什么不同,值传递是把变量的值传递给形参去参与函数运算,而地址传递则把变量的地址传递给形参去参与函数运算。当然,如果函数改变了变量地址的值,实参的值也会变化的。地址传递好比是你把文件在网络上的地址告诉他人,他人通过网络访问你机器上的文件,他可以对文件进行修改并保存,此时,文件的内容就会发生变化。即形参与实参是相同的变量,占用同一段内存空间。

C语言之参数传递的更多相关文章

  1. C语言的参数传递

    一.三道考题 开讲之前,我先请你做三道题目.(嘿嘿,得先把你的头脑搞昏才行……唉呀,谁扔我鸡蛋?) 考题一,程序代码如下:void Exchg1(int x, int y){   int tmp;  ...

  2. 菜鸟学习-C语言函数参数传递详解-结构体与数组 分类: C/C++ Nginx 2015-07-14 10:24 89人阅读 评论(0) 收藏

    C语言中结构体作为函数参数,有两种方式:传值和传址. 1.传值时结构体参数会被拷贝一份,在函数体内修改结构体参数成员的值实际上是修改调用参数的一个临时拷贝的成员的值,这不会影响到调用参数.在这种情况下 ...

  3. C语言函数参数传递

    1.值传递 void swap(int x,int y) { int temp = x; x = y; y = temp; } void main() { , b = ; swap(a, b); } ...

  4. OpenGL12-shader(GLSL)着色语言2-(参数传递)(代码以上传)

    上一篇中介绍了如何使用shader,用来一个最简单的shader,计算顶点的位置,调用了 OpenGL 顶点着色语言中的内置变量对顶点进行操作,这一例程中,将展示如何将应用层 的数据传递到shader ...

  5. C语言中的参数传递

    有空看看: c语言 函数传输传递的三种方式(值.指针.引用) C语言之参数传递 C语言形参和实参,传值调用和引用调用的区别

  6. R语言参数传递 按引用传递

    R 语言的参数传递是按照引用传递的,二者共享内存 如果想要按值传递 使用函数 copy()

  7. java 参数传递是引用传递还是值传递?

    JAVA的参数传递倒底是值传递还是引用传递,我觉得两种说法都没错,关键是看怎么理解“引用”和“引用传递”. (一)从编译原理的角度讲,所有那些无法通过形参来修改实参本身的传递机制都是“值传递”,在JA ...

  8. Java的参数传递是值传递还是引用传递

    当一个对象被当作参数传递到一个方法后,在此方法内可以改变这个对象的属性,那么这里到底是值传递还是引用传递?  答:是值传递.Java 语言的参数传递只有值传递.当一个对象实例作为一个参数被传递到方法中 ...

  9. Java的参数传递是「按值传递」还是「按引用传递」?

    JAVA传递的只有值,.传递的都是栈里的的值,只是有些栈里面的是值.有的是内存地址.(原文传递的都是栈里的的值有误,局部变量在栈中,成员变量在堆中,类变量(静态变量和常量)在方法区中,可以看做本文的变 ...

随机推荐

  1. Dottrace跟踪代码执行时间

    当自己程序遇到性能问题,比如请求反应缓慢,怎么分析是哪里出了问题呢?dottrace可以帮助.net程序跟踪出代码里每个方法的执行时间,这样让我们更清晰的看出是哪里执行时间过长,然后再分析应该怎样解决 ...

  2. 一个Eclipse代码显示主题

  3. [word]2010中插入公式自动编号并且公式不自动缩小/变小

    要实现在word2010中插入公式自动编号,就要用到自动图文集功能,具体操作如下: 1.先制定制表位位置:单击一个空白段落,然后双击标尺线的底部:这会激活"制表位"对话框,如图所示 ...

  4. gcc学习

    gcc学习 预处理:gcc –E xxx.c –o xxx.i;产生预处理过的C原始程序 编 译:gcc –S xxx.i –o xxx.s;产生汇编语言原始程序 汇 编:gcc –c xxx.s – ...

  5. RedHat版的linux安装yum源及redis

    一.前言 最近正在学习redis,但是在安装redis的时候遇到很多坎,在此记录一下. 硬件环境:我用 VMware Workstation Pro 12 安装 Red Hat Enterprise ...

  6. swift语言的学习笔记

    swift参考了OC,Rust,Haskell,Ruby,Python,C#等语言的特性.首先,学习这门语言是速学的,我不想浪费太多时间在笔记这门语言和其他语言的哪里不同,特性你自己亲自实践就知道了. ...

  7. 不得不说的JavaScript异步加载

    同步加载的问题 默认的js是同步加载的,这里的“加载”可以理解成是解析.执行,而不是“下载”,在最新版本的浏览器中,浏览器对于代码请求的资源都是瀑布式的加载,而不是阻塞式的,但是js的执行总是阻塞的. ...

  8. cocos2d-x 3.0以上版本字体设置问题

    cocos2d-x中的万年大坑,字体总算是有比较好的结局办法了.之前都是CCLabelTTF,CCLabelBMFont,CCLabelAtlas什么的,我只想说一句:好难用!毕竟是做游戏,那么难看的 ...

  9. node的实践(项目一)

    学习一门语言,我们先要学习他的基本的语法,基本的数据类型,基本的数组操作,字符串的操作,然后就是语言的特性,实现共享和降低耦合的方式,然后开始比较高级的学习(所有语言都是一样的),比如说通信方法,tc ...

  10. Fluent NHibernate关系映射

    1.好处:Fluent NHibernate让你不再需要去写NHibernate的标准映射文件(.hbm.xml), 方便了我们的代码重构,提供了代码的易读性,并精简了项目代码 实现: (1).首先我 ...