
上篇聊了union和enum有人后台说想看指针。来了。指针这个东西在C面试里出现的频率大概仅次于虚函数。特别是机器人方向你写驱动、操作内存、处理传感器数据……哪一样离得开指针但很多人学了几年C对指针的理解还是模糊的。讲个真事。去年带了三个实习生都是大三的C课本都学过。我让他们看一段传感器驱动的代码里面有指针。第一个实习生问我int* p和int *p有区别吗——没区别只是风格问题。第二个实习生问我*p是取地址还是取值——*p是取值p才是取地址。第三个实习生更猛问我指针和数组是一回事吗——不是一回事但关系很密切。三个问题三个不同的误区。但归根到底都是同一个原因没真正理解指针到底是什么。指针到底是什么别背定义理解门牌号课本上说指针是一个变量它的值是另一个变量的地址。这个定义没错但太抽象了。我用一个比喻来解释内存就像一栋大楼每个房间都有门牌号。指针就是门牌号。你有一个int a 10;这个a就是大楼里的一个房间里面住着数字10。a是房间名方便你找到它。但大楼还有个更底层的编号系统——内存地址。每个房间都有一个唯一的地址比如0x7fff5a2b。指针是什么指针就是记下了这个地址的变量。int a 10; int* p a; // p存的是a的地址a就是取a的地址p把这个地址存了下来。现在p指向a。你想通过指针找到房间里的值用*cout *p endl; // 输出10*p就是这个地址里住的数据所以*有两个身份声明的时候int* p表示p是个指针使用的时候*p表示取指针指向的值。记住这个比喻变量是房间名地址是门牌号指针是记着门牌号的纸条*是按门牌号找到房间看里面住着谁。指针为什么要有类型很多人有个疑问指针存的不就是个地址吗为什么还要分int*、float*、double*答案是类型告诉编译器这个地址后面的数据占多大空间、怎么解读。int a 10; int* ip a; float* fp (float*)a; cout *ip endl; // 输出10 cout *fp endl; // 输出一个奇怪的浮点数ip知道从a开始读4个字节按int来解读。fp也知道读4个字节但按float来解读。同样的内存不同的类型读出来的值完全不一样。在机器人开发里这个问题特别容易出在协议解析的时候。你收到一段原始数据如果类型搞错了读出来的值就是错的。传感器数据解析bug十个里有三个是类型不匹配。指针最容易翻车的三个地方面试的时候指针最爱考的就是那些坑。我总结了三个最常见的第一个坑空指针。int* p nullptr; cout *p endl; // 崩溃p存的是0nullptr这个地址不属于你的程序。你去访问它操作系统直接把你杀了。在机器人开发里空指针崩溃是最常见的bug之一。特别是传感器驱动你拿到一个指针没检查是不是空就去用程序就崩了。好习惯拿到指针先判空。void processData(SensorData* data) { if (data nullptr) { // 错误处理 return; } // 正常使用data }第二个坑野指针悬空指针。int* p new int(10); delete p; cout *p endl; // 未定义行为p指向的内存已经被释放了但p里还存着那个地址。你去访问它可能读到垃圾数据也可能程序崩溃。这种bug最恶心因为它不一定每次都崩。有时候跑得好好的上线之后才出问题。好习惯delete之后立刻把指针置为nullptr。delete p; p nullptr;第三个坑内存泄漏。void loadData() { int* data new int[10000]; // 处理数据 // 忘了delete }每次调用loadData()都分配了40KB内存但从不释放。调用一千次就泄漏了40MB。机器人程序是长时间运行的内存越用越少最后就OOM了。我见过一个真实的case。一个同事写的激光雷达驱动每帧点云都new了一块内存但忘了delete。程序跑了两个小时内存从500MB涨到了4GB最后被系统kill了。后来他改成用std::vector或者智能指针问题就消失了。指针在机器人开发里的实战用法说了这么多坑那指针在机器人开发里到底怎么用场景一动态内存分配。你不知道传感器一帧数据有多大只能运行时分配int* buffer new int[num_points]; // 读取数据 delete[] buffer;当然现在更推荐用std::vector自动管理内存。场景二函数参数传递。大的数据结构用指针传避免拷贝。这个上篇聊值传递的时候讲过了。场景三硬件寄存器映射。写嵌入式驱动的时候硬件寄存器的地址是固定的你用指针直接访问volatile uint32_t* reg (volatile uint32_t*)0x40021000; *reg 0x01; // 写寄存器volatile告诉编译器不要优化这个指针的访问因为硬件可能随时改变寄存器的值。场景四回调函数。机器人系统里经常用函数指针做回调typedef void (*Callback)(int event); void registerCallback(Callback cb);ROS2里虽然用Lambda更多了但底层还是函数指针。面试中指针的常见考法总结一下面试中关于指针最爱考这几个点基础题指针是什么指针和引用的区别*和分别是什么操作进阶题空指针和野指针的区别怎么避免内存泄漏volatile指针是什么底层题指针占多少字节64位系统上通常是8字节。不同平台的指针大小一样吗我面试的时候如果候选人能把指针的本质讲清楚——地址、类型、生命周期——我基本就认定这个人C基础过关了。给正在准备面试的你一点建议指针这个东西光看书是不够的。我的建议是打开你的IDE写几个小程序用调试器看看指针的值、看看内存地址、看看*和到底在干什么。亲眼看到内存布局比看十遍课本都管用。然后把指针的常见坑都踩一遍——空指针崩溃、野指针、内存泄漏。踩过了你才知道怎么避免。最后去看看开源的机器人代码比如ROS2的rclcpp、PCL看看人家是怎么用指针的。特别是智能指针的用法这是现代C的标准做法。还有一点特别重要面试现在基本必问智能指针。shared_ptr、unique_ptr、weak_ptr这三个东西你得搞清楚各自的使用场景。unique_ptr用于独占所有权性能最好零开销抽象shared_ptr用于共享所有权内部靠引用计数管理但要注意循环引用问题weak_ptr就是用来打破循环引用的。我面试候选人的时候经常追问一句你知道shared_ptr的引用计数是怎么实现的吗答得上来的说明真的看过源码或者深入学过加分不少。实际项目中我们团队已经基本不用裸指针了全部用智能指针替代代码审查的时候发现裸指针直接打回去重写。分享一个调试指针的小技巧在GDB里用print p可以看到指针的值也就是地址用print *p可以看到指向的数据用print p可以看到指针变量自己的地址。这三个地址分清楚了指针的三层关系就彻底明白了。很多实习生分不清这三层面试时被追问就慌了。如果这篇文章对你有帮助欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。「机器人软件开发面试·从入门到精通」连载系列上一篇第10篇 联合体与枚举——状态机设计中的常用工具 下一篇预告第12篇 指针运算与数组的关系——面试官最爱挖的底层细节有任何问题欢迎评论区留言我会尽量回复。