GESP2026年9月认证C++四级( 第一部分选择题(1~7题)精讲



一、第1题:指针修改变量

题目:

复制代码
int count = 8;
int *p = &count;

*p += 4;

cout << count << " " << *p;

选项:

A. 12 14

B. 14 14

C. 12 12

D. 12 8

答案:C


1. 先认识 p 是什么

这一句:

复制代码
int *p = &count;

可以拆成两部分:

复制代码
&count

表示:

取 count 的地址

而:

复制代码
int *p

表示:

p 是一个"指向 int 的指针"。

所以:

复制代码
p = &count;

可以理解成:

p 手里拿着 count 的房间地址。

可以画成:

复制代码
count
┌───────┐
│   8   │
└───────┘
   ↑
   │
   │ p保存的地址
   │
   p

2. *p 又是什么意思?

这里特别容易混淆。

p

表示:

地址

*p

表示:

这个地址对应的变量

因为:

复制代码
p = &count;

所以:

复制代码
*p

就是:

复制代码
count

因此:

复制代码
*p += 4;

其实就相当于:

复制代码
count += 4;

所以:

复制代码
count:8 → 12

3. 最后输出

复制代码
cout << count << " " << *p;

此时:

复制代码
count = 12
*p = 12

所以输出:

复制代码
12 12

答案:

C


⭐ 小学生记忆口诀

*p 看地址,p 找房子。

也就是:

复制代码
p   → 地址
*p  → 地址里面的东西
&p  → p自己的地址


二、第2题:const int *p 到底能不能修改?

题目:

复制代码
int a = 10;
int b = 20;

const int *p = &a;

题目问哪个说法正确。

选项:

A. 可以通过 p 修改 a 的值

B. 可以令 p = &b

C. p 的指向和所指向的值都不能修改

D. p 必须始终指向 a

答案:B


1. 先看这个奇怪的 const

复制代码
const int *p = &a;

这里的 const 修饰的是:

复制代码
int

也就是说:

不能通过 p 修改它所指向的 int。

因此:

复制代码
*p = 20;

是不允许的。

因为 *p 被看成一个:

复制代码
const int

2. 但是 p 自己能不能改变?

可以!

例如:

复制代码
p = &b;

完全可以。

原来:

复制代码
p
↓
a
10

执行:

复制代码
p = &b;

之后:

复制代码
p
↓
b
20

所以:

p 可以换目标,但是不能通过 p 修改目标。

因此 B 正确。


3. 三种非常容易混淆的写法

这道题非常值得掌握。

第一种

复制代码
const int *p;

或者:

复制代码
int const *p;

意思:

指向的值不能通过 p 修改,p 自己可以改变指向。

例如:

复制代码
*p = 100;   // ❌
p = &b;     // ✅

第二种

复制代码
int * const p = &a;

意思:

p 是一个不能移动的指针。

但是:

p 指向的值可以修改。

所以:

复制代码
*p = 100;   // ✅
p = &b;     // ❌

第三种

复制代码
const int * const p = &a;

两个都不能:

复制代码
*p = 100;   // ❌
p = &b;     // ❌

⭐ 超级口诀

看到 const,先问:

const 管的是谁?

复制代码
const int *p
     ↑
     管数据

int * const p
       ↑
       管指针

const int * const p
     ↑          ↑
   管数据      管指针

这也是 C++ 指针题的经典考点。



三、第3题:二维数组 + 数组指针

题目:

复制代码
int goods[3][4] = {
    {2, 4, 6, 8},
    {10, 12, 14, 16},
    {18, 20, 22, 24}
};

int (*p)[4] = goods;

int x = *(*(p + 1) + 2);

选项:

A. 12

B. 14

C. 20

D. 22

答案:B

这一题是前面 7 道里面最需要理解的一道。


1. 先看二维数组

把它画出来:

复制代码
        第0列 第1列 第2列 第3列

第0行     2    4    6    8

第1行    10   12   14   16

第2行    18   20   22   24

2. p 是什么?

复制代码
int (*p)[4] = goods;

注意括号:

复制代码
int (*p)[4]

表示:

p 是一个指针,指向"包含4个int的数组"。

也就是:

复制代码
p
↓
第0行
[2][4][6][8]

因此:

复制代码
p + 1

不是往后走一个 int

而是:

跳到下一整行。

所以:

复制代码
p
↓
第0行

p + 1
↓
第1行

3. *(p + 1)

p + 1

指向第1行

*

复制代码
*(p + 1)

得到:

第1行这个数组

也就是:

复制代码
10 12 14 16

4. 再看 *(p + 1) + 2

第1行:

复制代码
10  12  14  16
↑

+2

复制代码
10  12  14  16
          ↑

指向:

复制代码
14

最后:

复制代码
*(*(p + 1) + 2)

把它解引用:

复制代码
14

所以:

复制代码
x = 14;

答案:

B


⭐ 二维数组指针万能拆法

遇到:

复制代码
*(*(p + i) + j)

直接翻译:

第 i 行,第 j 列。

所以:

复制代码
*(*(p + 1) + 2)

就是:

复制代码
goods[1][2]

答案自然是:

复制代码
14


四、第4题:二维数组作为函数参数

题目:

复制代码
void addOne(________, int r) {
    for (int j = 0; j < 5; j++) {
        arr[r][j]++;
    }
}

题目要求:

一个 3行5列 的二维数组,第 r 行所有元素加 1。

选项:

A.

复制代码
int arr[][]

B.

复制代码
int **arr

C.

复制代码
int arr[][5]

D.

复制代码
int arr[5][]

答案:

C


1. 为什么必须写 [5]

二维数组:

复制代码
int arr[3][5];

可以理解成:

有 3 行,每行有 5 个整数。

也就是:

复制代码
第0行:5个
第1行:5个
第2行:5个

计算机在内存中是连续存储的。

因此,当你想通过:

复制代码
arr[r][j]

找到元素时,计算机必须知道:

一行到底有多少个元素?

这里就是:

复制代码
5个

所以函数参数至少要告诉计算机:

复制代码
[5]

因此:

复制代码
int arr[][5]

正确。


2. 为什么第一维可以省略?

函数:

复制代码
void addOne(int arr[][5], int r)

第一维:

复制代码
[]

可以不写。

因为函数真正需要知道的是:

每一行有多少列。

也就是:

复制代码
[5]

3. 为什么 int **arr 不对?

这是一个非常重要的坑。

很多初学者会认为:

复制代码
int arr[3][5]

就是:

复制代码
int **arr

其实不是。

二维数组:

复制代码
int arr[3][5];

和:

复制代码
int **p;

在类型上完全不同。

简单理解:

复制代码
二维数组:
┌───────────────┐
│ int int int...│
├───────────────┤
│ int int int...│
├───────────────┤
│ int int int...│
└───────────────┘

int**:
指针 → 指针 → int

所以不能把它们混为一谈。



五、第5题:全局变量、局部变量与引用

题目:

复制代码
int score = 60;

void update(int &score) {
    score += 5;
}

int main() {
    int score = 80;
    update(score);
    cout << score << " " << ::score;
    return 0;
}

选项:

A. 85 60

B. 80 65

C. 85 65

D. 80 60

答案:

A


1. 这里有两个 score

最开始:

复制代码
int score = 60;

这是:

全局变量

可以理解为:

复制代码
整个程序都能找到的 score

score = 60

然后:

复制代码
int main() {
    int score = 80;

这里又定义了一个:

局部变量 score

所以现在有:

复制代码
全局 score = 60

main里面的 score = 80

2. update(score) 修改谁?

复制代码
update(score);

这里传进去的是:

复制代码
main

里的:

复制代码
score = 80

而函数参数:

复制代码
void update(int &score)

这里的 & 是:

引用

所以函数里的 score 和 main 里的 score 是同一个变量。

执行:

复制代码
score += 5;

于是:

复制代码
80 → 85

3. 最后的 ::score 是什么?

这里:

复制代码
cout << score << " " << ::score;

第一个:

复制代码
score

因为在 main 中,所以找到:

复制代码
局部 score = 85

而:

复制代码
::score

前面的:

复制代码
::

叫:

作用域解析运算符

这里表示:

去全局作用域寻找 score。

所以:

复制代码
score    = 85
::score  = 60

输出:

复制代码
85 60

答案:

A


⭐ 这一题一定记住

复制代码
score

找当前作用域。

复制代码
::score

找全局作用域。

可以把 :: 想象成:

"去最外面的房间找!"



六、第6题:结构体传值 vs 引用

题目:

复制代码
struct Device {
    int id;
    int state;
};

void reset(Device d) {
    d.state = 0;
}

void start(Device &d) {
    d.state += 1;
}

int main() {
    Device d{7, 2};

    reset(d);
    start(d);

    cout << d.id << " " << d.state;

    return 0;
}

选项:

A. 7 0

B. 7 1

C. 7 2

D. 7 3

答案:

D


1. 一开始

复制代码
Device d{7, 2};

所以:

复制代码
d.id    = 7
d.state = 2

2. 调用 reset(d)

函数:

复制代码
void reset(Device d)

注意:

这里没有 &

所以是:

值传递

也就是说,函数得到的是一个副本。

可以想象成:

复制代码
原来的 d
id = 7
state = 2

        ↓ 复制

reset里面的 d
id = 7
state = 2

然后:

复制代码
d.state = 0;

修改的是:

复制代码
reset里面的副本

原来的:

复制代码
state = 2

完全没有改变。


3. 接下来 start(d)

函数:

复制代码
void start(Device &d)

这里有:

复制代码
&

所以是:

引用传递

函数里面的 d 就是 main 里面的那个 d

执行:

复制代码
d.state += 1;

原来的:

复制代码
state = 2

变成:

复制代码
state = 3

4. 最后

复制代码
cout << d.id << " " << d.state;

得到:

复制代码
7 3

答案:

D


⭐ 第6题是四级非常重要的考点

一定要分清:

值传递

复制代码
void f(Device d)

相当于:

复印一份再拿进去改。

函数里面改了:

原来的不变。


引用传递

复制代码
void f(Device &d)

相当于:

直接拿原件进去改。

函数里面改了:

原来的也跟着变。


可以用这个表记忆:

写法 实际操作 能否修改原变量
void f(int x) 复制一份
void f(int &x) 使用原变量
void f(int *x) 通过地址访问


七、第7题:结构体数组 + 指针

题目:

复制代码
struct Book {
    string name;
    int pages;
};

int main() {
    Book books[2] = {
        {"C++", 120},
        {"Math", 150}
    };

    Book *p = books + 1;

    p->pages += 10;

    cout << books[1].name << " " << books[1].pages;

    return 0;
}

答案:

C

即:

复制代码
Math 160

1. 先把结构体数组画出来

复制代码
Book books[2]

里面有两个 Book:

复制代码
books[0]
┌──────────────┐
│ C++          │
│ 120          │
└──────────────┘

books[1]
┌──────────────┐
│ Math         │
│ 150          │
└──────────────┘

2. p = books + 1

这里:

复制代码
Book *p = books + 1;

数组名:

复制代码
books

通常可以看成:

复制代码
&books[0]

所以:

复制代码
books + 1

就是:

复制代码
&books[1]

因此:

复制代码
p
↓
books[1]

3. p->pages 是什么意思?

这是结构体指针非常重要的语法。

复制代码
p->pages

等价于:

复制代码
(*p).pages

也就是:

找到 p 指向的结构体,再访问它的 pages

现在:

复制代码
p → books[1]

所以:

复制代码
p->pages

就是:

复制代码
books[1].pages

4. 执行加 10

原来:

复制代码
books[1].pages = 150

执行:

复制代码
p->pages += 10;

变成:

复制代码
150 + 10 = 160

而:

复制代码
books[1].name

仍然是:

复制代码
Math

所以:

复制代码
cout << books[1].name << " " << books[1].pages;

输出:

复制代码
Math 160

答案:

C


.-> 一定要分清

这是结构体指针题的核心。

如果手里是:

复制代码
Book b;

直接使用:

复制代码
b.pages

因为:

b 是结构体对象。


如果手里是:

复制代码
Book *p;

使用:

复制代码
p->pages

因为:

p 是结构体指针。


口诀

对象用点 .,指针用箭头 ->

并且:

复制代码
p->pages

等价于:

复制代码
(*p).pages

注意这里的括号不能省

复制代码
*p.pages

含义就不一样了。


八、把1~7题串成一张"知识地图"

这 7 道题看起来分别在考不同东西,其实它们是一条非常清晰的知识链:

复制代码
                    C++变量
                       │
             ┌─────────┴─────────┐
             ↓                   ↓
           地址                  引用
             │                   │
             ↓                   ↓
           指针              int &x
             │
       ┌─────┴─────┐
       ↓           ↓
   普通变量      数组
       │           │
       ↓           ↓
    *p / &x     二维数组
                   │
                   ↓
              int (*p)[5]
                   │
                   ↓
              函数参数
                   │
                   ↓
             int arr[][5]

结构体
   │
   ├──────────────┐
   ↓              ↓
对象             指针
   │              │
   ↓              ↓
b.id             p->id

九、1~7题考点总结

题号 核心考点 正确答案 一句话记忆
1 指针修改变量 C *p就是p指向的变量
2 const指针 B const int *p:不能改值,可以换指向
3 二维数组指针 B *(*(p+i)+j)就是第 i 行第 j
4 二维数组函数参数 C 二维数组参数必须知道"每行多少列"
5 引用、全局/局部作用域 A ::x找全局变量
6 结构体值传递/引用传递 D & 改原件,没有 & 改副本
7 结构体指针 C 对象用.,指针用->

十、给小学生的"考场版"口诀

如果考试的时候遇到这类题,不要马上算,先问自己几个问题:

① 看到 *p

问:

p指向谁?

例如:

复制代码
int *p = &a;

那么:

复制代码
*p == a

② 看到 const int *p

问:

const管的是谁?

答案:

*p,不能通过 p 修改数据。


③ 看到二维数组

遇到:

复制代码
*(*(p+i)+j)

直接翻译:

第 i 行第 j 列。


④ 看到二维数组函数参数

例如:

复制代码
void f(int a[][5])

记:

第一维可以省,第二维不能乱省。


⑤ 看到函数参数 &

例如:

复制代码
void f(int &x)

记:

&,改的是原来的。


⑥ 看到 ::

记:

往外找,全局作用域。


⑦ 看到结构体

记住:

复制代码
对象.成员

而:

复制代码
指针->成员

也就是:

"人用点,地址用箭头。"


最后给大家一个特别重要的思维方法

要掌握下面这 7 个"翻译器"

复制代码
&p       → p的地址
*p       → p指向的变量

const int *p
           → 不能通过p修改数据

*(*(p+i)+j)
           → 第i行第j列

int a[][5]
           → 每行5个元素

int &x
           → x是原变量的别名

::x
           → 全局作用域的x

p->x
           → (*p).x

如果这 7 个翻译器真正理解了,那么这类 GESP 四级选择题就不是"背答案",而是在做"C++代码翻译题"。


相关推荐
geats人山人海2 小时前
现代c++第二章 字符串
c++
idealzouhu2 小时前
现代 CMake 依赖管理详解:从构建树、Target 封装到 find_package 工作原理
c++·cmake
四代水门3 小时前
游戏客户端——算法题
c++
Xia__Quan3 小时前
centos 共享文件夹
c++
hi_ro_a4 小时前
基于正倒排索引的boost搜索引擎
linux·c++·搜索引擎·项目
神仙别闹4 小时前
基于 C++ MFC 实现的个人通讯录管理系统
c++
GG-_-Bond4 小时前
9.1kv存储持久化模拟面试
linux·c语言·数据结构·c++
郝学胜-神的一滴5 小时前
C++20模板元编程 04:变量模板 别名模板与模板Lambda实战
服务器·开发语言·数据结构·c++·程序人生
qq_344920565 小时前
Qt事件过滤器
开发语言·c++·qt