彻底搞懂值传递、地址传递、引用传递

您所在的位置:网站首页 什么叫传递函数 彻底搞懂值传递、地址传递、引用传递

彻底搞懂值传递、地址传递、引用传递

2024-07-13 14:32| 来源: 网络整理| 查看: 265

文章目录 一、值传递1、值传递的一个错误认识2、一个预备的常识3、理解值传递的形式 二、地址传递三、引用传递四、对比值传递与引用传递:1、在函数定义格式上有不同2、调用时有相同的格式3、功能上是不同的 五、参考

我们都知道:C 语言中函数参数的传递有:值传递、地址传递、引用传递这三种形式。这三种参数传递的形式,曾把我给搞得晕头转向。我相信也有很多人与我有同感吧?下面请让我逐个地谈谈这三种传递形式。

一、值传递 1、值传递的一个错误认识

先看一段关于Exchg1 函数的代码:

void Exchg1(int x, int y) /* 定义中的x,y变量被称为Exchg1 函数的形式参数 */ { int tmp; tmp = x; x = y; y = tmp; printf("x = %d, y = %d.\n", x, y); }

问:你认为这个函数是在做什么呀?

答:好像是对参数 x、y 的值对调吧?

请往下看,我想利用这个函数来完成对 a,b 两个变量值的对调,程序如下:

int main() { int a = 4,b = 6; Exchg1(a, b); /*a,b 变量为 Exchg1 函数的实际参数。*/ printf("a = %d, b = %d.\n”, a, b); return(0); }

我问:Exchg1()里头的 printf(“x = %d, y = %d.\n”, x, y);语句会输出什么啊?

我再问:Exchg1()后的 printf("a = %d, b = %d.\n”, a, b);语 句输出的是什么?

程序输出的结果是: x = 6, y = 4. a = 4, b = 6. 为什么不是 a = 6,b = 4 呢?

奇怪,明明我把 a、b 分别代入了 x、y 中,并在函数里完成了两个变量值的交换,为什么 a、b 变量值还是没有交换(仍然是 a = 4、b= 6,而不是 a = 6、b = 4)?如果你也会有这个疑问,那是因为你根本就不知实参 a、b 与形参 x、y 的关系了。

2、一个预备的常识

为了说明这个问题,我先给出一个代码:

int a = 4; int x; x = a; x = x + 3;

看好了没,现在我问你:最终 a 值是多少,x 值是多少?

(怎么搞的,给我这个小儿科的问题。还不简单,不就是 a = 4、x = 7 嘛!)

在这个代码中,你要明白一个东西:虽然 a 值赋给了 x,但是 a 变量并不是x 变量哦。我们对 x 任何的修改,都不会改变 a变量。呵呵!虽然简单,并且一看就理所当然,不过可是一个很重要的认识喔。

3、理解值传递的形式

看调用 Exch1 函数的代码:

int main() { int a = 4,b = 6; Exchg1(a, b) /* 这里调用了 Exchg1 函数 */ printf("a = %d, b = %d.\n", a, b); }

Exchg1(a, b)时所完成的操作代码如下所示。

int x = a; /* ← */ int y = b; /* ← 注意这里,头两行是调用函数时的隐含操作 */ int tmp; tmp = x; x = y; y = tmp; 请注意在调用执行 Exchg1 函数的操作中我人为地加上了头两句: int x = a; int y = b;

这是调用函数时的两个隐含动作。它确实存在,现在我只不过把它显式地写了出来而已。问题一下就清晰起来啦。(看到这里,现在你认为函数里面交换操作的是a、b 变量或者只是 x、y 变量呢?)

原来 ,其实函数在调用时是隐含地把实参 a、b 的值分别赋值给了 x、y,之后在你写的 Exchg1 函数体内再也没有对 a、b 进行任何的操作了。交换的只是 x、y 变量。并不是 a、b。当然 a、b 的值没有改变啦!函数只是把 a、b 的值通过赋值传递给了 x、y,函数里头操作的只是 x、y 的值并不是 a、b 的值。这就是所谓的参数的值传递了。

哈哈,终于明白了,正是因为它隐含了那两个的赋值操作,才让我们产生了前述的迷惑(以为 a、b 已经代替了 x、y,对 x、y 的操作就是对a、b 的操作了,这是一个错误的观点啊!)

二、地址传递

继续!地址传递的问题!看地址传递的代码:

void Exchg2(int *px, int *py) { int tmp = *px; *px = *py; *py = tmp; printf("*px = %d, *py = %d.\n", *px, *py); } int main() { int a = 4; int b = 6; Exchg2(&a, &b); printf("a = %d, b = %d.\n”, a, b); return(0); } 它的输出结果是: *px = 6, *py = 4. a = 6, b = 4. 看函数的接口部分: Exchg2(int *px, int *py),请注意:参数 px、py 都是指针。 再看调用处:Exchg2(&a, &b);

它将 a 的地址(&a)代入到 px,b 的地址(&b)代入到 py。同上面的值传递一样,函数调用时作了两个隐含的操作:将&a,&b的值赋值给了 px、py。

px = &a; py = &b;

呵呵!我们发现,其实它与值传递并没有什么不同,只不过这里是将 a、b的地址值传递给了 px、py,而不是传递的 a、b的内容,而(请好好地在比较比较啦)整个 Exchg2 函数调用是如下执行的:

px = &a; /* ← */ py = &b; /* ← 请注意这两行,它是调用 Exchg2 的隐含动作。*/ int tmp = *px; *px = *py; *py = tmp; printf("*px =%d, *py = %d.\n", *px, *py);

这样,有了头两行的隐含赋值操作。我们现在已经可以看出,指针 px、py的值已经分别是 a、b 变量的地址值了。接下来,对*px、*py 的操作当然也就是对 a、b 变量本身的操作了。所以函数里头的交换就是对 a、b 值的交换了,这就是所谓的地址传递(传递 a、b 的地址给了px、py),你现在明白了吗?

三、引用传递

先看引用传递的代码:

void Exchg3(int &x, int &y) /* 注意定义处的形式参数的格式与 值传递不同 */ { int tmp = x; x = y; y = tmp; printf("x = %d, y = %d.\n", x, y); } int main() { int a = 4; int b = 6; Exchg3(a, b); /*注意:这里调用方式与值传递一样*/ printf("a = %d, b = %d.\n”, a, b); } 输出结果: x = 6, y = 4. a = 6, b = 4. /*这个输出结果与值传递不同。*/ 看到没有,与值传递相比,代码格式上只有一处是不同的,即在定义处: Exchg3(int &x, int &y)

但是我们发现 a 与 b 的值发生了对调。这说明了 Exchg3(a, b)里头修改的是 a、b 变量,而不只是修改 x、y 了。

我们先看 Exchg3 函数的定义处 Exchg3(int &x, int &y)。参数 x、 y 是 int的变量,调用时我们可以像值传递(如: Exchg1(a, b); )一样调用函数(如: Exchg3(a, b);)。但是 x、y 前都有一个取地址符号“&”。有了这个,调用 Exchg3 时函数会将 a、b 分别代替了 x、y 了,我们称:x、y分别引用了 a、b变量。这样函数里头操作的其实就是实参 a、b 本身了,也就是说函数里是可以直接修改到 a、b 的值了。

四、对比值传递与引用传递: 1、在函数定义格式上有不同

值传递在定义处是:Exchg1(int x, int y); 引用传递在这义处是:Exchg3(int &x, int &y);

2、调用时有相同的格式

值传递:Exchg1(a, b); 引用传递:Exchg3(a, b);

3、功能上是不同的

值传递的函数里操作的不是 a、b 变量本身,只是将 a、b 值赋给了 x、y。函数里操作的只是 x、y 变量而不是 a、b,显示 a、b 的值不会被 Exchg1 函数所修改。

引用传递 Exchg3(a, b)函数里是用 a、b 分别代替了 x、y。函数里操作的就是 a、b 变量的本身,因此 a、b的值可在函数里被修改的。

五、参考

姚云飞,《彻底搞定 C 指针》 刘洪涛,熊家.[嵌入式应用程序设计综合教程].北京:人民邮电出版社,2017. 刘洪涛,苗德行.[嵌入式 Linux C语言程序设计].北京:人民邮电出版社,2017



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3