全部模拟卷

《C++ 程序设计》期末模拟卷 A(均衡·标准考点版)

满分 100 分 建议用时 120 分钟。题型与分值:一、单项选择题 18 题 × 1 分,共 18 分;二、读程序写输出 7 题 × 5 分,共 35 分;三、程序填空 约 15 空,共 17 分;四、编程大题 3 题 × 10 分,共 30 分。本卷为均衡·标准考点版,覆盖第 2–14 章四种题型与各难度,最贴近真实期末形态。参考答案与解析见文末(前端默认折叠,自测后再展开)。
1.

下列关于 '\0''0'"0"0 的说法正确的是?

A

'0''\0' 的内码值相同

B

"0" 在内存中占 1 个字节

C

'\0' 是字符串结束标记,其 ASCII 值为 0

D

NULL'\0' 是完全等价的写法

2.

int a = 7, b = 2;,下列表达式结果为 double 类型且值为 3.5 的是?

A

a / b

B

a / b * 1.0

C

(double)(a / b)

D

(double)a / b

3.

执行以下语句后,输出的是?

int x = 0;
switch (x) {
    case 0: x += 1;
    case 1: x += 2; break;
    case 2: x += 4;
    default: x += 8;
}
cout << x;
A

1

B

3

C

11

D

7

4.

关于 for (int k = 0; k < 3; ++k); 这条语句,下列说法正确的是?

A

这是语法错误

B

行末的分号使循环体为空语句,循环结束后 k 为 3

C

循环将无限执行

D

循环体只执行一次

5.

下列哪个运算符不能重载为友元(全局)函数?

A

+

B

==

C

=

D

<<

6.

已知 DB 的公有派生类,定义 D *pd, d; B *pb, b;,下列赋值不符合赋值兼容规则的是?

A

pb = pd;

B

pb = &d;

C

pd = pb;

D

b = d;

7.

关于 const 与指针,设 int m = 1, n = 2;,下列说法正确的是?

A

const int *p = &m; 之后可以执行 *p = 5;

B

int * const p = &m; 之后可以执行 p = &n;

C

int * const p = &m; 之后可以执行 *p = 5;

D

const int *p = &m; 定义时可以不初始化

8.

执行 AB a(2), b[3], *p[4];AB 含一个带 int 参数的构造函数),共调用构造函数几次?

A

8

B

5

C

4

D

3

9.

关于 static 局部变量,下列说法错误的是?

A

未显式初始化时自动初始化为 0

B

函数调用结束后仍然存在,下次调用保留上次的值

C

其作用域仍局限于定义它的函数内

D

每次进入函数都会重新初始化一次

10.

char *city[] = {"sea", "moon", "glass", "river"};,则 cout << city[2] + 1; 的输出是?

A

lass

B

glass

C

l

D

'l'

11.

关于类的静态数据成员,下列说法正确的是?

A

静态数据成员被该类的所有对象共享

B

静态数据成员只能在构造函数初始化列表中初始化

C

每个对象都拥有独立的一份静态数据成员

D

静态数据成员不需要在类外单独定义即可使用

12.

关于常量成员函数(const 成员函数),下列说法正确的是?

A

常量对象既能调用常量成员函数,也能调用普通成员函数

B

常量成员函数内可以修改本对象的非静态数据成员

C

常量对象只能调用常量成员函数

D

普通对象不能调用常量成员函数

13.

关于虚函数与多态,下列说法正确的是?

A

通过对象(非指针/引用)调用虚函数也能实现动态绑定

B

只有通过基类的指针或引用调用 virtual 函数时才发生动态绑定

C

析构函数不允许声明为 virtual

D

纯虚函数所在的类可以被实例化为对象

14.

关于异常处理 throw / try / catch,下列说法正确的是?

A

catch 的匹配会进行隐式类型提升,throw 3(int)可被 catch(double) 捕获

B

一个 try 块只能跟随一个 catch 子句

C

catch(...) 可以捕获任意类型的异常

D

throw 抛出异常后,当前作用域中已构造的局部对象不会被析构

15.

关于类模板,下列说法错误的是?

A

类模板必须先实例化为具体类型后才能定义对象

B

template <class T> 中的 T 是类型参数

C

同一个类模板用不同类型实例化得到的是同一个类

D

类模板的成员函数本身也是函数模板

16.

关于派生类的构造与析构顺序,下列正确的是?

A

构造顺序为:派生类 → 对象成员 → 基类

B

构造顺序为:基类 → 对象成员 → 派生类,析构顺序与之相反

C

析构函数会被继承到派生类中

D

派生类不需要负责从基类继承来的数据成员的初始化

17.

关于文件输入流 ifstream,下列用法正确的是?

A

ifstream fin("data.txt"); 后用 if (fin) 判断打开是否成功

B

文件流对象使用完毕后无需关闭

C

ifstream 默认以 out 模式打开

D

while (fin >> x) 在读到文件中第一个数据后立即终止

18.

int a[5] = {0}; int *p = a;,关于指针算术,下列说法正确的是?

A

p + 2(char*)p + 2 指向同一地址

B

p + 2 相对 p 在地址上前进了 2 个字节

C

*(p + 2) 等价于 a[2]

D

数组名 a 可以被重新赋值为另一个数组的地址

19.

(构造/拷贝构造/析构调用追踪)写出下列程序的完整输出。

#include <iostream>
using namespace std;

class Box {
    int id;
public:
    Box(int i) : id(i) { cout << "ctor " << id << endl; }
    Box(const Box &b) : id(b.id) { cout << "copy " << id << endl; }
    ~Box() { cout << "dtor " << id << endl; }
};

Box make(int n) {
    Box t(n);
    return t;
}

int main() {
    Box a(1);
    Box b = make(2);
    cout << "---" << endl;
    return 0;
}

提示:现代编译器可能因返回值优化省略拷贝;本题按未启用 NRVO、严格按语义作答,return t; 触发一次拷贝构造、t 随后析构。

20.

(switch 穿透)写出下列程序的输出。

#include <iostream>
using namespace std;

int main() {
    for (int m = 0; m <= 4; ++m) {
        int n;
        switch (m) {
            case 0:
            case 2: n = 10; break;
            case 1: n = 20;
            case 3: n = 30; break;
            default: n = 40;
        }
        cout << n << " ";
    }
    return 0;
}
21.

(static 局部变量 + 引用 vs 值传参)写出下列程序两行输出。

#include <iostream>
using namespace std;

void g(int x, int &y) {
    static int s = 1;
    s += x;
    x = x + s;
    y = y + s;
}

int main() {
    int a = 3, b = 5;
    g(a, b);
    cout << a << " " << b << endl;
    g(a + 1, b);
    cout << a << " " << b << endl;
    return 0;
}
22.

(虚函数多态 vs 对象切片)写出下列程序的输出。

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void say() { cout << "Animal" << endl; }
};

class Cat : public Animal {
public:
    void say() { cout << "Cat" << endl; }
};

int main() {
    Cat c;
    Animal *p = &c;
    Animal &r = c;
    Animal o = c;        // 对象切片
    p->say();
    r.say();
    o.say();
    return 0;
}
23.

(流操纵符作用范围)写出下列程序的输出。

#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int n = 255;
    cout << setfill('-') << setw(8) << "A" << n << endl;
    cout << hex << n << endl;
    cout << n << endl;
    return 0;
}

提示:setw 只对其后第一次输出有效,setfill 与进制设置持续生效。

24.

(递归)写出下列程序的输出。

#include <iostream>
using namespace std;

void f(int n) {
    if (n == 0) return;
    cout << n % 2;
    f(n / 2);
}

int main() {
    f(13);
    cout << endl;
    return 0;
}
25.

(运算符重载 + 类型转换)写出下列程序的输出。

#include <iostream>
using namespace std;

class Frac {
    int a, b;
public:
    Frac(int x = 0, int y = 1) : a(x), b(y) {}
    Frac operator+(const Frac &r) const {
        return Frac(a * r.b + r.a * b, b * r.b);
    }
    operator double() const { return double(a) / b; }
    friend ostream& operator<<(ostream &os, const Frac &f) {
        os << f.a << "/" << f.b;
        return os;
    }
};

int main() {
    Frac x(1, 2), y(1, 3);
    Frac z = x + y;
    cout << z << endl;
    cout << z + 1.0 << endl;
    return 0;
}
26.

(String 类深拷贝三件套,第 10 章,5 分)下面是一个自管理 char* 的字符串类,补全 3 处使其满足"三法则"(深拷贝赋值含自赋值判断)。

#include <cstring>
class MyStr {
    char *str;
public:
    MyStr(const char *s) {
        str = new char[strlen(s) + 1];
        strcpy(str, s);
    }
    MyStr& operator=(const MyStr &s) {
        if (______(1)______) return *this;   // 自赋值判断
        ______(2)______;                     // 释放原有空间
        str = new char[strlen(s.str) + 1];
        strcpy(str, s.str);
        return ______(3)______;
    }
    ~MyStr() { delete[] str; }
};
27.

(二分查找补全,第 7 章,4 分)数组 a 升序排列,补全二分查找。

int bsearch(int *a, int len, int target) {
    int left = 0, right = len - 1, mid;
    while (______(4)______) {
        mid = left + (right - left) / 2;
        if (a[mid] == target) return mid;
        else if (______(5)______) ______(6)______;
        else left = mid + 1;
    }
    return -1;
}
28.

(文件流读取,第 14 章,4 分)从文本文件逐个读入整数并求和。

#include <fstream>
#include <iostream>
using namespace std;

int sumFile(const char *fname) {
    ______(7)______ fin(fname);   // 定义输入文件流
    if (______(8)______) {        // 判断打开失败
        cout << "open error";
        return -1;
    }
    int x, sum = 0;
    while (______(9)______) sum += x;   // 逐个读入
    ______(10)______;             // 关闭文件
    return sum;
}
29.

(const 数据成员 + static 成员 + 引用传参,第 10 章,4 分)补全使总重量统计正确。

class Goods {
    const int weight;
    static int totalWeight;
public:
    Goods(int w) : ______(11)______ { totalWeight += weight; }
    ~Goods() { totalWeight -= weight; }
    static int total() { return totalWeight; }
};

______(12)______;   // 在类外定义并初始化静态成员

void show(______(13)______ g) {   // 以引用传参,避免拷贝/析构改变 totalWeight
    cout << Goods::total() << endl;
}
30.

(递归,第 6 章,10 分) 编写函数 void squeeze(char str[], char c),用递归实现:删除以 '\0' 结尾的字符串 str所有等于 c 的字符,结果仍存回 str(原地修改)。不得使用循环语句(for/while/do),不得使用 <cstring> 之外的库容器。例如 str = "banana"c = 'a',调用后 str 变为 "bnn"

要求:

  • 递归边界正确(空串);
  • 命中字符时正确地把后续字符整体前移一位再继续递归;
  • 给出可直接编译运行的 main 测试一例。
31.

(运算符重载 + 友元的完整类设计,第 10 章,10 分) 设计一个商品类 Goods,含数据成员:名称 namestring)、单价 pricedouble)、数量 countint)。要求实现:

  1. 合适的构造函数;
  2. 成员运算符 operator+:将两个商品的总额price * count)相加,返回一个新的 Goods(名称取 "sum"count 置 1、price 为两者总额之和);
  3. 友元 operator<<:按 name price count 格式输出;
  4. 友元函数 double avgPrice(const Goods &x, const Goods &y):返回两商品单价的平均值。

给出完整类定义与各函数实现(可附简单 main)。

32.

(抽象类 + 多态层次,第 12 章,10 分) 从抽象基类 Shape 出发设计图形继承层次:

  • Shape 含纯虚函数 virtual double area() const = 0; 和虚函数 virtual void print() const;(打印面积);
  • 派生 Circle(半径 r,面积 PI * r * r)与 Rectangle(宽 w、高 h,面积 w * h);
  • PI 作为类内共享常量(用 static const double 或等价方式);
  • main 中用基类指针数组存放若干 Circle/Rectangle 对象,遍历多态调用 print(),并正确释放内存(注意基类析构函数应为虚)。

给出完整定义与 main