[C]值传递、指针传递、引用传递

本文详细解析了C语言中值传递、地址传递及引用传递的概念与应用,通过代码实例展示了不同传递方式对内存的影响,帮助读者理解参数传递机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C语言值传递怎么用,引用传递怎么用?

以表格来简要说明并区分这几种传递到底在做什么:

类型传递对象传递行为内存关系适用情况区别与联系举例
值传递数值将实参的数值拷贝到另一块独立的内存上,在新的内存上操作形参和实参占用不同的内存函数内部需要修改参数,并且希望此改变的作用域不涉及调用者传递是单向的,实参->形参函数调用时,参数为数值
地值传递地址直接在实参所在的内存上操作形参指向的和实参所在的是一块内存内部对变量进行操作,并且希望此操作的作用域包括调用者;返回值传递传递是双向的,实参<->实参函数调用时,参数为地址
引用传递别名同上形参和实参是同一个变量的不同名字,拥有相同的内存同上同上实参代替了形参

具体说来,引用/地址传递在返回值传递上的应用是指:
假设函数需要有多个返回值,而显式上不能有返回值或者只能有一个返回值,则此时可利用指针/引用传递,对其他需要返回的变量进行修改,并将修改返回给调用者,完成隐式的返回值传递。
下面我们用代码来直接证明这三种传递在做什么:

#include<iostream>
#include<stdlib.h>
using namespace std;

void swap_value(int a, int b){
    cout << "swap 前,形参的数值和地址:" << endl;
    cout << "value(a) = " << a << "," << "变量a的地址:" << &a << endl;
    cout << "value(b) = " << b << "," << "变量b的地址:" << &b << endl;
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
    cout << "swap 后,形参的数值和地址:" << endl;
    cout << "value(a) = " << a << "," << "变量a的地址:" << &a << endl;
    cout << "value(b) = " << b << "," << "变量b的地址:" << &b << endl;

}

void swap_adress_value(int *a, int *b){
    cout << "swap 前,形参的地址和指向的数值:" << endl;
    cout << "value(a) = " << a << "," << "*a:" << *a << endl;
    cout << "value(b) = " << b << "," << "*b:" << *b << endl;
    int *tmp;
    tmp = a;
    a = b;
    b = tmp;
    cout << "swap 后,形参的地址和指向的数值:" << endl;
    cout << "value(a) = " << a << "," << "*a:" << *a << endl;
    cout << "value(b) = " << b << "," << "*b:" << *b << endl;

}

void swap_pointer(int *a, int *b){
    cout << "swap 前,形参的地址和指向的数值:" << endl;
    cout << "value(a) = " << a << "," << "*a:" << *a << endl;
    cout << "value(b) = " << b << "," << "*b:" << *b << endl;
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
    cout << "swap 后,形参的地址和指向的数值:" << endl;
    cout << "value(a) = " << a << "," << "*a:" << *a << endl;
    cout << "value(b) = " << b << "," << "*b:" << *b << endl;

}

void swap_reference(int &a, int &b){
    cout << "swap 前,形参的地址和指向的数值:" << endl;
    cout << "value(a) = " << a << "," << "a存储地址:" << &a << endl;
    cout << "value(b) = " << b << "," << "b存储地址:" << &b << endl;
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
    cout << "swap 后,形参的地址和指向的数值:" << endl;
    cout << "value(a) = " << a << "," << "a存储地址:" << &a << endl;
    cout << "value(b) = " << b << "," << "b存储地址:" << &b << endl;

}

int main(){
    cout << "值传递:" << endl;
    int x = 10;
    int y = -1;
    cout << "swap 前,实参的数值和地址:" << endl;
    cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
    cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
    swap_value(x, y);

    cout << "swap 后,实参的数值和地址:" << endl;
    cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
    cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;


    system("pause");
    cout << endl;
    cout << endl;
    cout << endl;

    cout << "传递地址且对地址进行修改:" << endl;
    x = 10;
    y = -1;
    cout << "swap 前,实参的数值和地址:" << endl;
    cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
    cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
    swap_adress_value(&x, &y);

    cout << "swap 后,实参的数值和地址:" << endl;
    cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
    cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;

    system("pause");
    cout << endl;
    cout << endl;
    cout << endl;

    cout << "指针传递:" << endl;
    x = 10;
    y = -1;
    cout << "swap 前,实参的数值和地址:" << endl;
    cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
    cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
    swap_pointer(&x, &y);

    cout << "swap 后,实参的数值和地址:" << endl;
    cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
    cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;

    system("pause");
    cout << endl;
    cout << endl;
    cout << endl;

    cout << "引用传递:" << endl;
    x = 10;
    y = -1;
    cout << "swap 前,实参的数值和地址:" << endl;
    cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
    cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;
    swap_reference(x, y);

    cout << "swap 后,实参的数值和地址:" << endl;
    cout << "value(x) = " << x << "," << "变量x的地址:" << &x << endl;
    cout << "value(y) = " << y << "," << "变量y的地址:" << &y << endl;

    system("pause");
    cout << endl;
    cout << endl;
    cout << endl;

}

再来看执行结果:

值传递:
swap 前,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
swap 前,形参的数值和地址:
valuea) = 10,变量a的地址:0046FC68
value(b) = -1,变量b的地址:0046FC6C
swap 后,形参的数值和地址:
valuea) = -1,变量a的地址:0046FC68
value(b) = 10,变量b的地址:0046FC6C
swap 后,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
请按任意键继续. . . 



传递地址且对地址进行修改:
swap 前,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
swap 前,形参的地址和指向的数值:
valuea) = 0046FD4C,*a:10
value(b) = 0046FD40,*b:-1
swap 后,形参的地址和指向的数值:
valuea) = 0046FD40,*a:-1
value(b) = 0046FD4C,*b:10
swap 后,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
请按任意键继续. . . 



指针传递:
swap 前,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
swap 前,形参的地址和指向的数值:
valuea) = 0046FD4C,*a:10
value(b) = 0046FD40,*b:-1
swap 后,形参的地址和指向的数值:
valuea) = 0046FD4C,*a:-1
value(b) = 0046FD40,*b:10
swap 后,实参的数值和地址:
value(x) = -1,变量x的地址:0046FD4C
value(y) = 10,变量y的地址:0046FD40
请按任意键继续. . . 



引用传递:
swap 前,实参的数值和地址:
value(x) = 10,变量x的地址:0046FD4C
value(y) = -1,变量y的地址:0046FD40
swap 前,形参的地址和指向的数值:
valuea) = 10,a存储地址:0046FD4C
value(b) = -1,b存储地址:0046FD40
swap 后,形参的地址和指向的数值:
valuea) = -1,a存储地址:0046FD4C
value(b) = 10,b存储地址:0046FD40
swap 后,实参的数值和地址:
value(x) = -1,变量x的地址:0046FD4C
value(y) = 10,变量y的地址:0046FD40
请按任意键继续. . . 



      我们结合运行结果来分析一下:
      调用swap_xxx函数之前,变量x,y分别有自己的地址和数值。
      调用函数swap_value时,相当于做了以下2个赋值操作:

a = x;b = y;

     这只是说把x、y的value分别赋给a、b。
     可以通过结果看出,a、b有自己的内存,内存地址与x、y不同。且调出swap_value之后,发生数值交换的仅是内部变量而已,外部变量x、y的地址和数值并没受到影响。
     调用swap_adress_value/swap_pointer时,相当于做了以下2个赋值操作:

*a = &x*b = &y

     这里&是取地址的意思,是把x、y的地址分别赋给指针变量a、b,也就是说a有自己的内存地址,这块内存存储的就是x的地址,也即a指向了x。
     只不过,在函数swap_adress_value内部,只是将指针变量a和b的value做了交换。所以外部变量x、y不受任何影响,而内部变量a、b有自己的内存地址,a和b的地址未发生改变,但是a和b的value改变了,a和b指向的变量改变了。
     而在swap_pointer里面,则是将a和b指向的内容作了交换,a和b的value未发生改变,依然指向之前的内存,但是它们指向的内存里面所存储的内容作了交换。同时在外部,x和y依然对应着原来的内存,所以x和y的地址都没有改变,但是里面写入的值却发生了改变。也就是说内部变量交换的时候,是在外部变量所对应的同一块内存空间上进行的。
     调用swap_reference时,相当于做了以下2个赋值操作:

&a = x;&b = y;

     这里&是引用的意思,是说a和x对应着同一块内存,对其中任何一个的修改,另一个都会受到影响,a和x相当于同一个变量的两个名字。所以内部变量a和x的地址一样,数值一样。交换之后,a和x的数值、地址依然一样。

#define
#ifdef的用途
#include的作用

#include是文件包含指令,在程序编译时,把#include后面指定文件的内容包含进当前的文件中。主要有2种形式:
1、#include<file.h>
从标准库中寻找file.h文件,是系统库头文件,根据一定的规则查找filh.h。
2、#include”file.h”
从工程目录下开始寻找file.h文件,是自定义的头文件,在源文件所在位置查找filh.h。

typedef
C语言工程的编译过程

如下图所示:
这里写图片描述

C程序的内存分布
数组的初始化
数组和指针的联系与区别
为什么数组不能更改指向地址?这样设计的动机是什么?
void指针是什么?
函数指针怎么定义?
函数指针的用途是什么?
malloc和free,什么时候需要用它们?
<think>好的,我现在需要回答用户关于C++中指针传递值传递引用传递的区别及应用场景的问题。首先,我需要回顾一下已有的参考资料,确保准确理解每个传递方式的特点。 首先,根据引用[1]、[2]、[4],值传递是将实参的副本传递给函数,函数内部修改的是副本,不影响原始值。这点在示例代码中也很清楚,比如modifyValue函数里的x被修改为100,但main函数中的a仍然保持原值。这说明值传递适用于不需要修改原始数据的场景,或者处理小型数据时效率较高的情况。 接下来是引用传递引用[3][4]提到,引用传递传递变量的别名,函数内对引用的操作直接影响原始变量。引用必须初始化且不能为空,这使得它在需要直接修改原变量或者传递大型数据结构时更高效,避免了拷贝开销。例如,swap函数使用引用参数可以直接交换两个变量的值,而不需要指针的语法。 然后是指针传递。根据引用[3]、[5],指针传递实际上是传递指针的副本,这个副本指向原变量的地址。因此,通过指针可以修改原变量的值,但无法改变原指针的指向。指针允许传递空值,这在需要可选参数或动态内存管理时非常有用。例如,当函数需要处理可能为null的情况,或者需要重新分配内存时,指针更合适。 现在需要比较三者的区别。值传递引用/指针传递的主要区别在于是否复制数据以及能否修改原数据。引用指针都能修改原数据,但引用更安全,因为不能为空,语法也更简洁。而指针则更灵活,允许空值地址操作。 应用场景方面,值传递适合小型数据或不需修改的场景;引用传递适合需要修改原数据或大型数据;指针适合可选参数、动态内存或需要改变指向的情况。例如,动态数组处理可能用指针,而交换变量值用引用更直观。 需要注意,其他语言如Java的参数传递机制不同,可能只有值传递,但对象类型传递的是引用的副本。这部分可能需要简要提及,但用户主要关注C++,所以重点在C++的区别。 最后,需要检查是否有遗漏或错误。比如,确认引用不能为空是否正确,以及指针传递中能否改变原指针的指向。根据引用[3],指针传递时形参是实参的拷贝,因此修改形参的指向不会影响实参指针,但可以通过解引用修改指向的数据。 总结:结构上先分别介绍三种传递方式,再对比区别,最后说明应用场景,并附上示例代码。确保回答清晰,引用正确,符合用户要求的中文格式要求。</think>### 指针传递 vs 值传递 vs 引用传递的区别与使用场景 在 C++ 中,函数参数传递方式主要分为**值传递**、**指针传递****引用传递**。它们的行为差异主要体现在内存操作、性能开销应用场景上。 --- ### 一、核心区别 #### 1. **值传递** - **定义**:将实参的**副本**传递给函数,函数内操作的是副本,不影响原始数据。 - **特点**: - 适用于小型数据(如基本类型)。 - 无法通过形参修改实参的值。 - 默认的传递方式(无需特殊语法)。 - **示例**: ```cpp void modifyValue(int x) { x = 100; // 修改副本,不影响实参 } int main() { int a = 10; modifyValue(a); std::cout << a; // 输出 10 } ``` #### 2. **指针传递** - **定义**:传递变量的**内存地址**,函数通过指针间接操作原始数据。 - **特点**: - 允许修改实参的值(通过解引用)。 - 指针本身是值传递传递的是地址的副本),因此无法通过形参指针修改实参指针的指向[^3]。 - 支持空值(`nullptr`),适合可选参数或动态内存管理[^5]。 - **示例**: ```cpp void modifyByPointer(int* ptr) { *ptr = 100; // 通过指针修改实参的值 } int main() { int a = 10; modifyByPointer(&a); std::cout << a; // 输出 100 } ``` #### 3. **引用传递** - **定义**:传递变量的**别名**,函数内操作直接影响原始数据。 - **特点**: - 语法简洁(无需解引用)。 - 引用必须初始化且不能为空。 - 无法通过形参引用修改实参引用的绑定关系。 - 性能高效(避免大型对象的拷贝开销)[^4]。 - **示例**: ```cpp void modifyByReference(int& ref) { ref = 100; // 直接修改实参的值 } int main() { int a = 10; modifyByReference(a); std::cout << a; // 输出 100 } ``` --- ### 二、对比总结 | 特性 | 值传递 | 指针传递 | 引用传递 | |---------------------|---------------------|-----------------------|-----------------------| | **内存操作** | 操作副本 | 通过地址操作原始数据 | 直接操作原始数据 | | **空值支持** | 不适用 | 支持(`nullptr`) | 不支持 | | **语法复杂度** | 简单 | 需解引用(`*`) | 简洁(无特殊符号) | | **适用场景** | 小型数据、只读操作 | 动态内存、可选参数 | 大型对象、需修改实参 | --- ### 三、使用场景 1. **值传递**: - 函数无需修改原始数据(如数学计算)。 - 处理小型数据(如`int`, `char`)时性能更优[^2]。 2. **指针传递**: - 需要传递空值或可选参数(如链表节点)。 - 动态内存管理(如`new`/`delete`操作)[^5]。 - 需在函数内改变指针指向(需使用指针指针)。 3. **引用传递**: - 需要直接修改原始数据(如交换函数`swap`)。 - 传递大型对象(如类实例、容器)避免拷贝。 - 实现运算符重载(如`operator<<`)。 --- ### 四、其他语言中的差异 - **Java/Python**:仅支持值传递,但对象类型传递的是引用的副本(形似引用传递,实为值传递)。 - **Rust**:通过所有权机制限制引用指针的使用,避免内存安全问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值