C/C++ 常见笔试题与陷阱详解

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

原因分析

  1. (int&)a 实际上并不是类型转换,而是创建了一个 匿名的 int 类型引用,并且和 a(float 类型变量)绑定。
  2. 由于引用是 int&,所以编译器会把 a 在内存中的存储形式按 整数的方式解释
  3. 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;

问:调用了几次构造函数?

分析

  1. A a; —— 创建了对象 a,调用一次 默认构造函数
  2. A b(3); —— 创建了对象 b,调用一次 带参数的构造函数
  3. 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);

结果:ab 的值没有交换。

问题所在

原因是 p1p2 是局部变量,它们只是指针的副本。交换的是副本的值,并不会影响 ab

正确写法

方法一:交换指针所指向的值。

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++ 笔试题:

  1. 区分 (int&)a(int)a 的差别,理解浮点数存储原理。
  2. 理清构造函数调用次数与对象、指针的关系。
  3. 掌握左值函数的写法,理解引用返回值的重要性。
  4. 记住 cout 对字符型指针做了特殊重载。
  5. 避免交换函数中指针副本的问题。
  6. 理解数组与引用的合法写法。

这些知识点不仅能帮你应对笔试,还能让你在写实际代码时少踩坑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tt555555555555

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值