行业资讯
📅 2026/8/1 5:13:31
一文看懂:信息学奥赛中的指针和引用
适用对象有一定 C 基础正在备赛 CSP-J/S 或 NOIP 的学生。一句话先记住指针存地址引用是别名。竞赛里引用天天用指针偶尔见。一、先搞懂内存地址变量存在内存里每个变量都有自己的“门牌号”——地址。inta10;couta;// 输出 a 的地址比如 0x7ffee3f9a8dca就是取 a 的地址。二、指针Pointer指针就是一个存地址的变量。inta10;int*pa;// p 存着 a 的地址核心操作代码含义int *p定义一个指针变量p a让 p 指向 a*p取 p 指向的那个变量解引用*p 20通过指针修改 a 的值inta10;int*pa;*p20;// a 变成 20intb30;pb;// p 改为指向 b指针可以换指向*p40;// b 变成 40指针能换指向这是它和引用最大的不同。三、引用Reference引用就是给变量起个外号、别名。inta10;intra;// r 是 a 的别名核心操作代码含义int r ar 是 a 的引用必须初始化r 20就是a 20r取 a 的地址r 没有自己的地址inta10;intra;r20;// a 变成 20intb30;// 引用不能换绑r b 只是把 b 的值赋给 a四、指针 vs 引用核心区别对比维度指针引用本质存地址的变量变量的别名必须初始化否可以先定义后赋值是必须绑定到一个变量能否为空可以nullptr不能能否改变指向能可以指向别的变量不能一生绑定一个如何访问值需要*解引用直接使用像普通变量内存占用占用内存存地址不占额外内存本质是别名安全性容易出错空指针、野指针安全不容易出错竞赛中用哪个用于底层实现用于日常编码传参、遍历五、-运算符是什么-是竞赛中天天要用的运算符它的本质是p-member 等价于(*p).member就是“取出指针指向的那个东西然后访问它的成员”。.和-的区别左边是什么用什么示例普通对象.Node u; u.val 10;指针-Node *p; p-val 10;引用.Node r u; r.val 10;structNode{intval;Node*left,*right;};Node u;Node*pu;Noderu;u.val10;// 对象 → 用 .p-val20;// 指针 → 用 -r.val30;// 引用 → 用 .跟对象一样六、竞赛实战场景场景一函数传参避免拷贝最常用voiddfs(Node*u){if(unullptr)return;coutu-val;dfs(u-left);dfs(u-right);}场景二范围遍历修改for(intx:vec){x*2;// 直接改原数组不拷贝}场景三手写二叉树/链表structNode{intval;Node*next;// 指向下一个节点};voidprint(Node*head){for(Node*phead;p!nullptr;pp-next){coutp-val ;}}场景四链式前向星数组模拟指针structEdge{intto,w,next;// next 就是“指针”存的是下一条边的下标}edges[N];inthead[N];voidadd(intu,intv,intw){edges[cnt]{v,w,head[u]};head[u]cnt;// 把新的边的下标存进去}// 遍历用 . 访问因为下标不是指针for(intihead[u];i!-1;iedges[i].next){// 处理 edges[i]}场景五Node *—— 指针的引用voidinsert(Node*u,intx){if(unullptr){unewNode{x,nullptr,nullptr};return;}if(xu-val)insert(u-left,x);elseinsert(u-right,x);}Node*rootnullptr;insert(root,10);// root 本身被修改了从 nullptr 变成指向新节点为什么用Node *而不是Node *// 如果写成 Node *u传指针的值voidinsert(Node*u,intx){unewNode{x,nullptr,nullptr};// 修改的是指针的副本}// 外面的 root 还是 nullptr改不了// 要用引用传递指针本身voidinsert(Node*u,intx){// u 是 root 的别名unewNode{x,nullptr,nullptr};// 直接修改 root}一句话想修改指针本身指向什么就得传指针的引用。七、常见陷阱错误正确做法int *p; *p 10;没初始化就用定义时赋值int *p a;Node *p nullptr; cout p-val;空指针解引用用前检查if (p ! nullptr)Node *p; cout p-val;野指针初始化Node *p new Node;int r;引用没初始化必须初始化int r a;八、记牢这张图指针和引用 │ ┌───────────────┴───────────────┐ │ │ 指针 引用 │ │ 存地址的变量 变量的别名 可以重新指向 不能换绑 可以为空 必须初始化 用 * 解引用 直接用 用 - 访问成员 用 . 访问成员九、对竞赛来说够用的标准必须掌握理解即可暂时不用管引用作函数参数指针的基本概念二级指针int **p范围遍历用修改指针和引用的区别函数指针理解*和含义nullptrnew/delete-访问结构体成员Node *的用法复杂指针运算十、一句话总结指针是“存地址的变量”引用是“变量的别名”。引用安全、直观、高效竞赛里天天用。指针灵活但容易犯错主要用于底层实现和高级数据结构。掌握引用的用法理解指针的概念够了。十一、检查你是否掌握了inta5,b10;int*pa;intrb;*p20;// a ?r30;// b ?couta bendl;// 输出什么答案a 20b 30附录你可能还疑惑的Q1为什么引用的本质是“别名”因为引用不占额外内存它和原变量共用同一块内存地址。对引用做任何操作都直接反映在原变量上。Q2int *和int *哪个对int *是对的指针的引用。int *是错的引用的指针不存在。Q3竞赛里指针和引用哪个重要引用重要得多。函数传参、STL 容器操作都离不开引用。指针主要用于手写链表、二叉树、平衡树等数据结构的底层实现。