第 2.1 节

26届嵌入式组提前批C/C++考核题参考答案

作者
李骏远的头像李骏远
协作者
董佳辉的头像董佳辉
发布于 2025/02/07更新于 2026/07/29

一、单项选择题 共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/false2
能解释指针值按值传递但仍指向同一对象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();
}

#endif

counter.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 正确包含头文件并输出 113
编译命令同时包含两个 .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`,或没有检查长度、空指针和允许范围。