C 语言按值调用和按引用调用

2025年6月29日 | 阅读9分钟

在 C 编程中,主要有两种将参数传递给函数的方法:传值调用(Call by Value)和传引用调用(Call by Reference)。当我们向函数传递参数时,了解这些参数在函数内部如何被处理非常重要。

这些机制决定了函数接收的是变量的副本还是原始变量的引用。选择合适的方法可以确保程序的正确性、安全性和效率。

call by value and call by reference in c

让我们逐一了解 C 语言 中的传值调用和传引用调用。

C 中的传值调用

在传值调用方法中,实际参数的值被复制到形式参数中。换句话说,我们可以说在传值调用方法中,变量的值被用于函数调用。在传值调用方法中,我们不能通过形式参数来修改实际参数的值。这是原始数据类型(如整数、字符和浮点数)的标准方法。它是 C 编程语言的默认行为。

在传值调用中,由于实际参数的值被复制到形式参数中,因此实际参数和形式参数会分配不同的内存。实际参数是用于函数调用的参数,而形式参数是用于函数定义的参数。

语法

它具有以下语法:

C 语言传值调用示例

让我们通过下面的示例来理解 C 语言中的传值调用概念:

示例

编译并运行

输出

Before function call x=100
Before adding value inside function num=100
After adding value inside function num=200
After function call x=100

说明

在此示例中,我们演示了传值调用,其中变量 x 的副本被传递给 change() 函数。在函数内部对 num 所做的任何更改都不会影响 main() 函数中的原始变量 x。因此,在函数调用后,其值保持不变。

用于交换两个变量值的传值调用示例

让我们再举一个例子来说明传值调用如何交换两个变量的值:

示例

编译并运行

输出

Before swapping the values in main a = 10, b = 20
After swapping values in function a = 20, b = 10
After swapping values in main a = 10, b = 20  

说明

在此示例中,我们演示了传值调用,其中 swap() 函数接收 a 和 b 的副本。之后,交换仅发生在函数内部,因此在函数调用后 main() 函数中的原始值保持不变。

C 语言传值调用的特点

C 语言的传值调用有几个特点。C 语言传值调用的一些主要特点如下:

  • 数据隔离:基本值保持不变。
  • 安全且可预测:由于函数无法修改原始变量,因此更容易理解代码。
  • 内存开销:对于大型 数据类型结构体,复制可能会产生额外的内存和性能成本。
  • 用例:当意图仅使用输入而不修改它时,首选此方法。

C 语言中的传引用调用

在传引用调用中,我们传递实际参数的内存地址(引用)给函数,而不是传递变量的副本。它允许函数直接访问和修改实际变量。

在传引用调用中,形式参数和实际参数的内存分配是相似的。函数中的所有操作都在确切参数地址中存储的值上执行,并且修改后的值存储在同一地址。C 语言本身不支持传引用调用(例如 C++),但可以通过 指针 来模拟。

C 语言传引用调用的语法

它具有以下语法:

C 语言传引用调用示例

让我们举一个例子来说明 C 语言中的传引用调用:

示例

编译并运行

输出

Before function call x=100
Before adding value inside function num=100
After adding value inside function num=200
After function call x=200

说明

在此示例中,我们使用指针演示了传引用调用。之后,我们将 x 的地址传递给 change() 函数,从而可以直接修改其值。结果,函数内部的更改会反映在 main() 函数中,并且在函数调用后 x 变为 200。

用于交换两个变量值的传引用调用示例

让我们举一个例子来说明如何使用 C 语言的传引用调用来交换两个 变量 的值:

示例

编译并运行

输出

Before swapping the values in main a = 10, b = 20
After swapping values in function a = 20, b = 10
After swapping values in main a = 20, b = 10  

说明

在上面的示例中,我们使用指针演示了传引用调用。之后,将 a 和 b 的地址传递给 swap() 函数,这使得它们的实际值可以被交换。因此,更改会保留在 main() 函数中,a 变为 20,b 变为 10。

C 语言传引用调用的特点

C 语言的传引用调用有几个特点。一些主要特点如下:

  • 直接修改:函数可以更改实际变量的值。
  • 对大型数据高效:与复制大型结构体或数组相比,引用可以提供更好的性能。
  • 复杂性和风险:使用指针可能会导致 bug 或内存问题。
  • 用例:当函数需要修改输入或返回多个值时。

何时在 C 语言中使用传值调用和传引用调用

在 C 编程中,选择传值调用和传引用调用在代码的性能和正确性方面都起着关键作用。在 C 语言中,有几种情况可以使用传值调用和传引用调用。一些主要情况如下:

传值调用

可以使用传值调用,当:

  • 我们希望保护原始变量不被修改。
  • 函数只需要读取数据,不需要修改。
  • 我们处理的是小型数据类型,如整数或字符,此时复制成本很低。

传引用调用

可以使用传引用调用,当:

  • 我们需要在函数内部修改原始变量。
  • 我们处理大型数据结构(如数组、结构体)以避免不必要的复制。
  • 我们需要一个函数通过指针返回多个值。
  • 性能是首要考虑因素,并且需要内存效率。
  • 我们正在操作对象类行为或动态内存。

例如,传引用调用在排序算法、输入/输出操作和实时更新方面提供了速度和灵活性。另一方面,传值调用为只读操作(如检查有效性或状态)提供了安全性和清晰性。

C 语言中传值调用和传引用调用的区别

C 语言中的传值调用和传引用调用之间有几个区别。一些主要区别如下:

传值调用传引用调用
将值的副本传递给函数。将值的地址传递给函数。
在函数内部所做的更改仅限于函数本身。通过更改形式参数,实际参数的值不会改变。在函数内部所做的更改也会在函数外部生效。通过更改形式参数,实际参数的值确实会改变。
实际参数和形式参数在不同的内存位置创建。实际参数和形式参数在同一内存位置创建。
数据是安全的,因为原始数据受到保护,不会被意外更改。如果处理不当,数据是有风险的,因为原始数据可能会被修改。
用于我们想读取或模拟数据而不修改它。用于我们需要修改或更新原始变量。
如果重复复制大量数据,可能会较慢。对于大型结构体(如数组或结构体)更有效。
易于实现和理解。由于指针,实现起来稍微复杂一些。
执行一些简单操作,包括数学模拟、比较等。执行一些操作,例如存款、更新分数、修改记录等。

结论

总之,理解 C 编程中传值调用和传引用调用之间的区别并编写高效的代码是必要的。传值调用提供了一种安全的方式来传递变量进行任务,而不会改变其原始状态的风险。另一方面,传引用调用在需要直接修改外部变量的任务中非常强大,例如更新值、更改数组或操作结构体。

C 语言中的传值调用和传引用调用常见问题解答

1) C 语言中的传值调用是什么?

在传值调用方法中,实际参数的值被复制到形式参数中。我们不能通过形式参数来修改实际参数的值。

2) 传引用调用如何帮助在函数内修改实际变量?

在 C 语言中,传引用调用使函数能够通过传递函数(使用指针)来直接访问和修改原始变量。在函数内部,我们使用指针来解引用地址并更改存储在该位置的值。

3) 我们可以在 C 语言中使用数组和传引用调用吗?

是的,我们可以在 C 编程中将数组作为指针传递。因此,在函数内部进行的任何修改都会影响原始数组。

4) 我们可以在 C 语言中使用传值调用交换两个变量吗?

不,我们不能在 C 语言中使用传值调用来交换两个变量。在传值调用中,交换不会影响原始变量,因为只交换了副本。

5) 使用 C 语言的传引用调用时,需要避免的一些常见错误是什么?

常见错误包括:

  • 空指针可能导致程序崩溃。
  • 调用函数时忘记使用 & 传递地址。
  • 错误地定义指针,导致逻辑错误。
  • 无意中覆盖重要数据,尤其是在重复使用同一指针时。
  • 当使用只读访问时没有使用 const,这可能导致意外修改。

为了避免这些问题,请始终验证指针,清楚地记录函数的行为,并在不需要修改时使用 const 指针。