C++ 凭借其高性能和底层控制能力,仍然是软件开发领域的硬通货。从操作系统内核到高频交易系统,再到 3A 游戏引擎,C++ 始终占据着核心地位。这也是为什么,尽管技术栈日新月异,C++ 依然是技术面试中 toughest 但最具含金量的环节之一。
作为一名开发者,我们深知“刷题”不仅仅是背诵答案,更是为了通过代码理解底层逻辑。这篇文章,我们精心整理了 100 道 C++ 编程面试题,涵盖了从基础语法检查到复杂的算法逻辑。无论你是初入职场的新人,还是希望温故知新的资深开发者,这份清单都将帮助你梳理知识体系,从容应对面试挑战。
我们需要关注的核心考点
在深入代码之前,让我们先来看看面试官最看重哪些能力。这些问题旨在全方位考察你的技术深度:
- C++ 语法与现代特性:不仅是基础语法,还涉及现代 C++(如 C++11/14/17)的新特性。
- 数据结构与算法:这是面试的基石,考察你对内存和效率的理解。
- 面向对象编程 (OOP):封装、继承、多态在实际代码中的应用。
- 内存管理:指针、引用、智能指针的使用,以及如何避免内存泄漏。
- STL (标准模板库):熟练使用容器和算法是提高开发效率的关键。
—
第一部分:基础逻辑控制与流程
这部分考察的是对程序基本流程的掌控能力。虽然看起来简单,但写出“健壮”且“高效”的代码需要细节把控。
1. 编写一个 C++ 程序,检查数字是正数还是负数
这是一个经典的入门题,但我们可以从中看到输入处理和分支逻辑的重要性。
// C++ 程序:检查数字是正数还是负数
#include
using namespace std;
int main() {
int number;
// 这里为了演示方便直接赋值,实际场景中通常会使用 cin >> number
number = -100;
if (number >= 0) {
cout << number << " 是一个正数。" << endl;
} else {
cout << number << " 是一个负数。" << endl;
}
return 0;
}
输出:
-100 是一个负数。
💡 面试官追问: 如果 INLINECODE3201441b 是 INLINECODEf8e3b6f4 怎么办?在上述代码中,0 被归类为“非负数”。如果在严格的数学定义中,0 既不是正数也不是负数。这就引出了边界条件的处理。在实际工程中,我们必须明确业务规则,是 INLINECODE1b5d7923 才为正,还是 INLINECODEf0a03884 算非负。
2. 编写一个程序,找出三个数字中最大的一个
比较三个数字看似简单,但它是理解逻辑运算符 INLINECODEdfcd6182(与)和 INLINECODEcdaba5d0(或)的好例子。
// C++ 程序:找出三个数字中的最大值
#include
using namespace std;
int main() {
int a = 10, b = 20, c = 30;
cout <= b && a >= c) {
cout << a <= a && b >= c) {
cout << b << endl;
}
// 如果上述都不满足,那肯定就是 c 最大了
else {
cout << c << endl;
}
return 0;
}
输出:
三个数字中最大的是 : 30
💡 进阶写法: 如果我们需要比较的数字很多,写嵌套的 INLINECODEae47567e 会非常繁琐且难以维护。我们可以使用 C++ 标准库中的 INLINECODE594bfa02 函数,配合 initializerlist,代码会优雅得多:INLINECODE4f4c51b5。
3. C++ 程序:检查数字是偶数还是奇数
取模运算符 % 在这里扮演了关键角色。
// C++ 程序:检查数字是奇数还是偶数
#include
using namespace std;
// 辅助函数:如果 n 是偶数返回 true,否则返回 false
// 这种将逻辑封装成函数的做法值得推荐,提高了代码复用性
bool isEven(int n) { return (n % 2 == 0); }
int main() {
int n = 247;
if (isEven(n)) {
cout << "偶数" << endl;
} else {
cout << "奇数";
}
return 0;
}
输出:
奇数
⚠️ 性能小贴士: 虽然取模运算很直观,但在极度性能敏感的场景下(比如底层驱动),位运算 if (n & 1) 会比取模更快,因为它直接操作二进制位,避免了除法指令。了解这一点会让你在系统级编程面试中脱颖而出。
—
第二部分:字符与字符串处理
字符串处理是 C++ 面试的重灾区。C++ 风格的 INLINECODE98827a5e 与 C 风格的 INLINECODE5ca3230d 之间的区别,以及各种字符串操作函数的效率,都是考察重点。
4. 编写一个程序,查找字符的 ASCII 值
计算机内部存储的实际上是字符的整数值(ASCII 码)。理解这一点对于字符加密、网络传输等场景至关重要。
// C++ 程序:查找字符的 ASCII 值
#include
using namespace std;
int main() {
char ch = ‘A‘;
// 我们可以通过将 char 显式转换为 int 来打印其 ASCII 值
cout << "字符 " << ch << " 的 ASCII 值是: " << int(ch) << endl;
return 0;
}
输出:
字符 A 的 ASCII 值是: 65
5. 编写一个程序,检查字符是元音还是辅音
这个题目考察的是多重条件判断。注意大小写的兼容性处理。
// C++ 程序:检查字符是元音还是辅音
#include // 包含 isalpha 等工具函数
#include
using namespace std;
int main() {
char ch = ‘e‘;
// 首先判断输入是否为字母
if (isalpha(ch)) {
// 使用逻辑或 || 来判断元音,涵盖大小写
if (ch == ‘a‘ || ch == ‘e‘ || ch == ‘i‘ || ch == ‘o‘
|| ch == ‘u‘ || ch == ‘A‘ || ch == ‘E‘
|| ch == ‘I‘ || ch == ‘O‘ || ch == ‘U‘) {
cout << ch << " 是元音。" << endl;
} else {
cout << ch << " 是辅音。" << endl;
}
} else {
cout << ch << " 不是一个字母。" << endl;
}
return 0;
}
输出:
e 是元音。
🔍 代码优化思路: 如果你需要频繁检查字符类型,使用 INLINECODE7cc33c5c 或者查找表会比连续的 INLINECODE24eb59b2 判断效率更高,尤其是在处理大量文本数据时。
6. 编写一个程序,检查字符是否为字母
判断用户输入是否合法是输入处理的第一步。
// C++ 程序:检查字符是否为字母
#include
#include
using namespace std;
int main() {
char ch = ‘a‘;
// isalpha() 是标准库函数,专门用于判断是否为字母
// 它比手写 (ch >= ‘a‘ && ch <= 'z') 更加安全且支持本地化
if (isalpha(ch)) {
cout << ch << " 是一个字母。" << endl;
} else {
cout << ch << " 不是一个字母。" << endl;
}
return 0;
}
输出:
a 是一个字母。
7. 编写一个程序,在不使用 strlen() 函数的情况下查找字符串长度
这道题考察你对 C 风格字符串底层原理的理解——即以空字符 \0 结尾的特性。
// C++ 程序:不使用 strlen() 计算字符串长度
#include
#include
using namespace std;
int main() {
string str = "Hello C++";
int length = 0;
// 遍历字符串直到遇到空终止符 ‘\0‘
for (int i = 0; str[i] != ‘\0‘; i++) {
length++;
}
cout << "字符串的长度是: " << length << endl;
return 0;
}
输出:
字符串的长度是: 9
💡 深度解析: 为什么这样写?INLINECODE3b2e33a1 类内部通常会维护一个 size 变量,直接调用 INLINECODE887916cb 的时间复杂度是 O(1)。而上述通过循环查找的方式,时间复杂度是 O(N)。这道题的核心在于让你明白,C 风格字符串不存储长度,必须通过遍历计算,这也带来了潜在的性能开销和安全风险(如果没有正确的 \0 结尾)。
8. 编写一个程序,切换字符串中每个字符的大小写
这在处理数据清洗或格式化输出时非常有用。
// C++ 程序:切换字符串大小写
#include
#include
#include // 用于 islower 和 toupper
using namespace std;
int main() {
string str = "Hello World!";
for (int i = 0; str[i] != ‘\0‘; i++) {
// 如果是小写,转大写
if (islower(str[i])) {
str[i] = toupper(str[i]);
}
// 如果是大写,转小写
else if (isupper(str[i])) {
str[i] = tolower(str[i]);
}
// 其他字符(如数字、符号)保持不变
}
cout << "切换后的字符串: " << str << endl;
return 0;
}
输出:
切换后的字符串: hELLO wORLD!
🚀 常见错误提醒: 很多初学者会直接用 ASCII 码加减 32 来实现大小写转换(例如 INLINECODE064e478a)。虽然这在 ASCII 码表上是正确的,但这种代码不仅可读性差,而且在非 ASCII 字符集(如 EBCDIC)的机器上会完全失效。使用标准的 INLINECODE3a6a22dd/tolower 函数是体现专业素养的最佳实践。
—
第三部分:算法与数据结构应用
在掌握了基础语法后,面试通常会迅速转移到对算法效率的考察上。这里我们列举几个必须掌握的核心算法模式。
9. 判断一个数字是否为素数
素数判断是循环和条件优化的经典案例。素数是指大于 1 且只能被 1 和它本身整除的数。
// C++ 程序:检查一个数字是否为素数
#include
using namespace std;
bool isPrime(int n) {
if (n <= 1) return false; // 0 和 1 不是素数
// 我们只需要检查到 sqrt(n) 即可
// 因为如果 n 有因子 a,那么必然存在对应的因子 b = n / a
// 其中一个必然小于等于 sqrt(n)
for (int i = 2; i * i <= n; i++) {
if (n % i == 0)
return false;
}
return true;
}
int main() {
int n = 29;
if (isPrime(n))
cout << n << " 是素数。" << endl;
else
cout << n << " 不是素数。" << endl;
return 0;
}
输出:
29 是素数。
10. 反转数组
数组反转考察的是双指针技巧,这在很多链表和数组问题中都会用到。
// C++ 程序:反转数组
#include
#include // std::swap
using namespace std;
// 反转数组的函数
void reverseArray(int arr[], int size) {
int start = 0;
int end = size - 1;
while (start < end) {
// 交换首尾元素
swap(arr[start], arr[end]);
start++;
end--;
}
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
int n = sizeof(arr) / sizeof(arr[0]);
reverseArray(arr, n);
cout << "反转后的数组: ";
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
return 0;
}
输出:
反转后的数组: 5 4 3 2 1
—
总结:如何真正掌握 C++ 面试
通过上述题目,我们不仅仅是在学习 C++ 的语法,更是在培养一种严谨的工程思维。从边界条件的检查(如素数中的 1),到底层内存的理解(如字符串终止符),再到算法效率的优化(如 sqrt(n)),每一个细节都决定了代码的质量。
在接下来的面试准备中,建议你:
- 手写代码:不要依赖 IDE 的自动补全,在白板或纸上练习手写,这能强迫你记住语法细节。
- 关注性能:在写出能运行的代码后,多问自己一句:“还有更快的实现方式吗?”
- 使用现代 C++:尽量使用 INLINECODE2f18a0ea, INLINECODE31af9ef0, 智能指针等现代特性,而不是裸指针和 C 风格数组。
掌握这 100 道题目背后的逻辑,不仅仅是通过面试的敲门砖,更是成为一名优秀 C++ 工程师的必经之路。让我们一起,把代码写得更加漂亮、高效。