值传递vs引用传递:这道题我面了十次,每次都有人翻车

📅2026/7/11 16:05:12 👁️次浏览
值传递vs引用传递:这道题我面了十次,每次都有人翻车
上周帮朋友面试来了个硕士应届生985的简历上项目经验挺丰富什么SLAM、路径规划都做过看着挺有底气的。我想先热热身问了个自认为很简单的问题你写一个函数交换两个整数的值怎么写他刷刷刷写完了笔都没停void swap(int a, int b) { int temp a; a b; b temp; }我问他这样写对吗他很自信地说对啊教科书上就是这么写的。我说你调用一下试试。他写了一个测试int x 1, y 2; swap(x, y); cout x y endl;输出是1 2。没交换。他愣住了。讲真这种问题我见过太多次了。不是不会写而是没真正理解值传递和引用传递的区别。教科书上写的swap函数用的是指针不是值传递。值传递复印一份给你值传递说白了就是把参数的副本传给函数。你在栈上开辟一块新空间把原变量的值原封不动地复制过去。函数里怎么折腾这个副本原变量都不受影响。打个比方你有一本书值传递就是我去复印店复印了一本给你。你在上面画花、做笔记我的书还是干干净净的。void modify(int x) { x 100; } int a 10; modify(a); // a还是10这种传递方式安全因为不会意外修改原变量。但有个问题如果参数是个大的数据结构比如一个包含100万个点的点云值传递就要拷贝100万个点性能开销很大。我见过一个实习生写的代码处理激光雷达数据函数参数是值传递的点云对象。每次调用函数都要拷贝一次点云。结果程序跑得特别慢从30fps掉到了8fps。后来改成引用传递帧率立刻恢复了。所以在机器人开发里对于大的数据结构值传递要慎用。引用传递给你起个别名引用传递是C特有的语法相当于给原变量起了个别名。函数里修改引用就是在修改原变量。底层怎么实现的编译器在底层其实是用指针来做的引用就是指针的语法糖。但这个语法糖让代码好读太多了。你不用写*和直接用变量名就行。void modify(int x) { x 100; } int a 10; modify(a); // a现在是100这种传递方式高效因为没有拷贝。但要注意函数内部可能会修改原变量所以要小心。在机器人开发里引用传递用得特别多。比如你要处理一个大的点云数据不想拷贝就用引用传递void processPointCloud(PointCloud cloud) { // 直接修改原数据 }但如果你不想让函数修改原数据就加个constvoid processPointCloud(const PointCloud cloud) { // 只读不能修改 }这样既高效又安全。面试的时候如果你能主动提到const引用面试官会觉得你有工程经验。真的。指针传递 vs 引用传递有什么区别指针传递和引用传递效果类似都能修改原变量。但语法上不一样。指针传递void modify(int* x) { *x 100; } int a 10; modify(a); // 传地址引用传递void modify(int x) { x 100; } int a 10; modify(a); // 直接传变量看起来引用传递更简洁不需要取地址符也不需要用*解引用。但在底层引用传递其实是用指针实现的。编译器帮你做了那些繁琐的语法。面试的时候面试官可能会问引用传递和指针传递有什么区别答案是语法上引用更简洁语义上引用必须绑定到一个有效的变量不能为空而指针可以是nullptr使用上引用一旦绑定就不能改变指向指针可以随便指。在机器人开发里我更喜欢用引用传递因为代码更清晰。但有些场景必须用指针比如参数可能为空的时候。void processSensor(Sensor* sensor) { if (sensor ! nullptr) { // 处理传感器数据 } }这种时候指针就比引用更合适。返回值也是值传递很多人忽略了函数的返回值也是值传递。如果返回的是大数据结构拷贝开销很大。怎么办一种方法是用引用参数代替返回值void getPointCloud(PointCloud cloud) { // 直接填充传入的cloud避免拷贝 }另一种方法是用移动语义C11后面有机会再聊。const引用的威力——只读又高效const引用是C中最实用的参数传递方式没有之一。它结合了值传递的安全性不会修改原变量和引用传递的高效性没有拷贝。void calculateDistance(const Point3D a, const Point3D b) { double dx a.x - b.x; double dy a.y - b.y; double dz a.z - b.z; // a和b都不能被修改编译器会报错 // a.x 0; // 编译错误 }在机器人开发中const引用几乎是标配。你去看PCL、ROS2的源码大数据结构的参数基本都是const引用。面试时候被问为什么不用值传递加const你可以说值传递的const只保护函数内部的副本原变量本来就不会被修改。const引用的const保护的是原变量——这才是有意义的。还有一个容易忽略的点const引用可以绑定到临时对象上而普通引用不行。void print(const std::string s) { cout s endl; } print(hello); // OKconst引用可以绑定到字符串字面量临时对象 void modify(std::string s) { s modified; } // modify(hello); // 编译错误普通引用不能绑定到临时对象这个特性在实际开发中非常有用。比如你的函数需要一个默认参数用const引用就能直接传字面量。面试中的陷阱题面试的时候有些题目特别容易踩坑。比如这个void getString(std::string s) { s modified; } std::string str original; getString(str); cout str endl;输出是什么答案是original。因为参数是值传递函数里修改的是副本。但很多人会想当然地认为是modified。还有这个void modify(std::string s) { s modified; } std::string str original; modify(str); cout str endl;这次输出是modified因为参数是引用传递。这种题目考的就是你对值传递和引用传递的理解。面试的时候一定要看清楚参数是值传递还是引用传递。给正在准备面试的你一点建议值传递和引用传递真的是C最基础的特性之一。但基础的东西往往最容易出错。我面试的时候看候选人写函数第一眼就看参数是怎么传的。如果是大的数据结构用值传递我心里就会打个问号——这个人有没有性能优化的意识怎么提高我的建议是把值传递、引用传递、指针传递的区别搞清楚知道什么时候用哪个。然后去看看开源的机器人代码比如PCL、ROS2看看人家是怎么传参数的。你会发现大的数据结构基本都是const引用只有小的、便宜拷贝的类型才用值传递。最重要的是养成好习惯。大的数据结构用const引用需要修改的时候用引用或指针小的基本类型用值传递。这些习惯一旦养成代码质量和性能都会有提升。对了还有个实用的小技巧写函数的时候先想清楚这个参数需不需要在函数内部修改修改的话调用者需不需要感知到想清楚这两个问题你就知道该用哪种传递方式了。如果这篇文章对你有帮助欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。「机器人软件开发面试·从入门到精通」连载系列上一篇第6篇 函数定义与调用——代码复用的起点 下一篇预告第8篇 递归函数——运动学求解中的常见思路有任何问题欢迎评论区留言我会尽量回复。