C语言值传递与地址传递对比使用小结

 更新时间:2025年12月18日 09:02:42   作者:fyakm  
C语言中函数参数传递主要有值传递和地址传递两种方式,本文就来介绍一下C语言值传递与地址传递对比使用小结,具有一定的参考价值,感兴趣的可以了解一下

在C语言编程中,函数参数传递是一个非常重要的概念。我们调用函数时,常常需要给函数传递一些数据,而传递数据的方式有多种,其中值传递和地址传递是两种最常用的方式。了解这两种传递方式的区别和应用场景,能帮助我们根据实际需求选择合适的参数传递方式,避免在编程中出现地址传递时指针操作错误、值传递无法修改实参等问题。接下来,我们就详细探讨这两种传递方式。

值传递和地址传递的概念

值传递

值传递是指在调用函数时,将实际参数的值复制一份传递给函数的形式参数。也就是说,函数内部操作的是实参的副本,而不是实参本身。这就好比你把一份文件复印了一份给别人,别人在复印件上做任何修改,都不会影响到你手中的原件。

在C语言中,值传递是最常见的参数传递方式。当我们使用值传递时,函数内部对形参的修改不会影响到实参的值。例如,我们定义一个函数来计算两个整数的和:

#include <stdio.h>

// 定义一个函数,用于计算两个整数的和
int add(int a, int b) {
    // 在函数内部对形参进行操作
    a = a + 1;
    b = b + 1;
    return a + b;
}

int main() {
    int num1 = 3;
    int num2 = 5;
    // 调用函数,传递实参的值
    int result = add(num1, num2);
    printf("The result is: %d\n", result);
    // 输出实参的值,发现实参的值没有改变
    printf("num1 = %d, num2 = %d\n", num1, num2);
    return 0;
}

在这个例子中,add 函数接受两个整数作为参数,在函数内部对形参 ab 进行了修改。但是,当我们在 main 函数中输出实参 num1num2 的值时,会发现它们的值并没有改变。这就是值传递的特点,函数内部对形参的修改不会影响到实参。

地址传递

地址传递是指在调用函数时,将实际参数的地址传递给函数的形式参数。这样,函数内部就可以通过这个地址直接访问和修改实参的值。这就好比你把文件的存放地址告诉了别人,别人可以根据这个地址找到文件并进行修改,修改的就是你手中的原件。

在C语言中,地址传递通常使用指针来实现。指针是一种特殊的变量,它存储的是另一个变量的地址。例如,我们定义一个函数来交换两个整数的值:

#include <stdio.h>

// 定义一个函数,用于交换两个整数的值
void swap(int *a, int *b) {
    int temp;
    // 通过指针操作交换两个整数的值
    temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int num1 = 3;
    int num2 = 5;
    // 调用函数,传递实参的地址
    swap(&num1, &num2);
    // 输出交换后的实参的值,发现实参的值已经改变
    printf("num1 = %d, num2 = %d\n", num1, num2);
    return 0;
}

在这个例子中,swap 函数接受两个整数指针作为参数,在函数内部通过指针操作交换了两个整数的值。当我们在 main 函数中输出实参 num1num2 的值时,会发现它们的值已经交换了。这就是地址传递的特点,函数内部可以通过指针直接访问和修改实参的值。

值传递和地址传递的区别

数据操作对象不同

值传递操作的是实参的副本,而地址传递操作的是实参本身。这是值传递和地址传递最本质的区别。

在值传递中,函数内部对形参的修改不会影响到实参的值,因为形参是实参的副本。而在地址传递中,函数内部通过指针直接访问和修改实参的值,因为指针指向的是实参的地址。

内存开销不同

值传递需要复制实参的值,会占用额外的内存空间。而地址传递只需要传递实参的地址,内存开销相对较小。

当实参是一个很大的结构体或者数组时,值传递会复制整个结构体或数组,占用大量的内存空间。而地址传递只需要传递结构体或数组的首地址,内存开销很小。

安全性不同

值传递不会改变实参的值,相对比较安全。而地址传递可以直接修改实参的值,如果使用不当,可能会导致程序出现错误。

在一些情况下,我们不希望函数内部修改实参的值,这时就可以使用值传递。而在一些需要修改实参的值的情况下,就需要使用地址传递。

值传递和地址传递的应用场景

值传递的应用场景

  • 不需要修改实参的值:当我们只需要使用实参的值,而不需要修改实参的值时,可以使用值传递。例如,计算两个数的和、求平均值等。
#include <stdio.h>

// 计算两个数的平均值
float average(int a, int b) {
    return (a + b) / 2.0;
}

int main() {
    int num1 = 3;
    int num2 = 5;
    float result = average(num1, num2);
    printf("The average is: %.2f\n", result);
    return 0;
}

在这个例子中,average 函数只需要使用实参 num1num2 的值,不需要修改它们的值,所以使用值传递。

  • 保护实参的值:当我们不希望函数内部修改实参的值时,可以使用值传递。例如,我们有一个函数用于打印数组的元素,我们不希望函数内部修改数组的元素,就可以使用值传递。
#include <stdio.h>

// 打印数组的元素
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);
    printArray(arr, size);
    return 0;
}

在这个例子中,printArray 函数只需要使用数组的元素,不需要修改它们的值,所以使用值传递。

地址传递的应用场景

  • 需要修改实参的值:当我们需要在函数内部修改实参的值时,必须使用地址传递。例如,交换两个数的值、对数组进行排序等。
#include <stdio.h>

// 交换两个数的值
void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int num1 = 3;
    int num2 = 5;
    swap(&num1, &num2);
    printf("num1 = %d, num2 = %d\n", num1, num2);
    return 0;
}

在这个例子中,swap 函数需要交换两个数的值,所以使用地址传递。

  • 传递大型数据结构:当实参是一个很大的结构体或者数组时,使用地址传递可以减少内存开销。例如,我们有一个大型的结构体,包含很多成员,我们可以使用地址传递来传递这个结构体。
#include <stdio.h>

// 定义一个大型结构体
typedef struct {
    int id;
    char name[50];
    float score;
} Student;

// 打印学生信息
void printStudent(Student *s) {
    printf("ID: %d\n", s->id);
    printf("Name: %s\n", s->name);
    printf("Score: %.2f\n", s->score);
}

int main() {
    Student s = {1, "John", 85.5};
    printStudent(&s);
    return 0;
}

在这个例子中,Student 结构体包含很多成员,如果使用值传递,会复制整个结构体,占用大量的内存空间。而使用地址传递,只需要传递结构体的地址,内存开销很小。

通过交换两个变量值的代码示例对比值传递和地址传递的效果

下面我们通过一个交换两个变量值的代码示例,来对比值传递和地址传递的效果。

值传递实现交换

#include <stdio.h>

// 尝试使用值传递交换两个变量的值
void swapByValue(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int num1 = 3;
    int num2 = 5;
    printf("Before swap: num1 = %d, num2 = %d\n", num1, num2);
    // 调用函数,使用值传递
    swapByValue(num1, num2);
    printf("After swap: num1 = %d, num2 = %d\n", num1, num2);
    return 0;
}

在这个例子中,swapByValue 函数使用值传递来交换两个变量的值。但是,由于值传递操作的是实参的副本,函数内部对形参的修改不会影响到实参的值,所以交换没有成功。

地址传递实现交换

#include <stdio.h>

// 使用地址传递交换两个变量的值
void swapByAddress(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int main() {
    int num1 = 3;
    int num2 = 5;
    printf("Before swap: num1 = %d, num2 = %d\n", num1, num2);
    // 调用函数,使用地址传递
    swapByAddress(&num1, &num2);
    printf("After swap: num1 = %d, num2 = %d\n", num1, num2);
    return 0;
}

在这个例子中,swapByAddress 函数使用地址传递来交换两个变量的值。由于地址传递操作的是实参本身,函数内部通过指针直接访问和修改实参的值,所以交换成功。

总结与后续学习

通过以上的学习,我们了解了C语言中值传递和地址传递的概念、区别和应用场景。值传递操作的是实参的副本,不会改变实参的值,内存开销较大,但相对安全。地址传递操作的是实参本身,可以修改实参的值,内存开销较小,但使用不当可能会导致程序出错。我们可以根据实际需求选择合适的参数传递方式,避免地址传递时指针操作错误、值传递无法修改实参等问题。

掌握了值传递和地址传递的内容后,下一节我们将深入学习C语言函数的返回值和作用域,进一步完善对本章C语言函数与模块化编程主题的认知。

到此这篇关于C语言值传递与地址传递对比使用小结的文章就介绍到这了,更多相关C语言值传递与地址传递内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 总结UNIX/LINUX下C++程序计时的方法

    总结UNIX/LINUX下C++程序计时的方法

    本文总结了下UNIX/LINUX下C++程序计时的一些函数和方法,对日常使用C++程序的朋友很有帮助,有需要的小伙伴们可以参考学习,下面一起来看看吧。
    2016-08-08
  • C++数据结构与算法之双缓存队列实现方法详解

    C++数据结构与算法之双缓存队列实现方法详解

    这篇文章主要介绍了C++数据结构与算法之双缓存队列实现方法,结合实例形式分析了双缓存队列的原理、实现方法与相关注意事项,需要的朋友可以参考下
    2017-08-08
  • C++使用map实现多进程拷贝文件的程序思路

    C++使用map实现多进程拷贝文件的程序思路

    这篇文章主要介绍了C++使用mmap实现多进程拷贝文件,通过本文给大家分享程序思路及完整代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • 浅析C++的引用与const指针与各种传递方式

    浅析C++的引用与const指针与各种传递方式

    这篇文章主要介绍了浅析C++的引用与const指针与各种传递方式的相关资料,需要的朋友可以参考下
    2017-08-08
  • C语言函数传递数组和传递地址的区别你知道吗

    C语言函数传递数组和传递地址的区别你知道吗

    这篇文章主要介绍了C语言中数组作为函数的参数以及返回值的使用简单入门,这里以一维数组作为基本条件进行例子讲解,需要的朋友可以参考下
    2021-09-09
  • C/C++ Qt TreeWidget 嵌套节点操作使用

    C/C++ Qt TreeWidget 嵌套节点操作使用

    本文主要介绍了TreeWidget的如何使用,实现对树形框多节点的各种操作,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • C语言实现图书馆管理系统

    C语言实现图书馆管理系统

    这篇文章主要为大家详细介绍了C语言实现图书馆管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • C语言用递归函数对素数进行判断流程

    C语言用递归函数对素数进行判断流程

    素数判断是编程语言学习过程中一个老生常谈的话题,而它的实现也有多种算法,包括经典的试除法(以及试除法的几种优化),进阶的素数表筛选法,埃拉托斯特尼筛法和欧拉筛法(以及它们的优化)等。对以上算法感兴趣的朋友们,不妨搜索“素数判断的N种境界”来学习了解
    2022-09-09
  • C++封装远程注入类CreateRemoteThreadEx实例

    C++封装远程注入类CreateRemoteThreadEx实例

    这篇文章主要介绍了C++封装远程注入类CreateRemoteThreadEx实例,详细讲述了注入DLL到指定的地址空间以及从指定的地址空间卸载DLL的方法,需要的朋友可以参考下
    2014-10-10
  • C++实现LeetCode(309.买股票的最佳时间含冷冻期)

    C++实现LeetCode(309.买股票的最佳时间含冷冻期)

    这篇文章主要介绍了C++实现LeetCode(309.买股票的最佳时间含冷冻期),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08

最新评论