引用和指针

本文详细介绍了C++中指针与引用的区别,包括它们在内存分配、初始化、空值处理等方面的差异,并探讨了在参数传递和函数返回时的应用。指针可以为空,而引用必须在创建时初始化且不可改变。在函数调用中,引用传递直接操作实际参数,而指针传递可能需要二级指针来改变实参。返回引用可以避免拷贝开销,但要注意局部变量引用的安全性。返回指针则可能涉及指针拷贝。最后,给出了示例代码演示了指针和引用交换函数的实现。

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

引用和指针的区别

(1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。
(2) 引用不可以为空,当被创建的时候,必须初始化,初始化后就不会再发生改变;而指针可以是空值,可以在任何时候被初始化,指针的值在初始化后可以改变,即指向其它的存储单元。
(3) 可以有const指针,但是没有const引用;
(4) ”sizeof引用”得到的是所指向的变量(对象)的大小,而”sizeof指针”得到的是指针本身的大小;
(5) 从内存分配上看,程序为指针变量分配内存区域,而不为引用分配内存区域,因为引用声明时必须初始化,从而指向一个已经存在的对象。引用不能指向空值。

1. 指针传递和引用传递

指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值(变量地址值)。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值,也就是改变形参指针指向的地址,不会改变实参指针的地址,如果想通过指针参数传递来改变主调函数中,也就是实参的值,那就得使用指向指针的指针,或者指针引用。但是对形参指向的地址空间改变会影响实参指针指向的地址空间值,因为两者指向的都是同一个内存空间(相同的地址值)
而在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

// 指针方式进行交换
// 数值传递,有数值拷贝的过程
void swap1(int* x, int* y) {
    *x = *x ^ *y;
    *y = *x ^ *y;
    *x = *x ^ *y;
}

// 引用的方式进行交换
// 形参引用的实参,修改形参等价于修改实参
// x 将是a的引用, y将是b的引用
void swap2(int& x, int& y) {
    x = x ^ y;
    y = x ^ y;
    x = x ^ y;
}

int main(void) {
	//
    int a = 3;
    int b = 5;
    swap1(&a, &b);
    cout << "a=" << a << ", b=" << b << endl;
    swap2(a, b);
    cout << "a=" << a << ", b=" << b << endl;
	
}
2. 返回引用和返回指针

引用型返回值,可以将函数返回类型声明为引用型,此时函数返回的就是数据的别名,避免函数返回时的一个空间值拷贝,避免函数返回值的开销。
指针型返回值,可以将函数返回类型声明为指针型,此时函数返回的就是指向数据的指针,指针在返回时会拷贝一份指针变量存放的数据变量地址。
注意:1)可以返回全局变量、静态变量和成员变量的引用;2)可以返回引用型参数的本身;3)可以返回调用对象自身的引用;4)可以返回函数内部动态分配的堆对象的引用;4)不能返回局部变量的引用,因为局部变量空间在函数结束时,会自动释放掉;
参考链接:
[1] https://www.jianshu.com/p/9d4f5ab84d40
[2] https://blog.youkuaiyun.com/guaiderzhu1314/article/details/113099091

<think>嗯,用户想了解C++中引用指针的区别以及它们的应用场景。首先,我需要回忆一下这两者的基本概念。引用是变量的别名,而指针存储的是变量的地址。从之前的资料来看,引用必须在初始化时绑定到一个实体,之后不能更改,而指针可以重新指向其他变量。另外,引用不能为空,指针可以为NULL。 接下来,我需要整理它们的区别。根据引用[2][5],区别包括初始化要求、是否可为空、操作上的不同,比如指针可以算术运算而引用不行。还有引用的安全性更高,因为不能为空更容易出现野指针的情况。 应用场景方面,引用常用于函数参数传递,尤其是需要修改实参或者传递大对象时,提高效率。而指针适合需要动态内存分配、可选参数或者需要重新指向不同对象的情况。比如链表、树结构通常用指针,而函数参数传递用引用。 要注意用户可能混淆两者的语法使用方式,比如引用不需要解引用,而指针需要。此外,引用的返回需要注意生命周期,不能返回局部变量的引用,这点在引用[4]中提到过。 可能用户还想知道什么时候该用哪个,所以需要给出明确的场景对比。比如函数参数传递优先用引用,操作数据结构时用指针。同时,性能方面引用可能更高效,但指针更灵活。 最后,生成相关问题需要考虑用户可能的后续疑问,比如性能差异、如何选择、常见错误等。这样能帮助他们深入理解。</think>### C++ 引用指针的区别及应用场景 #### 一、核心区别 1. **初始化要求** - **引用**:必须在定义时初始化,且无法重新绑定到其他实体[^5]。例如: ```cpp int a = 10; int& ra = a; // 正确,引用必须初始化 ``` - **指针**:允许定义时不初始化,后续可修改指向(但建议初始化以避免野指针)[^4]。 2. **空值合法性** - **引用**:不能为 `NULL`,必须指向有效对象。 - **指针**:可以指向 `NULL` 或空地址,例如: ```cpp int* p = nullptr; // 合法 ``` 3. **内存操作** - **指针**:支持算术运算(如 `p++`)显式解引用(`*p`)[^3]。 - **引用**:直接操作目标变量,无解引用语法,例如: ```cpp ra = 20; // 直接修改 a 的值 ``` 4. **内存占用** - **指针**:占用独立内存空间(通常 4/8 字节)[^2]。 - **引用**:语法层面是别名,目标共享内存地址,无额外空间[^2]。 #### 二、应用场景 1. **引用的典型用途** - **函数参数传递**:避免拷贝大型对象,提升效率[^2]。 ```cpp void swap(int& a, int& b) { // 引用传参 int tmp = a; a = b; b = tmp; } ``` - **返回值优化**:返回引用可避免临时对象的复制(需确保返回值生命周期足够)[^4]。 2. **指针的典型用途** - **动态内存管理**:操作堆内存(如 `new`/`delete`)[^1]。 ```cpp int* arr = new int[100]; delete[] arr; ``` - **可选参数传递**:使用 `nullptr` 表示参数缺失。 - **数据结构实现**:如链表、树的节点连接。 ```cpp struct Node { int data; Node* next; // 指针实现链表 }; ``` #### 三、安全性对比 - **引用更安全**:因不可为空且无法重绑定,减少了野指针风险。 - **指针更灵活**:支持动态操作,但需手动管理内存,易引发内存泄漏或越界问题。 #### 四、总结表格 | **特性** | **引用** | **指针** | |------------------|-----------------------------|-----------------------------| | 初始化要求 | 必须初始化 | 允许未初始化(不建议) | | 空值合法性 | 不能为 `NULL` | 可为 `nullptr` | | 重绑定 | 不可 | 可重新指向其他地址 | | 内存操作 | 直接操作目标变量 | 需解引用(`*p`) | | 应用场景 | 函数参数、返回值优化 | 动态内存、数据结构、可选参数 | --- §§ 1. 引用作为函数返回值时需要注意哪些问题? 2. 如何避免指针导致的野指针问题? 3. 在C++中,为什么优先选择引用而非指针传递参数? 4. 指针引用在底层实现上有何异同? 5. 引用能否完全替代指针?为什么?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值