Cprogramming 简明教程

Function Call by Reference in C

函数可以通过两种方式调用:(a)按值调用和 (b) 按引用调用。在本章中,我们将解释按引用调用函数的机制。

让我们从简要概述“指针”和“地址运算符 (&)”开始本章。为了完全理解按引用调用的机制,学习这两个概念非常重要。

The Address Operator (&) in C

在 C 语言中,变量是一个已命名的内存位置。当声明变量时,编译器将在内存中分配一个随机位置,并在内部使用用户定义的名称标识该位置。

要获取创建变量的地址,我们使用 address (&) operator

Example

请看以下示例:

#include <stdio.h>

int main(){

   int x = 10;

   printf("x: %d Address of x: %d", x, &x);
}

这将打印 x 的值和它的地址 −

x: 10 Address of x: -1990957196

What is a Pointer in C?

指针是一个存储另一个变量地址的变量。要声明一个指针变量,它的名称前面加上 * 符号。指针变量的类型及其宿主变量的类型必须相同。

地址分配给 & 运算符。 dereference operator ( )* 与指针一起使用。它获取地址分配给指针的变量的值。

Example

以下示例演示了如何在 C 中进行引用和解引用 −

#include <stdio.h>

int main(){

   int x = 10;
   int *y = &x;

   printf("x: %d Address of x: %d\n", x, &x);
   printf("Address of y: %d \n", &y);
   printf("Value at address in y: %d\n", *y);
}

运行代码并检查其输出:

x: 10 Address of x: -1742755108
Address of y: -1742755104
Value at address in y: 10

How Does Call by Reference Work in C?

当按引用调用函数时,将传递实际参数变量的地址,而不是它们的值。

让我们定义一个接收两个变量的引用作为参数的 add() 函数 −

int add(int *x, int *y){

   int z = *x + *y;

   return z;
}

当调用此函数时,会传递实际参数的地址。

Example

让我们从 main() 函数的内部通过引用调用 add() 函数 −

#include <stdio.h>

/* function declaration */
int add(int *, int *);

int main(){

   int a = 10, b = 20;
   int c = add(&a, &b);

   printf("Addition: %d", c);
}

int add(int *x, int *y){

   int z = *x + *y;

   return z;
}

当你运行这段代码时,它将产生以下输出:

Addition: 30

现在让我们了解此代码的实际工作原理。 main() 函数将 @s0@s1 的地址传递给 @s2 函数。 @s3@s4 的地址被分配给指针变量 @s5@s6

现在关注语句 "z = @s7" 存储 @s8 的地址。 @s9@s10 中的解引用运算符分别获取 @s11@s12 的值,因此 @s13main() 函数中 @s14@s15 的和。

Example: Swap Values with Call by Reference

让我们在以下交换两个变量值的示例的帮助下,更详细地了解按引用调用机制如何工作。

#include <stdio.h>

/* Function definition to swap the values */
/* It receives the reference of two variables whose values are to be swapped */

int swap(int *x, int *y){

   int z;

   z = *x;   /* save the value at address x */
   *x = *y;  /* put y into x */
   *y = z;   /* put z into y */

   return 0;
}

/* The main() function has two variables "a" and "b" */
/* Their addresses are passed as arguments to the swap() function. */

int main(){

   /* local variable definition */
   int a = 10;
   int b = 20;

   printf("Before swap, value of a: %d\n", a );
   printf("Before swap, value of b: %d\n", b );

   /* calling a function to swap the values */
   swap(&a, &b);

   printf("After swap, value of a: %d\n", a);
   printf("After swap, value of b: %d\n", b);

   return 0;
}

当你运行这段代码时,它将产生以下输出:

Before swap, value of a: 10
Before swap, value of b: 20
After swap, value of a: 20
After swap, value of b: 10

Explanation

假设 main() 函数中的变量 @s16@s17 被分配了内存地址为 100 和 200 的位置。当它们的地址传递给 @s18@s19 (请记住,它们是指针)时,swap() 函数中的变量 @s20@s21@s22 分别被创建于地址 1000、2000 和 3000。

inside the swap

由于 "x" 和 "y" 存储 "a" 和 "b" 的地址,正如上图所示,因此 "x" 变为 100,而 "y" 变为 200。

swap() 函数内部,第一条语句 @s23 使地址存储在 "x" 中的值存储在 "x" 中(值为 10)。类似地,在语句 @s24 中,地址存储在 "y" 中的值(值为 20)存储在其指针为 "x" 的位置。

最后,语句 @s25 将 "z" 分配给由 "y" 指向的变量,即 main() 函数中的 "b"。现在 "a" 和 "b" 的值发生了交换。

下图直观地展示了其工作原理 −

understand visually how this works

Mixing Call by Value and Call by Reference

你可以使用按值调用和按引用调用相结合的函数调用机制。它可以被称为“混合调用机制”,其中一些参数按值传递,而另一些参数按引用传递。

C 中的函数可以有多个参数,但只能返回一个值。按引用调用机制是克服此限制的一个很好的解决方案。

Example

在这个示例中, calculate() 函数通过值接收一个整型参数,通过两个指针存储其平方和立方。

#include <stdio.h>
#include <math.h>

/* function declaration */
int calculate(int, int *, int *);

int main(){

   int a = 10;
   int b, c;

   calculate(a, &b, &c);

   printf("a: %d \nSquare of a: %d \nCube of a: %d", a, b, c);
}

int calculate(int x, int *y, int *z){

   *y  = pow(x,2);
   *z = pow(x, 3);

   return 0;
}

当你运行这段代码时,它将产生以下输出:

a: 10
Square of a: 100
Cube of a: 1000

当函数需要执行内存级别的操作(例如控制外围设备、执行动态分配等)时,按引用调用机制被广泛使用。