26届嵌入式组提前批C/C++考核题参考答案
一、单项选择题 共30分
单选 01|在文件作用域写下`int system_mode;` 且没有显式初始化。程序开始运行时,`system_mode` 的值是( )。 [3分]
A.0
B.随机值
C.1
D.编译错误
答案|A
解析|具有静态存储期的整型对象在没有显式初始化时会先进行零初始化,因此初值为 0。
单选 02|执行下列代码后,输出结果是( )。 [3分]
int a = 6;
int b = a;
int* p = &a;
*p = 9;
std::cout << a << " " << b;A.6 6
B.9 9
C.9 6
D.6 9
答案|C
解析|`b = a` 只复制当时的值 6;`p` 保存 `a` 的地址,`*p = 9` 修改的是 `a`,不会修改独立对象 `b`。
单选 03|执行下列代码后,输出结果是( )。 [3分]
int count = 2;
{
int count = 5;
++count;
}
std::cout << count;A.2
B.3
C.5
D.6
答案|A
解析|内层 `count` 屏蔽外层同名变量,并在离开代码块时结束生命周期;外层 `count` 始终为 2。
单选 04|执行下列代码后,`result` 的值是( )。 [3分]
int x = 7;
int result = (x % 2 == 0) ? x / 2 : x + 1;A.3
B.4
C.7
D.8
答案|D
解析|7 是奇数,条件为假,三目运算符选择 `x + 1`,结果为 8。
单选 05|执行下列代码后,输出结果是( )。 [3分]
int n = 0;
do {
n += 2;
} while (n < 0);
std::cout << n;A.0
B.2
C.无限循环
D.编译错误
答案|B
解析|`do-while` 先执行循环体再判断条件,因此循环体至少执行一次。
单选 06|执行下列代码后,输出结果是( )。 [3分]
int data[4] = {10, 20, 30, 40};
int* p = &data[1];
std::cout << *(p + 1);A.10
B.20
C.30
D.40
答案|C
解析|`p` 指向 `data[1]`,`p + 1` 指向下一个整型元素 `data[2]`,解引用得到 30。
单选 07|执行下列代码后,输出结果是( )。 [3分]
void update(int value, int* target) {
value += 2;
*target += 2;
}
int a = 3;
int b = 3;
update(a, &b);
std::cout << a << " " << b;A.3 3
B.5 3
C.3 5
D.5 5
答案|C
解析|`value` 是 `a` 的值副本;`target` 虽然也是按值复制的指针,但其中仍保存 `b` 的地址,所以可通过 `*target` 修改 `b`。
单选 08|执行下列代码后,输出结果是( )。 [3分]
struct Data { int value; };
Data d = {4};
Data* p = &d;
p->value = 10;
std::cout << d.value;A.4
B.10
C.输出地址
D.编译错误
答案|B
解析|`p` 指向结构体对象 `d`,`p->value` 访问并修改的是 `d` 内部的成员。
单选 09|关于头文件中的`extern int total;`,下列说法正确的是( )。 [3分]
A.它要求每个包含该头文件的源文件都定义一个独立的 total
B.它通常声明 total 在其他位置有且只有一个定义
C.它把 total 定义为局部变量
D.它使 total 成为常量
答案|B
解析|`extern` 声明用于让多个源文件引用同一个外部对象;真正的定义应在某一个源文件中出现一次。
单选 10|关于`union`,下列说法正确的是( )。 [3分]
A.所有成员始终拥有互不重叠的独立存储
B.所有成员共享同一块存储,写入一个成员会影响这块共享存储
C.联合体大小一定等于所有成员大小之和
D.联合体不能包含整型成员
答案|B
解析|联合体成员复用同一块存储,这是它与结构体的核心区别;其大小至少能容纳最大的成员,并可能受对齐影响。
二、判断题 共10分
判断 01|在包含正确头文件的 C++ 程序中,`printf` 和 `std::cout` 都可以用于输出。 [2分]
答案|√(正确)
解析|C++ 可调用 C 标准库输出函数,也可使用 iostream;分别包含 `<cstdio>` 和 `<iostream>` 即可。
判断 02|函数内的普通局部变量`int value;` 如果没有初始化,读取它时一定得到 0。 [2分]
答案|×(错误)
解析|普通局部自动对象不会自动零初始化;在赋值前读取其不确定值会导致未定义行为。
判断 03|指针变量本身也是一个有存储和地址的对象;它保存的值通常是另一个对象的地址或空指针值。 [2分]
答案|√(正确)
解析|应区分“指针对象自己的地址”和“指针中保存的目标地址”。
判断 04|把指针传给函数时,复制的是指针值;函数重设形参指针不会改变调用者的指针,但通过解引用仍可修改所指对象。 [2分]
答案|√(正确)
解析|这是“指针按值传递、通过地址间接修改对象”的准确描述。
判断 05|只要在头文件中写`extern int total;`,链接器就会为每个源文件各创建一个独立的 `total`。 [2分]
答案|×(错误)
解析|`extern` 只是声明;程序仍需要在一个源文件中提供唯一的定义。
编程题 1|变量赋值与数值换算 8分
任务|编写完整程序:输入两个整数 `raw` 和 `offset`。先执行 `int corrected = raw;`,再将 `offset` 加到 `corrected`;若结果小于 0 则改为 0,若大于 4095 则改为 4095。定义常量 `REF_VOLTAGE = 3.3`,按 `voltage = corrected * REF_VOLTAGE / 4095.0` 计算电压并保留两位小数。输入 `2000 100` 时输出 `raw=2000`、`corrected=2100`、`voltage=1.69V`。最后用一句话解释为什么修改 `corrected` 不会改变 `raw`。
考查点|变量、常量、赋值复制、数据类型、运算符、if/else、浮点除法
参考答案
#include <iomanip>
#include <iostream>
int main() {
const double REF_VOLTAGE = 3.3;
int raw = 0;
int offset = 0;
std::cin >> raw >> offset;
int corrected = raw;
corrected += offset;
if (corrected < 0) {
corrected = 0;
} else if (corrected > 4095) {
corrected = 4095;
}
double voltage = corrected * REF_VOLTAGE / 4095.0;
std::cout << "raw=" << raw << '\n';
std::cout << "corrected=" << corrected << '\n';
std::cout << std::fixed << std::setprecision(2)
<< "voltage=" << voltage << "V\n";
return 0;
}关键说明|`corrected = raw` 复制的是值。随后两个 `int` 对象占用各自存储,修改 `corrected` 不会反向改变 `raw`。
| 评分点 | 分值 |
|---|---|
| 变量、常量与输入初始化正确 | 2 |
| 完成赋值复制与 offset 累加 | 1 |
| 上下界处理正确 | 2 |
| 电压公式和浮点除法正确 | 2 |
| 输出格式正确并解释两个独立对象 | 1 |
编程题 2|函数编写与值传递 10分
任务|声明并定义 `void addOne(int value)`,在函数内执行 `value += 1`;再声明并定义 `int stepValue(int start, int step, int times)`,使用 `while` 循环把 `step` 累计 `times` 次并返回结果。在 `main` 中令 `int n = 10`,调用 `addOne(n)` 后输出 `n`,再输出 `stepValue(n, 3, 4)`。预期结果分别为 10 和 22,并解释第一个结果。
考查点|函数声明、定义、调用、返回值、局部变量、while、值传递
参考答案
#include <iostream>
void addOne(int value);
int stepValue(int start, int step, int times);
int main() {
int n = 10;
addOne(n);
std::cout << n << '\n';
std::cout << stepValue(n, 3, 4) << '\n';
return 0;
}
void addOne(int value) {
value += 1;
}
int stepValue(int start, int step, int times) {
int current = start;
int count = 0;
while (count < times) {
current += step;
++count;
}
return current;
}关键说明|`addOne(n)` 把 10 复制给形参 `value`;函数只把副本改成 11,所以主函数中的 `n` 仍为 10。
| 评分点 | 分值 |
|---|---|
| 两个函数的声明、定义与调用匹配 | 2 |
addOne 正确体现值传递 | 2 |
stepValue 的 while 循环和局部变量正确 | 3 |
| 返回值与输出 10、22 正确 | 2 |
| 能解释形参是调用实参的值副本 | 1 |
编程题 3|指针与结构体 14分
任务|定义 `struct Motor { int id; int speed; bool enabled; };`。实现 `bool setSpeed(Motor* motor, int newSpeed)`:空指针或速度不在 -5000~5000 时返回 `false`,否则写入速度、将 `enabled` 设为 `true` 并返回 `true`。实现 `void stopMotor(Motor* motor)`:非空时把速度设为 0、使能设为 `false`。在 `main` 中创建 `Motor m = {1, 1200, true}` 和 `Motor* p = &m`,输出 `&m` 与 `p`,依次调用 `setSpeed(p, 1500)`、`stopMotor(&m)` 并打印每步结果。说明两个地址为什么相同、函数为什么能修改原结构体。
考查点|结构体对象、取地址、指针值、空指针、`->`、通过地址修改原对象
struct Motor {
int id;
int speed;
bool enabled;
};
bool setSpeed(Motor* motor, int newSpeed);
void stopMotor(Motor* motor);参考答案
#include <iostream>
struct Motor { int id; int speed; bool enabled; };
bool setSpeed(Motor* motor, int newSpeed) {
if (motor == nullptr ||
newSpeed < -5000 || newSpeed > 5000) return false;
motor->speed = newSpeed; motor->enabled = true;
return true;
}
void stopMotor(Motor* motor) {
if (motor == nullptr) return;
motor->speed = 0; motor->enabled = false;
}
void printMotor(const Motor* motor) {
if (motor == nullptr) return;
std::cout << "id=" << motor->id << ", speed=" << motor->speed
<< ", enabled=" << motor->enabled << '\n';
}
int main() {
Motor m = {1, 1200, true};
Motor* p = &m;
std::cout << "&m=" << &m << "\np =" << p << '\n';
setSpeed(p, 1500); printMotor(&m);
stopMotor(&m); printMotor(p);
return 0;
}关键说明|`p` 中保存 `m` 的地址,所以 `p` 与 `&m` 的数值相同。函数得到这个地址值的副本后,仍能沿地址访问并修改 `m`。
| 评分点 | 分值 |
|---|---|
| 结构体定义、对象和指针初始化正确 | 2 |
setSpeed 的空指针与范围检查正确 | 3 |
使用 -> 写入原对象并返回正确状态 | 3 |
stopMotor 与打印函数正确 | 3 |
&m 与 p 一致,调用结果为 1500/true、0/false | 2 |
| 能解释指针值按值传递但仍指向同一对象 | 1 |
编程题 4|分文件编程并调用 12分
任务|建立 `counter.h`、`counter.cpp` 和 `main.cpp`。在命名空间 `counter` 中:头文件声明 `extern int total;`、`void reset();`、`void add(int value);`、`int getTotal();`;`counter.cpp` 中只定义一次 `total` 并实现三个函数;`main.cpp` 中调用 `reset()`,再依次加入 4 和 7,输出 `total=11`。写出同时编译两个 `.cpp` 文件的命令,并说明`extern` 声明与变量定义的区别。
考查点|头文件、声明与定义、extern、命名空间、跨文件调用与链接
// counter.h
namespace counter {
extern int total;
void reset();
void add(int value);
int getTotal();
}参考答案
counter.h|提供头文件保护、命名空间、extern 声明和函数声明。
#ifndef COUNTER_H
#define COUNTER_H
namespace counter {
extern int total;
void reset();
void add(int value);
int getTotal();
}
#endifcounter.cpp|包含自己的头文件,提供 total 的唯一实际定义和函数实现。
#include "counter.h"
namespace counter {
int total = 0;
void reset() {
total = 0;
}
void add(int value) {
total += value;
}
int getTotal() {
return total;
}
}main.cpp|通过头文件可见的声明调用另一个翻译单元中的实现。
#include <iostream>
#include "counter.h"
int main() {
counter::reset();
counter::add(4);
counter::add(7);
std::cout << "total=" << counter::getTotal() << '\n';
return 0;
}编译命令|`g++ -std=c++11 main.cpp counter.cpp -o app`
评分标准与检查
预期输出|`total=11`。
概念检查|`extern int total;` 是声明;`int total = 0;` 是定义并提供存储。定义只能出现一次。
| 评分点 | 分值 |
|---|---|
| 头文件保护、namespace、extern 与三个函数声明正确 | 3 |
| counter.cpp 中 total 只定义一次,三个函数实现正确 | 4 |
| main.cpp 正确包含头文件并输出 11 | 3 |
编译命令同时包含两个 .cpp 文件 | 2 |
编程题 5|混合应用:采样通道分析 16分
任务|定义 `enum State { NORMAL, ALERT };` 和结构体 `Channel`,其中包含 `id`、6 个整型样本、`minimum`、`maximum`、`average`、`state`。实现 `int sumSamples(const int* data, int length)`;实现 `void findMinMax(const int* data, int length, int* minValue, int* maxValue)`;实现 `void analyze(Channel* channel, int threshold)`,计算最小值、最大值和平均值,平均值大于等于阈值时设为 `ALERT`;实现 `void printChannel(const Channel* channel)`,使用 `switch` 输出状态。`main` 中使用样本 `{62, 68, 75, 80, 85, 90}`、阈值 75,应得到 `minimum=62`、`maximum=90`、`average=76.67`、`state=ALERT`。
考查点|枚举、结构体、数组、for、函数、指针、输出参数、if、switch、综合调试
enum State { NORMAL, ALERT };
struct Channel {
int id;
int samples[6];
int minimum;
int maximum;
double average;
State state;
};参考答案
#include <iomanip>
#include <iostream>
enum State { NORMAL, ALERT };
struct Channel {
int id;
int samples[6];
int minimum;
int maximum;
double average;
State state;
};
int sumSamples(const int* data, int length) {
int sum = 0;
for (int i = 0; i < length; ++i) {
sum += data[i];
}
return sum;
}
void findMinMax(const int* data, int length,
int* minValue, int* maxValue) {
if (data == nullptr || minValue == nullptr ||
maxValue == nullptr || length <= 0) return;
*minValue = data[0];
*maxValue = data[0];
for (int i = 1; i < length; ++i) {
if (data[i] < *minValue) *minValue = data[i];
if (data[i] > *maxValue) *maxValue = data[i];
}
}
void analyze(Channel* channel, int threshold) {
if (channel == nullptr) return;
findMinMax(channel->samples, 6,
&channel->minimum, &channel->maximum);
channel->average = sumSamples(channel->samples, 6) / 6.0;
channel->state =
(channel->average >= threshold) ? ALERT : NORMAL;
}
void printChannel(const Channel* channel) {
if (channel == nullptr) return;
std::cout << "id=" << channel->id
<< ", minimum=" << channel->minimum
<< ", maximum=" << channel->maximum
<< ", average=" << std::fixed << std::setprecision(2)
<< channel->average << ", state=";
switch (channel->state) {
case NORMAL: std::cout << "NORMAL\n"; break;
case ALERT: std::cout << "ALERT\n"; break;
}
}
int main() {
Channel channel =
{7, {62, 68, 75, 80, 85, 90}, 0, 0, 0.0, NORMAL};
analyze(&channel, 75);
printChannel(&channel);
return 0;
}关键说明|数组首地址传给求和与最值函数;最小值和最大值通过两个输出指针写回结构体成员;结构体地址传给 analyze 后,函数写回 average 与 state。
评分标准与检查
预期输出|`id=7, minimum=62, maximum=90, average=76.67, state=ALERT`。
| 评分点 | 分值 |
|---|---|
| 枚举、结构体和初始化正确 | 3 |
sumSamples 循环与边界正确 | 2 |
findMinMax 使用输出指针正确写回最值 | 4 |
analyze 计算平均值并设置状态 | 3 |
printChannel 使用 switch,主函数按地址调用 | 2 |
| 结果正确、可编译、无越界和无效解引用 | 2 |
附录|评分诊断建议
| 分数 | 结论 | 建议 |
|---|---|---|
| 0–59 | 基础未稳 | 先补变量初始化、作用域、数组、函数和指针;逐行画出“对象—地址—值”。 |
| 60–74 | 基本达标 | 可完成直接任务,需加强空指针、数组边界、extern 和分文件编译。 |
| 75–89 | 掌握较好 | 能正确选择传参方式并组织多函数程序,可继续做结构体数组与模块化练习。 |
| 90–100 | 基础扎实 | 已具备进入引用及后续内存管理学习的前置基础。 |
高频失分点
值与地址混淆|把赋值复制误认为两个变量共享存储,或把地址当成对象的数值。
未初始化|读取未初始化局部变量,或解引用未指向有效对象的指针。
传参表述不准|把“指针值按值传递、再间接修改对象”误称为引用传递。
跨文件定义错误|在头文件直接定义普通全局变量,导致多重定义;或忘记把实现源文件加入编译。
边界错误|循环写成 `i <= length`,或没有检查长度、空指针和允许范围。


