当前位置: 首页 > news >正文

【C/C++】C++引用和指针的对比


🔥个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、C/C++干货分享&学习过程记录

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平



前言:本专栏记录了博主C++从初阶到高阶完整的学习历程,会发布一些博主学习的感悟、碰到的问题、重要的知识点,和大家一起探索C++这门程序语言的奥秘。这个专栏将记录博主C++语法、高阶数据结构、STL的学习过程,正所谓“万丈高楼平地起”嘛,我们话不多说,继续进行C++阶段的学习。本文我们不讲C++主线的内容,我们来拓展一下或者说整理一下我们学习时C/C++时经常会提到的一些专有名词,例如形参、实参,显式类型转换和隐式类型转换类型转换,内置类型等等。


 C++的两个参考文档:

老朋友(非官方文档):cplusplus

官方文档(同步更新):cppreference


目录

正文

一、引用的基本概念

1、定义与声明

2、引用与指针的区别

二、引用的主要用途

1、函数参数传递

2、函数返回值

三、const引用

1、常量引用

2、函数参数中的const引用

四、引用与右值引用(C++11)

1、左值引用 vs 右值引用

2、移动语义

五、引用折叠规则(C++11)

六、特殊引用情况

1、引用数组

2、指向指针的引用

七、引用使用的最佳实践

八、常见错误

1、 返回局部变量引用

2、未初始化的引用

 3、引用NULL

九、详解C++引用

引用基础

1、基本引用示例

2、引用与指针对比

(二)函数中的引用

1、引用参数示例

2、返回引用示例

(三)const引用

1、const引用基础

2、const引用参数

(四)右值引用(C++11)

1、基本右值引用

2、移动语义示例

(五)高级引用用法

1、引用数组

2、指向指针的引用

(六)综合应用示例

1、链式调用

2、引用作为类成员

结尾


正文

博主之前写过C++引用相关的内容,只不过那是在C++初识部分介绍的,比较简略:

【C/C++】初识C++(二):深入详解缺省参数(默认参数)函数重载、引用(重头戏)

【C/C++】初识C++(三):C++入门内容收尾——const引用,指针和引用关系梳理,inline(内联函数),nullptr替代NULL

引用是C++中一种重要的特性,它提供了对变量的别名机制,使得我们可以用不同的名称访问同一块内存空间。下面全面介绍C++引用的核心知识点。

一、引用的基本概念

1、定义与声明

int num = 10;
int &ref = num;  // ref是num的引用
  • 引用必须在声明时初始化

  • 引用一旦绑定到一个变量,就不能再绑定到其他变量

  • 引用不是对象,不占用额外存储空间(编译器实现可能不同)

2、引用与指针的区别

特性引用指针
初始化要求必须初始化可以不初始化
可修改性不能重新绑定可以指向不同对象
空值不能为空可以为NULL/nullptr
操作方式直接使用需要解引用(*)
内存占用通常不占额外空间占用指针大小的空间

二、引用的主要用途

1、函数参数传递

void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}
  • 避免拷贝大对象的开销

  • 允许函数修改实参的值

  • 比指针更安全(不能为null)

2、函数返回值

int &getMax(int &a, int &b) {return a > b ? a : b;
}int main() {int x = 5, y = 10;getMax(x, y) = 20;  // 修改了y的值
}
  • 可以返回引用实现左值调用

  • 不能返回局部变量的引用(会导致悬空引用)

三、const引用

1、常量引用

const int &ref = 42;  // 合法:常量引用可以绑定到字面量

2、函数参数中的const引用

void print(const std::string &str) {// 不能通过str修改原对象std::cout << str;
}
  • 避免不必要的拷贝

  • 保证函数内不会修改参数

  • 可以接受临时对象和字面量

四、引用与右值引用(C++11)

1、左值引用 vs 右值引用

int a = 10;
int &lref = a;       // 左值引用
int &&rref = 20;     // 右值引用

2、移动语义

class MyString {
public:// 移动构造函数MyString(MyString &&other) noexcept {data = other.data;other.data = nullptr;}
};

五、引用折叠规则(C++11)

template<typename T>
void func(T&& param) {  // 万能引用// 根据传入参数决定引用类型
}int a = 10;
func(a);   // T&
func(10);  // T&&

六、特殊引用情况

1、引用数组
int arr[5] = {1, 2, 3, 4, 5};
int (&refArr)[5] = arr;  // 数组的引用
2、指向指针的引用
int *ptr = nullptr;
int *&refPtr = ptr;  // 指向指针的引用

七、引用使用的最佳实践

  1. 函数参数优先使用const引用传递大对象

  2. 需要修改参数时使用普通引用

  3. 避免返回局部变量的引用

  4. 明确区分左值引用和右值引用

  5. 谨慎使用引用作为类成员(可能引入生命周期问题)

八、常见错误

1、 返回局部变量引用

int &badFunc() {int local = 10;return local;  // 错误!
}

2、未初始化的引用

int &ref;  // 错误:必须初始化

 3、引用NULL

int &ref = NULL;  // 错误

引用是C++强大而独特的特性,正确使用引用可以写出更高效、更安全的代码,但同时需要注意其特性和限制以避免潜在问题。

九、详解C++引用

引用基础

1、基本引用示例
#include <iostream>
using namespace std;int main() {int original = 42;int &ref = original;  // 引用声明和初始化cout << "original: " << original << endl;  // 42cout << "ref: " << ref << endl;            // 42ref = 100;  // 通过引用修改值cout << "after change:" << endl;cout << "original: " << original << endl;  // 100cout << "ref: " << ref << endl;            // 100// 验证它们共享同一地址cout << "Address of original: " << &original << endl;cout << "Address of ref: " << &ref << endl;  // 相同地址
}
2、引用与指针对比
void compareRefAndPointer() {int x = 10;// 引用方式int &ref = x;ref = 20;  // 直接使用// 指针方式int *ptr = &x;*ptr = 30;  // 需要解引用cout << "x after ref change: " << x << endl;cout << "x after ptr change: " << x << endl;// 尝试重新绑定int y = 50;// ref = y;  // 错误!不能重新绑定引用ptr = &y;    // 指针可以重新指向
}

(二)函数中的引用

1、引用参数示例
// 交换两个变量的值
void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}void testSwap() {int x = 10, y = 20;cout << "Before swap: x=" << x << ", y=" << y << endl;swap(x, y);cout << "After swap: x=" << x << ", y=" << y << endl;
}
2、返回引用示例
// 返回数组元素的引用
int &getElement(int arr[], int index) {return arr[index];
}void testReturnRef() {int numbers[] = {10, 20, 30, 40, 50};// 获取引用并修改getElement(numbers, 2) = 100;cout << "Modified array: ";for (int num : numbers) {cout << num << " ";}cout << endl;// 错误示例:返回局部变量引用/*int &badRef() {int local = 42;return local;  // 警告:返回局部变量引用}*/
}

(三)const引用

1、const引用基础
void constRefDemo() {int a = 10;const int &ref1 = a;  // 合法// ref1 = 20;        // 错误:不能通过const引用修改const int b = 20;const int &ref2 = b;  // 合法// 绑定到临时对象const int &ref3 = 30;  // 合法cout << "ref3: " << ref3 << endl;
}
2、const引用参数
void printLargeObject(const string &str) {cout << str << endl;// str[0] = 'A';  // 错误:不能修改
}void testConstRefParam() {string longStr(1000, 'x');  // 大字符串printLargeObject(longStr);   // 避免拷贝// 可以接受临时对象printLargeObject("Temporary string");
}

(四)右值引用(C++11)

1、基本右值引用
void rvalueRefDemo() {int &&rref1 = 10;  // 右值引用int x = 10;// int &&rref2 = x;  // 错误:不能绑定左值rref1 = 20;  // 可以修改cout << "rref1: " << rref1 << endl;
}
2、移动语义示例
class StringWrapper {char *data;
public:// 构造函数explicit StringWrapper(const char *str = "") {data = new char[strlen(str) + 1];strcpy(data, str);}// 移动构造函数StringWrapper(StringWrapper &&other) noexcept {data = other.data;other.data = nullptr;}// 移动赋值运算符StringWrapper &operator=(StringWrapper &&other) noexcept {if (this != &other) {delete[] data;data = other.data;other.data = nullptr;}return *this;}~StringWrapper() {delete[] data;}void print() const {cout << (data ? data : "null") << endl;}
};void testMoveSemantics() {StringWrapper sw1("Hello");StringWrapper sw2 = std::move(sw1);  // 使用移动构造函数cout << "After move:" << endl;cout << "sw1: ";sw1.print();  // 输出 nullcout << "sw2: ";sw2.print();  // 输出 Hello
}

(五)高级引用用法

1、引用数组
void refArrayDemo() {int arr[3] = {1, 2, 3};int (&refArr)[3] = arr;  // 数组的引用refArr[1] = 20;  // 修改原数组cout << "Original array: ";for (int n : arr) {cout << n << " ";}cout << endl;
}
2、指向指针的引用
void pointerRefDemo() {int x = 10;int *ptr = &x;int *&refPtr = ptr;  // 指向指针的引用*refPtr = 20;  // 修改x的值cout << "x: " << x << endl;int y = 30;refPtr = &y;    // 修改指针指向*refPtr = 40;cout << "y: " << y << endl;
}

(六)综合应用示例

1、链式调用
class Counter {int count;
public:Counter() : count(0) {}Counter &increment() {++count;return *this;}Counter &decrement() {--count;return *this;}int get() const { return count; }
};void testChaining() {Counter c;c.increment().increment().decrement();cout << "Count: " << c.get() << endl;  // 输出 1
}
2、引用作为类成员
class Logger {ostream &out;
public:explicit Logger(ostream &os = cout) : out(os) {}void log(const string &msg) {out << msg << endl;}
};void testLogger() {Logger consoleLogger;consoleLogger.log("This goes to console");ofstream file("log.txt");Logger fileLogger(file);fileLogger.log("This goes to file");
}

博主展示的这些代码示例,涵盖了C++引用的各种用法,从基础到高级特性。通过实际运行这些代码,可以更深入地理解引用的工作原理和应用场景。


结尾

往期回顾:

【C/C++】形参、实参相关内容整理

【C/C++】Dev-C++的安装与使用以及快捷键整理

【日常问题解决方案】VS2022不小心解决方案资源管理器把关掉了怎么办

VS2022进行监视功能的步骤

结语:本文内容到这里就全部结束了。本文我们重新整理了C++引用和指针相关的内容。

http://www.dtcms.com/a/318771.html

相关文章:

  • 29-数据仓库与Apache Hive-创建库、创建表
  • 树莓派安装OpenCV环境
  • 【CDA案例】数据分析案例拆解:解锁数据分析全流程!
  • 微服务、服务网格、Nacos架构与原理
  • mapbox进阶,mapbox-gl-draw绘图插件扩展,绘制新增、编辑模式支持点、线、面的捕捉
  • Linux系统编程--权限管理
  • 在NVIDIA Orin上用TensorRT对YOLO12进行多路加速并行推理时内存泄漏(下)
  • Redis为什么要引入多线程?
  • 如何在GPU上安装使用Docker
  • 【AI】——SpringAI通过Ollama本地部署的Deepseek模型实现一个对话机器人(二)
  • 用 tcpdump 捕获网络数据包
  • RTSP播放器技术详解:功能支持、平台覆盖与快速集成指南
  • PostgreSQL 强制索引:当重复数据让优化器“失明”时的解决方案
  • centos系统sglang单节点本地部署大模型
  • Sklearn 机器学习 数据降维PCA 自己实现PCA降维算法
  • 如何打造一支AI时代下的IT团队,为企业战略目标快速赋能
  • Java面试宝典:JVM的垃圾收集算法
  • MCU中的晶振(Crystal Oscillator)
  • 【Zephyr】02_从零教你开发芯片级ADC驱动(HAL层篇)
  • 每日五个pyecharts可视化图表-bars(6)
  • 嵌入式硬件中MOSFET基本原理与实现
  • 基于 Socket.IO 实现 WebRTC 音视频通话与实时聊天系统(Spring Boot 后端实现)
  • C语言中级_动态内存分配、指针和常量、各种指针类型、指针和数组、函数指针
  • MATLAB科研数据可视化
  • cuda编程笔记(13)--使用CUB库实现基本功能
  • 嵌入式硬件中MOSFET基本控制详解
  • 嵌入式硬件学习(十一)—— platform驱动框架
  • OpenAI 开源模型 GPT-OSS深度拆解:从1170亿参数到单卡部署,重构AI开源生态
  • 亚马逊采购风控突围:构建深度隐匿的环境安全体系
  • 360纳米AI、实在Agent、CrewAI与AutoGen……浅析多智能体协作系统