面试真题 | 华为OD C++[20260509]
非技术部分(背景、综测、HR、主管、offer)放在文首一笔带过;下文只把机考与两轮技术面写细,每道能回忆起来的题都附上可直接背诵或改写的答案。
非技术相关(一笔带过)
投华为 OD。流程大致是:机考 → 性格综测 → HR 面 → 技术一面 → 技术二面 → 主管面 → 审批与邮件 offer。综测别前后矛盾即可;HR 与主管主要是自我介绍、离职原因、加班接受度、个人情况,态度正常、不踩雷即可;offer 后按清单交材料、定入职时间。机考与技术面之间我自行拖了一阵刷题,属个人节奏,不展开。
一、机考(编程)
准备:有数据结构基础,C++ 刷题约一百道(含真题风格),注意边界与溢出。当时三道题方向大致是:空间占用计算、数列第 N 项、「勇攀数字高峰」(读清规则后多为模拟/贪心/简单 DP)。无具体题干则不给假答案;通用策略是先易后难、样例通过后自测极端数据。
二、技术一面
2.1 项目提问(略)
按简历问上位机、与硬件通信、异常处理等,无固定标准题,此处不展开。
2.2 map 与 unordered_map 的区别
问: std::map 和 std::unordered_map 有什么区别?什么时候用谁?
答:
- 底层结构:
map一般是红黑树,键有序;unordered_map是哈希表,键无序(遍历顺序不确定)。 - 时间复杂度:
map查找/插入/删除多为 O(log n);unordered_map平均 O(1),最坏在哈希冲突严重时退化(可答「接近 O(n)」,并补充好的哈希函数与reserve可缓解)。 - 内存与迭代器:
unordered_map常比map更占桶空间;unordered_map在 rehash 时可能使所有迭代器失效;map插入删除只影响被删节点及其相邻迭代器,其它迭代器相对稳定(除被删元素)。 - 键类型要求:
map需要 严格弱序(<或自定义Compare);unordered_map需要 哈希函数 和 相等比较。 - 选用:要有序遍历、范围查询、按序 lower_bound 用
map;只关心平均最快查找、不关心顺序用unordered_map。
2.3 STL 容器大致怎么分?
问: STL 里容器怎么分类?举几个例子。
答:
- 序列容器:元素线性排列,如
vector、deque、list、forward_list、array。 - 关联容器:基于比较的树结构,键有序,如
set、multiset、map、multimap。 - 无序关联容器:哈希,如
unordered_set、unordered_multiset、unordered_map、unordered_multimap。 - 容器适配器:封装别的容器接口,如
stack、queue、priority_queue(底层多为deque或vector+heap)。
2.4 虚函数与纯虚函数
问: 虚函数、纯虚函数是什么?抽象类呢?
答:
- 虚函数:成员函数前加
virtual,派生类可 override;通过基类指针/引用调用时,在运行时按对象实际类型解析(动态绑定),依赖 vtable + vptr。 - 纯虚函数:
virtual void foo() = 0;,无实现(可内联定义在类外,但接口上仍表示「必须被覆盖」);含纯虚函数的类叫抽象类,不能实例化,用于定义接口契约。 - 析构函数:多态基类析构应声明为
virtual,否则delete基类指针指向派生对象时可能只调基类析构,派生资源泄漏。
2.5 手撕:LeetCode 567 — 字符串的排列
问: 判断 s2 中是否存在 s1 的某个排列(子串是排列)。
思路: s1 长度 m,在 s2 上维护长为 m 的滑动窗口,窗口内各字符出现次数与 s1 完全一致即成立。用长度 26(或 128)的 cnt 数组做差分:先统计 s1,再在滑窗中维护「还需匹配数」或「与 s1 的差向量」,匹配数为 0 即 true。
边界: m > n 直接 false。
参考代码(C++):
bool checkInclusion(const std::string& s1, const std::string& s2) {
if (s1.size() > s2.size()) return false;
int need[26] = {};
for (char c : s1) need[c - 'a']++;
int win[26] = {};
int m = (int)s1.size();
for (int i = 0; i < m; ++i) win[s2[i] - 'a']++;
auto same = [&]() {
for (int i = 0; i < 26; ++i)
if (need[i] != win[i]) return false;
return true;
};
if (same()) return true;
for (int i = m; i < (int)s2.size(); ++i) {
win[s2[i - m] - 'a']--;
win[s2[i] - 'a']++;
if (same()) return true;
}
return false;
}
面试里可优化 same():用变量记录「当前窗口与 need 不同的字符种数」或「多余/缺少计数」,每次滑窗 O(1) 更新,整体 O(n);上面写法便于先写对再优化。
三、技术二面
3.1 static 关键字的作用
答(分场景说):
- 函数内静态局部变量:只初始化一次,生命周期贯穿整个程序,下次进函数保留上次的值;存储在静态/全局数据区,不是栈上每次新建。
- 函数外 / 命名空间内静态全局变量:C 里表示内部链接,仅本翻译单元可见;C++ 中文件作用域变量更推荐 匿名 namespace 实现同样效果。
- 类内 static 成员变量:所有对象共享一份,必须在类外定义(除
inline静态成员 C++17)。类内 static 成员函数:无this,只能访问静态成员/其它静态函数,常用于单例、工厂或纯工具函数。
3.2 数组和指针的区别
答:
- 类型:
int a[10]类型是「含 10 个 int 的数组」;int* p是指向 int 的指针。 sizeof:sizeof(a)是整个数组字节数(如 40);sizeof(p)是指针本身大小(32/64 位下 4 或 8)。数组名在多数表达式里会退化为指向首元素的指针,但sizeof(数组名)、&数组名、用char(&)[N]绑引用等场景不退化。&与步进:&a类型为指向整个数组的指针,与&a[0]地址数值常相同但类型不同;a+1与&a+1地址偏移不同(后者跳过整个数组)。- 可修改性:数组名不可被赋值改指向;指针变量可改指向。
3.3 静态局部变量、全局变量、局部变量的区别
答:
| 维度 | 普通局部变量 | 静态局部变量 | 全局变量 |
|---|---|---|---|
| 作用域 | 块/函数内 | 块/函数内 | 文件级(或 extern) |
| 生命周期 | 进入块创建,退出销毁 | 程序全程 | 程序全程 |
| 默认初值 | 未定义(栈) | 0 初始化 | 0 初始化(BSS) |
| 存储区 | 通常栈 | 静态数据区 | 静态数据区 |
多线程下:静态局部变量在 C++11 起函数内静态初始化线程安全(magic static);普通全局/静态对象的动态初始化顺序在翻译单元间不确定,要小心。
3.4 局部变量都有哪些?举例
答: 最常见的是自动存储期的局部变量(函数内、块内 int x),进栈帧创建,出栈销毁。可举例:循环变量、临时对象、lambda 按值捕获副本(在 lambda 体作用域内也算局部相关)。C++ 里还可提 register 已是废弃 hint,实际编译器自行分配寄存器。线程里 thread_local 变量在线程内像「全局」但每个线程一份,也可顺带一提(若面试官接受扩展)。
3.5 堆和栈的区别
答:
- 分配方式:栈由编译器自动生成/回收(栈帧);堆由
malloc/new分配,free/delete或智能指针管理。 - 速度:栈分配 O(1) 移动栈指针即可;堆分配涉及空,更慢,可能产生碎片。
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
【C/C++面试必考必会】专栏,直击面试核心,精选C/C++及相关技术栈中面试官最爱的必考点!从基础语法到高级特性,从内存管理到多线程编程,再到算法与数据结构深度剖析,一网打尽。助你快速构建知识体系,轻松应对技术挑战。希望专栏能让你在面试中脱颖而出,成为技术岗的抢手人才。

查看11道真题和解析