拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

第 8 章 · 指针与引用

第 8 章 · 指针与引用

这是 C++ 最核心、也最让新手头疼的一章。但别怕,我们用"门牌号"的类比,一步步讲到彻底理解。掌握它,你就跨过了 C++ 最大的门槛。

8.1 内存地址:数据的"门牌号"

第 3 章说过,内存像一个大储物柜,每个格子有地址(门牌号)。

intx=42;

这句做了两件事:找一个空格子,把 42 放进去。这个格子的门牌号(地址)就是&x能取到的值。

取地址运算符&可以得到变量的地址:

intx=42;std::cout<<&x<<std::endl;// 打印 x 的地址,形如 0x7ffd3a2b...

地址是一串十六进制数,指向内存中的某个位置。

8.2 指针:专门存地址的变量

指针(pointer)就是一个存地址的变量。

intx=42;int*p=&x;// p 是"指向 int 的指针",存的是 x 的地址

拆解int* p = &x;:

  • int*:类型,表示"指向 int 的指针"
  • p:变量名
  • &x:取出 x 的地址

现在p里存着 x 的门牌号。指针就是门牌号的副本。

解引用*:通过门牌号找到房间

有了门牌号,怎么进去看/改房间里的东西?用解引用运算符*:

intx=42;int*p=&x;std::cout<<*p<<std::endl;// 42,*p 就是"p 指向的那个值"*p=100;// 通过指针修改 xstd::cout<<x<<std::endl;// 100,x 被改了

*p读作"p 指向的内容"。通过*p,可以读写 x,就像直接操作 x 一样。

&和*是一对反操作:

  • &x:拿到 x 的地址(问"x 住哪")
  • *p:拿到地址 p 指向的值(问"这个门牌号住的是谁")

一张图记住

变量 x ── 存着 42 变量 p ── 存着 x 的地址 ──→ 指向 x *p === x 的值(42)

8.3 为什么需要指针

你可能想问:直接用变量不就行了,为什么要绕一圈用指针?原因有几个:

  1. 在函数里修改外部的值(见 8.5)
  2. 避免复制大数据:把一个巨大的数组/矩阵传给函数时,传地址比复制整个数据快得多
  3. 动态分配内存(第 11 章)
  4. 实现复杂数据结构(链表、树等)

这些场景,后面都会遇到。现在先掌握指针的基本操作。

8.4 空指针 nullptr

指针如果不指向任何东西,应该给它赋nullptr(空指针),表示"不指向任何地方":

int*p=nullptr;// 空指针

访问空指针是严重错误(程序崩溃)。所以解引用前要检查:

if(p!=nullptr){std::cout<<*p<<std::endl;// 安全}

8.5 指针与函数:真正修改外部变量

第 6 章说值传递改不了外部变量。用指针就能改:

#include<iostream>voidaddOne(int*p){*p=*p+1;// 通过指针,修改 p 指向的那个变量}intmain(){intx=5;addOne(&x);// 传入 x 的地址std::cout<<x;// 6,x 被真正修改了}

8.6 引用:更优雅的"别名"

指针好用但*、&写起来繁琐易错。C++ 提供了引用(reference)——给变量起别名:

intx=42;int&r=x;// r 是 x 的引用(别名),r 和 x 是同一个东西r=100;std::cout<<x;// 100,通过 r 改 x

引用和指针的区别:

指针引用
语法int* p = &x;用*p访问int& r = x;直接用r
能否为空可以为nullptr不能为空,必须绑定一个变量
能否改指向能指向别的变量一旦绑定,终身不改
可读性繁琐更简洁

引用的本质:就是变量的另一个名字,操作r就是操作x。

8.7 引用参数:函数里改外部变量(推荐写法)

用引用传参,函数里就能改外部变量,而且语法干净:

#include<iostream>voidswap(int&a,int&b){// 引用参数inttmp=a;a=b;b=tmp;}intmain(){intx=1,y=2;swap(x,y);std::cout<<x<<" "<<y;// 2 1,交换成功}

8.8 常量引用:只读 + 高效

传大对象时,既想"不复制"(高效),又不想让函数修改它,就用常量引用:

voidprint(conststd::string&s){// const + &// s 可以读,但不能改std::cout<<s<<std::endl;}

const std::string&读作:“一个字符串的只读引用”。这是 C++ 里极其常见的写法,Eigen 里到处都是(如const MatrixXd&),务必熟悉。

记忆口诀:看到const X&,就理解为"传了个地址进去,但保证不改它,既快又安全"。

8.9 指针的指针、指针与数组(了解)

指针可以指向指针(多级指针),数组名其实是指向首元素的指针:

inta[3]={10,20,30};int*p=a;// 数组名 a 就是首元素地址std::cout<<*p;// 10std::cout<<p[1];// 20,指针也能用下标

这些是底层细节,初学了解即可,后面用std::vector会更省心。

8.10 小结

  • 指针int* p存地址;&x取地址,*p解引用。
  • 指针能改外部变量、避免复制、动态分配内存。
  • 引用int& r是别名,不能为空、不能改绑。
  • 常量引用const T&:只读 + 高效,Eigen 里极常用。
  • 空指针nullptr,解引用前先判空。

下一章,学习结构体与类——把相关的数据打包成一个整体。


练习题

  1. 声明int x = 10; int* p = &x;,通过*p把 x 改成 20,打印验证。
  2. 写函数increment(int& n)用引用参数让外部变量加 1。
  3. 写函数print(const std::string& s)打印字符串,体会常量引用。
  4. 用指针写swap,交换两个 int 的值。
  5. 说说引用和指针的三点区别。
返回列表