C++测试题答案与讲解
一、填空题答案及讲解
- 答案:const
- 讲解:在 C++ 中,const关键字用于定义常量,一旦定义,其值不能被修改。例如const int num = 10;,这里的num就是一个常量。
- 答案:3
- 讲解:数组的下标从 0 开始,a[5] = {1, 2, 3, 4, 5};中,a[0]的值为 1,a[1]的值为 2,以此类推,a[2]的值就是 3。
- 答案:内存地址
- 讲解:指针变量用于存储其他变量的内存地址。通过指针,程序可以间接访问和操作存储在该地址的数据。例如int num = 5; int *p = #,这里的p就是一个指针,存储了num变量的地址。
- 答案:常量表达式
- 讲解:在switch语句中,每个case后面必须跟一个常量表达式。常量表达式在编译时就能确定其值,这样switch语句才能根据表达式的值准确地跳转到对应的case分支。例如switch (day) { case 1: // 处理周一的情况; break; case 2: // 处理周二的情况; break; },这里的 1 和 2 就是常量表达式。
- 答案:先执行循环体,再判断条件
- 讲解:while循环是先判断条件表达式,若条件为真则执行循环体;而do - while循环是先执行一次循环体,然后再判断条件表达式,若条件为真则继续执行循环体,否则退出循环。例如int i = 0; do { cout << i << " "; i++; } while (i < 3);,会先输出 0,然后再判断i < 3是否成立,继续循环。
- 答案:enum
- 讲解:enum关键字用于定义枚举类型,它是一种用户自定义的数据类型,用于将一组相关的常量组织在一起。例如enum Color { RED, GREEN, BLUE };,这里定义了一个Color枚举类型,其中RED、GREEN、BLUE是枚举常量,默认情况下,RED的值为 0,GREEN的值为 1,BLUE的值为 2。
- 答案:float、double
- 讲解:float(单精度浮点数)和double(双精度浮点数)用于表示带有小数部分的数值。float通常占用 4 个字节,double通常占用 8 个字节,double的精度更高,能表示更精确的小数。例如float f = 3.14f; double d = 3.141592653589793;。
- 答案:delete[] p;
- 讲解:当使用new运算符动态分配数组内存时,需要使用delete[]来释放该内存,以避免内存泄漏。这里int *p = new int[10];分配了一个包含 10 个int类型元素的数组内存,delete[] p;则释放了这块内存。如果使用delete p;(少了[]),则只会释放p指向的第一个元素的内存,而其他元素的内存将无法释放,导致内存泄漏。
- 答案:逻辑与、逻辑或
- 讲解:&&是逻辑与运算符,只有当左右两边的表达式都为真时,整个表达式才为真。例如(3 > 2) && (5 < 10),因为3 > 2为真,5 < 10也为真,所以整个表达式为真。||是逻辑或运算符,只要左右两边的表达式有一个为真,整个表达式就为真。例如(3 > 2) || (5 > 10),因为3 > 2为真,所以整个表达式为真。
- 答案:O(n^2)
- 讲解:冒泡排序是一种简单的排序算法。它通过多次比较相邻元素并交换位置,将最大(或最小)的元素逐步 “冒泡” 到数组的末尾。在最坏情况下,即初始数组是逆序的,需要进行n(n - 1)/2次比较和交换操作,时间复杂度为O(n^2)。例如对于一个长度为n的数组,第一轮需要比较n - 1次,第二轮需要比较n - 2次,以此类推,总的比较次数为(n - 1) + (n - 2) +... + 1 = n(n - 1)/2,时间复杂度为O(n^2)。
二、选择题答案及讲解
- 答案:B
- 讲解:char类型通常占用 1 个字节,用于存储单个字符。int类型在不同系统下可能占用 2 个字节(如 16 位系统)或 4 个字节(如 32 位和 64 位系统);float类型通常占用 4 个字节;double类型通常占用 8 个字节。所以在这几种数据类型中,char占用内存空间最小。
- 答案:D
- 讲解:指针变量在使用前最好初始化,否则它会指向一个不确定的内存地址,可能导致程序崩溃,所以 A 选项错误。指针变量的值是它所指向变量的内存地址,而不是变量的值,B 选项错误。虽然可以对指针变量进行算术运算,如p++,但指针算术运算的结果是基于其所指向的数据类型的大小,并且指针算术运算必须在合理的范围内,否则会导致未定义行为,C 选项不准确。指针变量通常只能指向同类型的变量,这样才能保证对指针所指向内存的访问和操作是安全和正确的,D 选项正确。
- 答案:B
- 讲解:a > b? a : b是一个条件表达式,其含义是如果a > b为真,则返回a的值,否则返回b的值。因为a = 5,b = 3,5 > 3为真,所以该表达式的值为a的值,即 5。
- 答案:A
- 讲解:在for(int i = 0; i < 10; i += 2)循环中,i的初始值为 0,每次循环后i增加 2。当i = 0时,满足i < 10,执行循环体;i变为 2 后,仍满足i < 10,继续执行循环体;以此类推,当i依次变为 4、6、8 时都执行循环体,当i变为 10 时,不满足i < 10,循环结束。所以循环体执行的次数为 5 次。
- 答案:D
- 讲解:switch语句中default分支用于处理case常量表达式都不匹配的情况,它可以省略,A 选项正确。switch语句中case后面的值必须是常量表达式,这是语法要求,B 选项正确。switch语句中case分支可以有多个语句,如果没有break语句,程序会继续执行下一个case分支的语句,所以case分支的多个语句不需要用{}括起来,C 选项正确。switch语句中case分支后面的语句不一定必须以break结束,如果没有break,会发生 “穿透” 现象,即继续执行下一个case分支的语句,所以 D 选项错误。
- 答案:C
- 讲解:在枚举类型enum Week {Mon, Tue, Wed, Thu, Fri, Sat, Sun};中,枚举常量默认从 0 开始编号,Mon的值为 0,Tue的值为 1,Wed的值为 2,以此类推。所以Wed的值为 2。
- 答案:B
- 讲解:在 C++ 运算符优先级中,乘法运算符*的优先级高于加法运算符+,逻辑与运算符&&和等于运算符==。例如表达式3 + 4 * 2,先计算4 * 2,结果为 8,再计算3 + 8,结果为 11。所以在这几个运算符中,*的优先级最高。
- 答案:B
- 讲解:数组在定义后大小是固定的,不能改变,A 选项错误。数组名代表数组的首地址,这是数组的一个重要特性,通过数组名可以访问数组中的元素,B 选项正确。通过数组名不能直接访问数组元素,需要通过数组名加下标来访问,例如arr[0],C 选项错误。数组元素的数据类型必须相同,这是数组的基本定义,D 选项错误。
- 答案:A
- 讲解:在代码int arr[5] = {1, 2, 3, 4, 5}; int *p = arr;中,p指向了数组arr的首地址。在for(int i = 0; i < 5; i++) { cout << *(p + i) << " "; }循环中,*(p + i)等价于arr[i],通过指针偏移依次访问数组中的每个元素,并将其输出。所以这段代码实现的功能是输出数组arr的元素。
- 答案:A
- 讲解:稳定排序是指在排序过程中,相同元素的相对顺序保持不变。冒泡排序在比较相邻元素时,如果元素相等不会交换位置,所以它是稳定排序。快速排序、选择排序和堆排序在某些情况下可能会改变相同元素的相对顺序,属于不稳定排序。例如,对于数组{2, 2, 1},冒泡排序后仍然是{1, 2, 2},相同元素的相对顺序不变;而快速排序在某些划分情况下,可能会将两个2的相对顺序改变。
三、判断题答案及讲解
- 答案:√
- 讲解:在 C++ 中,变量必须先声明后使用。声明变量的作用是告诉编译器变量的类型和名称,以便编译器为其分配内存空间。例如int num;声明了一个int类型的变量num,之后才能对num进行赋值和其他操作。
- 答案:×
- 讲解:字符串常量不能直接赋值给字符数组。例如char arr[10]; arr = "hello";这样的写法是错误的。应该使用strcpy函数来将字符串常量复制到字符数组中,如strcpy(arr, "hello");。这是因为字符数组名是一个常量指针,不能直接被赋值。
- 答案:×
- 讲解:指针变量通常指向同类型的变量。虽然可以通过强制类型转换让指针指向不同类型的变量,但这样做可能会导致未定义行为,因为不同类型的变量在内存中的存储方式和大小可能不同。例如int num = 5; char *p = (char *)#,这样的操作可能会导致访问内存错误,因为char类型和int类型的大小不同。
- 答案:√
- 讲解:if - else语句可以嵌套使用,以实现更复杂的条件判断逻辑。例如if (a > 10) { if (b > 20) { // 内层if语句 } else { // 内层else语句 } } else { // 外层else语句 },通过嵌套可以根据不同的条件执行不同的代码块。
- 答案:×
- 讲解:while循环是先判断条件表达式,若条件为真则执行循环体,若条件一开始就为假,则循环体一次都不会执行。例如int i = 5; while (i > 10) { // 循环体 },由于i > 10为假,循环体不会执行。
- 答案:√
- 讲解:枚举类型的元素默认从 0 开始编号。例如enum Season { SPRING, SUMMER, AUTUMN, WINTER };,SPRING的值为 0,SUMMER的值为 1,AUTUMN的值为 2,WINTER的值为 3。当然,也可以在定义枚举类型时指定元素的值,如enum Season { SPRING = 1, SUMMER, AUTUMN, WINTER };,此时SUMMER的值为 2,AUTUMN的值为 3,WINTER的值为 4。
- 答案:√
- 讲解:数组名作为函数参数传递时,传递的是数组的首地址。这意味着在函数内部对数组元素的修改会影响到原数组。例如void modifyArray(int arr[], int n) { arr[0] = 100; },调用该函数时,传递的数组首地址使得函数内部对arr[0]的修改会改变原数组第一个元素的值。
- 答案:√
- 讲解:逻辑运算符&&和||具有短路特性。对于&&运算符,如果左边的表达式为假,则右边的表达式不会被计算,因为整个表达式已经确定为假。例如(false && someFunction()),someFunction()不会被调用。对于||运算符,如果左边的表达式为真,则右边的表达式不会被计算,因为整个表达式已经确定为真。例如(true || someFunction()),someFunction()不会被调用。
- 答案:×
- 讲解:动态分配的内存(使用new运算符分配的内存)需要手动释放(使用delete或delete[]运算符),否则程序结束时系统不会自动回收,会造成内存泄漏。例如int *p = new int;,在使用完p后,需要使用delete p;来释放内存;如果是动态分配的数组int *arr = new int[10];,则需要使用delete[] arr;来释放内存。
- 答案:×
- 讲解:排序算法的时间复杂度不仅与数据规模有关,还与初始数据的顺序有关。例如冒泡排序,在初始数组已经有序的情况下,时间复杂度为O(n),因为只需要进行一轮比较,没有元素交换;而在初始数组逆序的情况下,时间复杂度为O(n^2)。插入排序也类似,在初始数组有序时,时间复杂度为O(n)。所以排序算法的时间复杂度与初始数据顺序有关。
四、编程题答案及讲解
1. 冒泡排序函数
void bubbleSort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } |
- 讲解:
- 外层循环for (int i = 0; i < n - 1; i++)控制排序的轮数。对于一个长度为n的数组,最多需要进行n - 1轮排序就能将数组排好序。
- 内层循环for (int j = 0; j < n - i - 1; j++)用于比较相邻元素并交换位置。在每一轮排序中,比较的次数会随着轮数的增加而减少,因为每一轮都会将一个最大(或最小)的元素 “冒泡” 到数组的末尾。
- if (arr[j] > arr[j + 1])判断相邻的两个元素arr[j]和arr[j + 1]的大小关系,如果arr[j]大于arr[j + 1],则交换它们的位置。通过int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp;这三行代码实现交换。经过多轮比较和交换,最终数组会按从小到大的顺序排列。
2. 寻找数组最大值和最小值的程序
#include <iostream> using namespace std; int main() { int n; cout << "请输入整数的个数: "; cin >> n; int arr[n]; cout << "请输入" << n << "个整数: "; for (int i = 0; i < n; i++) { cin >> arr[i]; } int maxVal = arr[0]; int minVal = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > maxVal) { maxVal = arr[i]; } if (arr[i] < minVal) { minVal = arr[i]; } } cout << "数组中的最大值为: " << maxVal << endl; cout << "数组中的最小值 |