GESP认证C++编程真题解析 | 202606 四级
附上汇总帖:GESP认证C++编程真题解析 | 汇总
单选题
第1题
小杨正在编写一个“数字交换器”程序,他希望通过函数交换两个变量的值。请问运行以下代码后,屏幕上输出的是( )。
void exchange(int *a, int &b) {
int t = *a;
*a = b;
b = t;
}
int main() {
int x = 100, y = 200;
exchange(&x, y);
cout << x << " " << y;
return 0;
}
A. 100 200
B. 200 100
C. 200 200
D. 编译错误
【答案】:B
【解析】
函数exchange的第一个参数是 int指针,第二个参数是 int 引用,两种方式都能修改实参。调用exchange(&x, y) 时,a指向x,b是y的别名。执行t=a=100;a=b即x=200;b=t即y=100。所以交换后x=200,y=100,输出"200 100"。
第2题
下面程序想通过函数计算三门课总分,横线处应填入的是( )。
int sumScore(int a, int b, int c) {
return a + b + c;
}
int main() {
int chinese = 88, math = 95, english = 90;
int total = __________;
cout << total;
return 0;
}
A. sumScore
B. sumScore(chinese, math, english)
C. sumScore(int chinese, int math, int english)
D. sumScore(a, b, c)
【答案】:B
【解析】
调用函数时需要使用函数名加实参列表,实参的类型和顺序要与形参匹配。main p 函数中定义了chinese、math、english三个变量,应调用sumScore(chinese, math, english)。选项A缺少参数;选项C在调用时写了参数类型,这是函数声明语法而非调用语法;选项D使用的变量a、b、c在main中未定义。
第3题
下面程序输出结果是( )。
int addOne(int x) {
return x + 1;
}
int main() {
int a = 6;
cout << addOne(a) + addOne(3);
return 0;
}
A. 9
B. 10
C. 11
D. 12
【答案】:C
【解析】
addOne(a)=addOne(6)=7,addOne(3)=4,两者相加7+4=11。函数参数按值传递,在函数内部 x 是实参的副本,修改x不影响实参。
第4题
关于下面程序,说法正确的是( )。
void show() {
int stars = 5;
}
int main() {
cout << stars;
return 0;
}
A. 程序输出 5
B. 程序可以通过编译,但输出随机值
C. 程序不能通过编译,因为 stars 只在 show 函数中有效
D. 程序不能通过编译,因为 cout 不能输出变量
【答案】:C
【解析】
stars 是 show 函数内的局部变量,其作用域仅限于 show 函数的花括号内。在main函数中访问stars 会因变量未声明而编译失败。这体现了局部变量作用域的概念:局部变量在定义它的函数结束后就被销毁,外部无法访问。
第5题
小杨在调试一个“等级提升”系统,代码逻辑如下,执行后 *p 的值是( )。
int lv = 5, next_lv = 6;
int *p = &lv;
*p = *p + 1;
p = &next_lv;
A. 5
B. 6
C. lv 的地址
D. next_lv 的地址
【答案】:B
【解析】
逐步分析:p=&lv,p指向lv;*p=*p+1即lv=5+1=6;然后p=&next_lv,p改为指向next_lv。此时*p=next_lv=6。注意最后一行只是改变了p的指向,并没有通过 p 修改 next_lv的值,所以*p 的值就是next_lv的值6。
第6题
小杨正在开发一款名为“星际网格”的游戏,他用二维数组 int map[5][4]; 来表示地图。已知 int 占 4 字节,如果 map 的内存地址是 0x2000 ,则表达式 &map + 1 的地址值是( )。
A. 0x204c
B. 0x205c
C. 0x2050
D. 0x2058
【答案】:C
【解析】
&map是指向整个二维数组的指针,其类型是 int(*)[5][4]。对&map加1,指针会跳过整个数组的大小。数组map共5×4=20个int,占20×4=80字节=0x50字节。所以 &map+1的地址=0x2000+0x50=0x2050。注意区分 map + 11(跳过一行16字节)和&map+1(跳过整个数组80字节)。
第7题
执行完下面代码后,变量 val 的值是( )。
int data[] = {10, 20, 30, 40, 50};
int *ptr = data + 2;
int val = *(ptr - 1) + *(ptr + 1);
A. 50
B. 60
C. 70
D. 80
【答案】:B
【解析】
data + 2指向data[2]=30。ptr-1指向data[1]=20,(ptr-1)=20;ptr+1 指向data[3]=40,(ptr +1)=40。val=20+40=60。指针的加减运算以元素大小为单位,ptr+n表示向后移动n个元素。
第8题
某班 3 个小组、每组 4 名同学的分数存入下面的二维数组 score ,则 score[1][2] 的值是( )。
int score[3][4] = {
{80, 81, 82, 83},
{90, 91, 92, 93},
{70, 71, 72, 73}
};
A. 81
B. 90
C. 92
D. 72
【答案】:C
【解析】
二维数组score有3行4列,下标从0开始。score[1][2]表示第2行(下标1)第3列(下标2)的元素。第2行是{90, 91, 92, 93},第3个元素(下标2)是92。
第9题
小杨定义了一个结构体 Hero 来表示游戏角色,下面哪种初始化方式会由于语法错误导致编译失败?( )。
struct Hero {
string name;
int hp;
};
A. Hero h = {"Arthur", 100};
B.
Hero h;
h.name = "Arthur";
h.hp = 100;
C. Hero h = new Hero{"Arthur", 100};
D. Hero *p = new Hero{"Arthur", 100};
【答案】:C
【解析】
选项A使用列表初始化,语法正确。选项B先默认构造再逐成员赋值,语法正确。选项D用 new动态创建结构体并返回指针赋给 Hero,语法正确。选项C的错误在于new返回的是 Hero 指针类型,而左边h 是Hero对象类型,类型不匹配导致编译失败。正确写法应该是 Hero *p = new Hero{"Arthur", 100}或 Hero h{"Arthur", 100}。
第10题
下面程序输出结果是( )。
struct Book {
string title;
int pages;
};
int main() {
Book books[2] = {{"Math", 120}, {"Science", 150}};
cout << books[1].title;
return 0;
}
A. Math
B. Science
C. 120
D. 150
【答案】:B
【解析】
books是结构体数组,books[0]={"Math", 120},books[1]={"Science", 150}。books[1].title 即第二个元素的title 成员,值为"Science"。注意数组下标从0开始,books[1]是第二个元素。
第11题
小杨在对“能量晶石”按亮度进行排序。如果两块晶石亮度相同,他希望保持它们在原始序列中的相对顺序。下列关于排序算法稳定性的说法,错误的是( )。
A. 冒泡排序是稳定的,因为只有在左边比右边大时才交换。
B. 插入排序是稳定的,因为它将元素插入到相等元素的右侧。
C. 选择排序是稳定的,因为它每次选出最小元素放在前面。
D. 稳定性是指排序后相等元素的相对位置不发生改变。
【答案】:C
【解析】
稳定排序的定义是:对于相等的元素,排序后它们的相对顺序保持不变。冒泡排序在相邻元素比较时,只有前一个大于后一个才交换,相等时不交换,所以是稳定的,A正确。插入排序将元素插入到相等元素的右侧(遇到相等的就停在其后面),保持稳定性,B正确。D是稳定性的标准定义,正确。选择排序每次选最小元素与当前位置交换,这个跨越式交换可能改变相等元素的相对顺序,所以选择排序是不稳定的,C说它是稳定的是错误的。
第12题
小杨的机器人正在能量踏板上跳跃,踏板编号为 1,2,3,...。跳到第 n 块踏板的方案数满足递推式 f(n)=f(n-1)+f(n-2)。若 f(1)=1, f(2)=2,则运行以下代码计算 jump(5) 的结果是( )。
int jump(int n) {
if (n <= 2)
return n;
int a = 1, b = 2, c = 0;
for (int i = 3; i <= n; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
A. 5
B. 8
C. 13
D. 21
【答案】:B
【解析】
这是斐波那契式的递推:jump(1)=1,jump(2)=2,jump(n)=jump(n-1)+jump(n-2)。逐步计算:jump(3)=1+2=3,jump(4)=2+3=5,jump(5)=3+5=8。代码用三个变量a、b、c滚动计算,避免了递归的重复计算。
第13题
在“模拟实验室”程序中,为了防止除以 0 导致崩溃,小杨使用了异常处理机制。执行以下代码将输出( )。
try {
int x = 10, y = 0;
if (y == 0) throw "Zero Error";
cout << x / y;
} catch (int e) {
cout << "Error Code: " << e;
} catch (const char* msg) {
cout << "Caught: " << msg;
}
A. 0
B. Error Code: 0
C. Caught: Zero Error
D. 程序直接崩溃
【答案】:C
【解析】
y == 0时执行 throw "Zero Error",抛出的是 const char* 类型的字符串字面量。try 块后续代码不再执行。第一个catch 捕获int类型,不匹配;第二个 catch 捕获 const char* 类型,匹配成功,输出"Caught: Zero Error"。异常处理的关键是 throw 的类型与 catch的参数类型匹配。
第14题
下面代码使用某种排序算法,将数组中的元素按从小到大排序。这段代码使用的排序算法是( )。
void mystery_sort(double arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int minPos = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minPos]) {
minPos = j;
}
}
double temp = arr[i];
arr[i] = arr[minPos];
arr[minPos] = temp;
}
}
A. 冒泡排序
B. 插入排序
C. 选择排序
D. 非典型排序
【答案】:C
【解析】
这段代码的典型特征是:外层循环每轮确定一个位置i,内层循环从i+1到n-1找最小元素的位置minPos,然后将最小元素与位置i的元素交换。这正是选择排序的核心思想——每轮选出未排序部分的最小值放到已排序部分的末尾。与冒泡排序的区别是不相邻交换而是跨越交换;与插入排序的区别是不逐个后移而是直接找最值。
第15题
小杨正在读取“冒险日志”文件 quest.txt 。若文件内容为 Level 10 ,执行以下程序后输出为( )。
ifstream fin("quest.txt");
string s;
int v;
fin >> s >> v;
cout << s.length() * v;
A. 50
B. 15
C. 70
D. 5
【答案】:A
【解析】
文件内容为"Level 10",fin >> s 读取第一个以空格分隔的词"Level",s.length()=5;fin>>v 读取整数10。输出5×10=50。注意>>运算符读取时会自动跳过空白字符并以空格作为分隔符。
判断题
第1题
运行以下程序后,变量 a 的值最终会变为 20 。
void modify(int *p) {
*p = *p + 10;
}
int main() {
int a = 10;
modify(&a);
return 0;
}
A. 正确
B. 错误
【答案】:A
【解析】
modify函数接收a的地址,通过*p=*p+10将a的值修改为10+10=20。指针传参可以在函数内修改实参的值,这是指针的核心用途之一。
第2题
在 C++ 中,引用一旦初始化并绑定到某个变量后,可以通过赋值语句将其重新绑定到另一个变量。
A. 正确
B. 错误
【答案】:B
【解析】
引用的一个重要特性是"一经绑定,不可更改"。引用在初始化时绑定到一个变量后,后续所有对引用的赋值操作实际上都是修改被引用变量的值,而不是让引用指向新的变量。这与指针不同,指针可以重新指向其他变量。所以"可以通过赋值语句将其重新绑定到另一个变量"的说法是错误的。
第3题
下面程序可以正确计算并输出 3 名学生的平均成绩。
struct Student {
int id;
int score;
};
int main() {
Student students[3] = {
{1, 90},
{2, 80},
{3, 100}
};
int sum = 0;
for (int i = 0; i < 3; i++) {
sum += students[i].score;
}
double average = sum / 3.0;
cout << average << endl;
return 0;
}
A. 正确
B. 错误
【答案】:A
【解析】
程序定义了结构体数组,每个元素包含id和score。循环累加3名学生的成绩:sum=90+80+100=270。然后计算平均值 average =270/3.0=90.0。注意这里除以3.0而非3,确保进行浮点除法,结果正确。
第4题
选择排序算法在寻找每一轮最小值时,如果遇到相等的元素不进行交换,则选择排序是一种稳定的排序算 法。
A. 正确
B. 错误
【答案】:B
【解析】
选择排序的不稳定性并非仅仅因为"遇到相等的元素进行交换"。即使在内层循环中遇到相等元素不更新 minPos (即 if (arr[j]< arr[minPos])用严格小于),选择排序仍然可能不稳定。原因是外层循环的交换操作:当最小元素与位置i的元素交换时,可能把位置上原有的元素交换到后面,如果这个元素与后面某个相等元素原本有先后关系,就会被打乱。例如序列[5a, 5b, 2],第一轮选出最小值2与5a交换,得到[2, 5b, 5a],5a和5b的相对顺序变了。所以选择排序本质上是不稳定的。
第5题
如果使用带 flag 的冒泡排序,且待排序数组一开始就是有序的,那么算法只需一轮扫描即可结束,时间复杂度为 \(O(n)\)。
A. 正确
B. 错误
【答案】:A
【解析】
带flag 的冒泡排序在每轮扫描前将 flag 设为false,如果发生交换就设为 true。如果数组本身有序,第一轮扫描中所有相邻元素比较都不会触发交换,flag 保持 false,算法提前结束。只需一轮n-1次比较,时间复杂度为O(n),这是冒泡排序的最佳情况。
第6题
在 C++ 中定义二维数组并初始化时,可以省略第一维,但不能省略第二维。因此 int a[][2] = {{1, 2}, {3, 4}}; 是合法的,而 int a[][] = {{1, 2}, {3, 4}}; 是不合法的。
A. 正确
B. 错误
【答案】:A
【解析】
C++中二维数组初始化时,编译器可以根据初始化列表自动推断第一维(行数)的大小,所以可以省略第一维。但第二维(列数)必须明确指定,因为编译器需要知道每行的元素个数来正确排列内存布局。int a[][2]= {{1, 2},{3, 4}}合法,编译器推断为2行2列;int a[][] = {{1, 2},{3, 4}}缺少第二维信息,编译器无法确定每行元素个数,不合法。
第7题
下面代码的时间复杂度是 \(O(2^n)\)。
int cnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
cnt++;
}
}
A. 正确
B. 错误
【答案】:B
【解析】
该代码外层循环执行n次,内层循环次数随变化,总执行次数为 \(1+2+…+n=\frac{n(n+1)}{2}\),最高次项为\(n^2\),因此时间复杂度为 \(O(n^2)\),而非\(O(2^n)\)。题目中说时间复杂度是\(O(2^n)\)是错误的。
第8题
假设文件 output.txt 能正常打开,下面代码通过 rdbuf 将 cout 的输出重定向到了文件中。
ofstream fout("output.txt");
streambuf* old_buf = cout.rdbuf();
cout.rdbuf(fout.rdbuf());
cout << "GESP Exam";
cout.rdbuf(old_buf);
A. 正确
B. 错误
【答案】:A
【解析】
rdbuf()用于获取或设置流的缓冲区指针。cout.rdbuf(fout.rdbuf()) 将 cout 的输出缓冲区重定向到文件输出流 fout 的缓冲区,此后所有 cout 的输出都会写入文件 output.txt 而非屏幕。最后 cout.rdbuf(old_buf) 恢复cout原来的缓冲区,后续输出重新回到屏幕。这是C++中输出重定向的标准做法。
第9题
小杨想通过下面程序给饭卡充值,程序会输出 70 。
void recharge(int money) {
money += 20;
}
int main() {
int card = 50;
recharge(card);
cout << card;
return 0;
}
A. 正确
B. 错误
【答案】:B
【解析】
recharge函数的参数:money是按值传递的,函数内修改的是 money这个副本,不影响实参 card的值。调用recharge(card)后,card 仍然是50,不会变成70。要真正修改card,需要使用引用传参void recharge(int &money) 或指针传参 void recharge(int *money)。
第10题
下面代码可以通过编译。
int a[5];
a++;
A. 正确
B. 错误
【答案】:B
【解析】
数组名a是一个常量指针(指向数组首元素),其值不能被修改。a++ 试图对数组名进行自增操作,相当于修改常量指针的指向,这是不允许的。编译器会报错 "lvalue required as increment operand" 。虽然数组名在表达式中会退化为指向首元素的指针,但它不是可修改的左值。
浙公网安备 33010602011771号