C/C++ 常见笔试题与陷阱详解
在嵌入式开发和 C/C++ 岗位面试中,经常会遇到一些看似简单,但实际考察很深的笔试题。这些题目不仅涉及基础语法,还深入考察了指针、引用、内存存储方式等底层知识。本文结合几个典型案例,带你逐步分析并解决这些问题。
浮点数与匿名引用
来看第一道题:
#include <iostream>
using namespace std;
int main() {
float a = 1.0;
cout << (int&)a << endl;
return 0;
}
很多人第一眼会以为 (int&)a
是 强制类型转换,即把 float
转换为 int
,那么结果应该输出 1
。但实际上,运行结果却是一个很大的整数:
1065353216
原因分析
(int&)a
实际上并不是类型转换,而是创建了一个 匿名的 int 类型引用,并且和a
(float 类型变量)绑定。- 由于引用是
int&
,所以编译器会把a
在内存中的存储形式按 整数的方式解释。 float
在内存中是按照 IEEE 754 标准存储的,比如1.0f
的二进制存储形式对应的整数就是1065353216
。
所以结果并不是 1
,而是 1.0f
在内存中的整数表示。
对比强制类型转换
如果我们改成强制类型转换:
cout << (int)a << endl;
输出结果就是:
1
所以请务必区分:
(int&)a
:引用绑定,直接按整型解读内存。(int)a
:强制类型转换,得到的是值的转换结果。
构造函数调用次数
题目:假设有如下语句:
A a;
A b(3);
A* p;
问:调用了几次构造函数?
分析
A a;
—— 创建了对象a
,调用一次 默认构造函数。A b(3);
—— 创建了对象b
,调用一次 带参数的构造函数。A* p;
—— 创建了一个指针变量p
,并没有创建对象,所以 不会调用构造函数。
所以总共调用 2 次。
如果写成:
A* p = new A();
此时会真正创建对象,因此还会额外调用一次构造函数。
左值函数与右值函数
平时我们写的函数大多数是右值函数,比如:
int maxValue(int a, int b) {
return (a > b) ? a : b;
}
调用时:
int x = 10, y = 20;
int w = maxValue(x, y); // w = 20
这里 maxValue
的结果只能放在赋值运算符的 右侧。
左值函数
如果我们希望函数的返回值能够放在赋值号左侧,例如:
maxValue(x, y) = 100;
就必须让函数返回 引用。
改写如下:
int& maxValue(int& a, int& b) {
return (a > b) ? a : b;
}
int main() {
int x = 10, y = 20;
maxValue(x, y) += 10; // 修改较大的那个数
cout << "x=" << x << ", y=" << y << endl;
return 0;
}
运行结果:
x=10, y=30
这就是 左值函数 的典型用法。
指针输出字符串还是地址?
来看这个例子:
#include <iostream>
using namespace std;
int main() {
const char* ptr = "Hello World";
cout << ptr << endl;
int a = 10;
int* p = &a;
cout << p << endl;
return 0;
}
运行结果:
Hello World
0x7ffee4d2a8
为什么?
- 当
cout
遇到 字符型指针 时,C++ 标准库重载了<<
运算符,会把它当作字符串处理,输出内容而不是地址。 - 当
cout
遇到其他指针类型(如int*
),则会直接输出指针存储的地址。
如果我们想输出 const char*
的真实地址,可以这样写:
cout << (void*)ptr << endl;
指针交换函数中的陷阱
题目:写一个交换函数,代码如下:
void swap(int* p1, int* p2) {
int* temp;
temp = p1;
p1 = p2;
p2 = temp;
}
调用:
int a = 10, b = 20;
swap(&a, &b);
结果:a
和 b
的值没有交换。
问题所在
原因是 p1
和 p2
是局部变量,它们只是指针的副本。交换的是副本的值,并不会影响 a
和 b
。
正确写法
方法一:交换指针所指向的值。
void swap(int* p1, int* p2) {
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
方法二:用引用简化写法。
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
数组与引用
错误写法
int& arr[3]; // ❌ 编译错误
为什么?因为 不存在“引用的数组”,引用只是别名,本身不是对象,数组元素必须是对象。
正确写法:数组的引用
int nums[3] = {1, 2, 3};
int (&arr)[3] = nums; // arr 是 nums 的引用
此时 arr
就是 nums
的别名,操作 arr
等价于操作 nums
。
总结
本文整理了几个典型的 C/C++ 笔试题:
- 区分
(int&)a
与(int)a
的差别,理解浮点数存储原理。 - 理清构造函数调用次数与对象、指针的关系。
- 掌握左值函数的写法,理解引用返回值的重要性。
- 记住
cout
对字符型指针做了特殊重载。 - 避免交换函数中指针副本的问题。
- 理解数组与引用的合法写法。
这些知识点不仅能帮你应对笔试,还能让你在写实际代码时少踩坑。