全部模拟卷

《C++ 程序设计》期末模拟卷 C(偏概念与陷阱版)

满分:100 分 | 建议用时:120 分钟。题型与分值:一、单项选择题 18 题 × 1 分 = 18 分;二、读程序写输出 7 题 × 5 分 = 35 分;三、程序填空题 4 题(共 17 空)= 17 分;四、编程题 3 题 × 10 分 = 30 分。本卷为「偏概念与陷阱版」,强化单选与程序填空,密集覆盖招牌易错点(switch 穿透、static 跨调用记忆性、构造/析构调用次序与次数、对象切片、深拷贝 operator= 自赋值、运算符重载与友元、动态内存数据结构)。
1.

已知 int x = 7, y = 2;,则表达式 x / y * 2.0 + x % y 的值是:

A

7.0

B

6.0

C

7

D

8.0

2.

unsigned char c = 250;,执行 c += 10; 后,c 的值为:

A

260

B

4

C

255

D

编译错误

3.

下列关于 '\0''0'"0"NULL 的说法中,正确的是:

A

'\0''0' 是同一个字符

B

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

C

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

D

NULL 与字符 '0' 等价

4.

阅读如下代码段:

int n = 5;
switch (n / 2) {
    case 1: cout << "A";
    case 2: cout << "B"; break;
    case 3: cout << "C";
    default: cout << "D";
}

输出为:

A

AB

B

B

C

CD

D

BD

5.

关于函数重载,下列说法正确的是:

A

函数名相同、仅返回类型不同即可构成重载

B

函数名相同、参数表(个数或类型)不同可构成重载

C

重载函数必须定义在同一个类中

D

默认参数会破坏函数重载,因此二者不能同时使用

6.

int a[5] = {10, 20, 30, 40, 50}; int *p = a;,则 *(p + 3) - *p 的值是:

A

30

B

3

C

40

D

地址差(与机器相关)

7.

关于 const 与指针,下列声明中不能通过指针修改其所指对象的是:

A

int * const p = &a;

B

const int *p = &a;

C

int *p = &a;

D

以上三者都可以通过指针修改

8.

执行语句 AB a(2), b[3], *p[4];AB 仅有一个带参构造函数),共调用构造函数的次数是:

A

8

B

5

C

4

D

3

9.

下列运算符中,只能重载为成员函数、不能重载为友元(全局)函数的是:

A

+

B

==

C

=

D

<<

10.

关于静态数据成员(static 数据成员),下列说法错误的是:

A

它被该类的所有对象共享

B

它必须在类外单独定义并分配空间

C

静态成员函数中可以直接访问非静态数据成员

D

static const int 成员可在类内初始化

11.

已知类 D 是类 B 的公有派生类,D *pd, d; B *pb, b;,下列赋值中不合法(不符合赋值兼容规则)的是:

A

pb = pd;

B

pb = &d;

C

pd = pb;

D

b = d;

12.

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

A

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

B

构造函数可以声明为虚函数

C

基类析构函数声明为 virtual 可避免 delete 基类指针时派生部分内存泄漏

D

纯虚函数所在的类仍可被直接实例化

13.

下列关于深拷贝与浅拷贝的说法,错误的是:

A

含指针成员的类若只用编译器合成的拷贝构造,可能导致同一块内存被重复 delete

B

operator= 实现深拷贝时应先判断自赋值,再释放旧空间

C

浅拷贝会让两个对象的指针成员指向同一块堆内存

D

只要类中含有指针成员,编译器就会自动为其生成深拷贝

14.

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

A

catch(int) 能捕获 throw 3.5; 抛出的 double 异常(自动类型提升)

B

异常匹配是按声明顺序逐个进行的精确类型匹配,不做隐式算术转换

C

一旦 throw,当前已构造的局部对象不会被析构

D

catch(...) 必须放在所有 catch 块的最前面

15.

关于流操纵符,已知 cout << setw(6) << setfill('*') << 12 << 34 << endl;,输出为:

A

****1234

B

****12****34

C

****1234**

D

12****34

16.

关于文件流,下列说法错误的是:

A

ifstream in("data.txt"); 后可用 if (!in) 判断打开是否失败

B

while (in >> x) 在读到文件尾或读取失败时结束循环

C

ofstream 默认方式打开一个已存在的文件,会清空原有内容

D

ifstream 默认以 ate 模式打开,读指针位于文件尾

17.

设有 char s[] = {'1', '2', '3', '\0', '4', '5'};,执行 cout << s; 的输出是:

A

123

B

12345

C

123 45

D

12345 后跟乱码

18.

关于组合(成员对象)类的构造与析构次序,下列说法正确的是:

A

成员对象按初始化列表中书写的先后顺序构造

B

成员对象按其在类中声明的顺序构造,按相反顺序析构

C

先执行本类构造函数体,再构造成员对象

D

析构次序与构造次序相同

19.

(switch 穿透 + 整数除法)

#include <iostream>
using namespace std;
int main() {
    for (int m = 1; m <= 5; m++) {
        int n;
        switch (m % 3) {
            case 0: n = 10;
            case 1: n = 20; break;
            case 2: n = 30;
            default: n = 40;
        }
        cout << n << " ";
    }
    cout << endl;
    return 0;
}
20.

(static 局部变量跨调用 + 引用/值传参)

#include <iostream>
using namespace std;
void calc(int a, int &b) {
    static int s = 1;
    s += a;
    a = a + b;
    b = s + a;
}
int main() {
    int x = 2, y = 3;
    calc(x, y);
    cout << x << " " << y << endl;
    calc(x + 1, y);
    cout << x << " " << y << endl;
    return 0;
}
21.

(构造/拷贝构造/析构调用次序与次数 + 局部 static 对象)

#include <iostream>
using namespace std;
class Item {
    char id;
public:
    Item(char c) : id(c) { cout << "ctor " << id << endl; }
    Item(const Item &o) : id(o.id) { cout << "copy " << id << endl; }
    ~Item() { cout << "dtor " << id << endl; }
};
void use() {
    static Item a('a');
    Item b('b');
}
int main() {
    Item *p = new Item('p');
    use();
    delete p;
    use();
    cout << "end main" << endl;
    return 0;
}
22.

(虚函数多态 vs 对象切片)

#include <iostream>
using namespace std;
class Base {
public:
    virtual void who() { cout << "Base "; }
    void tag()         { cout << "B-tag "; }
};
class Derived : public Base {
public:
    void who() { cout << "Derived "; }
    void tag() { cout << "D-tag "; }
};
int main() {
    Derived d;
    Base *pb = &d;
    Base ob = d;          // 对象赋值,发生切片
    pb->who(); pb->tag();
    ob.who(); ob.tag();
    cout << endl;
    return 0;
}
23.

(运算符重载:前置/后置 ++ 与友元 <<)

#include <iostream>
using namespace std;
class Counter {
    int v;
public:
    Counter(int x = 0) : v(x) {}
    Counter& operator++()      { v += 2; return *this; }   // 前置
    Counter  operator++(int)   { Counter t = *this; v += 2; return t; } // 后置
    friend ostream& operator<<(ostream &os, const Counter &c) {
        os << c.v; return os;
    }
};
int main() {
    Counter c(5);
    cout << c++ << " " << c << " ";
    cout << ++c << " " << c << endl;
    return 0;
}
24.

(指针与数组 / 字符指针偏移)

#include <iostream>
using namespace std;
int main() {
    const char *words[] = {"apple", "banana", "cherry"};
    cout << words[1] + 2 << endl;
    cout << *(words[0] + 1) << endl;
    cout << words[2][3] << endl;
    return 0;
}
25.

(异常处理:精确类型匹配 + 抛出时对象析构)

#include <iostream>
using namespace std;
class Guard {
    int id;
public:
    Guard(int i) : id(i) { cout << "in " << id << " "; }
    ~Guard() { cout << "out " << id << " "; }
};
void run(int code) {
    Guard g(1);
    if (code == 0) throw 100;     // int
    else           throw 2.5;     // double
}
int main() {
    try {
        run(1);
    } catch (int e) {
        cout << "catch int " << e << " ";
    } catch (double e) {
        cout << "catch double " << e << " ";
    }
    cout << endl;
    return 0;
}
26.

(含指针成员的 MyString 类——深拷贝三件套,5 空)

要求:MyString 自管理一段 C 风格字符串,下面补全带参构造、拷贝构造、赋值运算符,使其满足三法则(深拷贝、防自赋值、无内存泄漏)。

#include <cstring>
class MyString {
    char *str;
public:
    MyString(const char *s) {
        str = new char[__①__];
        strcpy(str, s);
    }
    MyString(const MyString &o) {
        str = new char[strlen(o.str) + 1];
        __②__;
    }
    MyString& operator=(const MyString &o) {
        if (__③__) return *this;   // 防自赋值
        __④__;                     // 释放旧空间
        str = new char[strlen(o.str) + 1];
        strcpy(str, o.str);
        return __⑤__;
    }
    ~MyString() { delete[] str; }
};
27.

(二分查找补全,4 空)

要求:在升序整型数组 a 中查找 target,找到返回下标,否则返回 -1

int binarySearch(int *a, int len, int target) {
    int left = 0, right = len - 1, mid;
    while (__①__) {
        mid = left + (right - left) / 2;
        if (a[mid] == target) return __②__;
        else if (a[mid] > target) __③__;
        else __④__;
    }
    return -1;
}
28.

(文件读取与统计行数,4 空)

要求:打开文本文件 fname,逐个读取以空白分隔的单词并输出,统计单词个数;打开失败时输出 open error

#include <fstream>
#include <iostream>
using namespace std;
void readWords(const char *fname) {
    __①__ fin(fname);
    char word[64];
    int cnt = 0;
    if (__②__) { cout << "open error"; return; }
    while (__③__) {
        cout << word << endl;
        cnt++;
    }
    cout << "total = " << cnt << endl;
    __④__;
}
29.

(const 数据成员 + 递归求和,4 空)

要求:Boxconst int cap(容量),必须用初始化列表初始化;sumTo递归1+2+...+n

class Box {
    const int cap;
public:
    Box(int c) __①__ {}   // 用初始化列表初始化 cap
    int capacity() const { return cap; }
};

int sumTo(int n) {
    if (__②__) return 0;          // 递归出口
    return __③__ + __④__;         // 当前项 + 递归调用
}
30.

(运算符重载 + 友元:Money 金额类,第 10 章)

设计一个金额类 Money,以「元」yuan 和「分」fen(0–99)两个整型成员表示。要求:

  1. 提供构造函数(可设默认值),并在构造时把 fen ≥ 100 的部分进位到 yuan
  2. 重载成员运算符 operator+,实现两个 Money 相加(分满 100 进位为元);
  3. 重载友元 operator<<,按 X.YY 元 格式输出(分不足两位补前导 0,如 12.05 元);
  4. 提供友元函数 Money average(const Money &a, const Money &b),返回两金额的平均值(向下取整到分)。

main 中构造两个 Money,输出它们的和与平均值。

31.

(递归:删除字符串中的指定字符,第 6 章)

编写函数 void delChar(char str[], char c);,删除 C 风格字符串 str 中出现的所有字符 c,要求用递归实现,不得使用循环(库函数 strlen 等可用,但删除逻辑必须递归)。删除后字符串仍以 '\0' 结尾。

例如 str = "banana", c = 'a' 处理后 str 变为 "bnn"。在 main 中读入一行字符串与一个字符,调用并输出结果。

32.

(动态内存数据结构 + 三法则:有序整型数组类 SortedArray,第 7 / 10 章)

设计一个动态有序整型数组类 SortedArray,内部用 int *data 指向堆内存,size 表示当前元素个数,cap 表示容量。要求:

  1. 构造函数申请初始容量的堆空间;析构函数释放;
  2. void insert(int x):将 x 按升序插入到正确位置(保持有序,不是简单尾插);容量不足时倍增扩容;
  3. 实现拷贝构造函数赋值运算符 operator=,均为深拷贝,operator= 须防自赋值;
  4. int operator[](int k) const:返回第 k 小的元素(即下标 k 处元素)。

main 中乱序插入若干整数,按从小到大输出,演示拷贝/赋值后两对象互不影响。