📘指针与动态内存(new/delete)

2026-09-06
⭐⭐ GESP 6级

📖概念讲解

【考点 · 6级】 new/delete 运算符用于在堆内存上动态分配和释放对象,属于指针与内存管理的核心考点。


【说人话】

栈上声明的数组大小编译时就固定了,比如 int a[n] 在很多编译器里其实是变长数组(VLA),不是标准 C++。想要"运行时才知道大小"的数组,必须用 new 在堆上申请,用完记得 delete 还回去,否则内存泄漏。


三个关键区别:

• new int → 申请一个 int 的空间,返回 int* 指针

• new int[n] → 申请 n 个 int 的连续空间,返回 int*

• 数组用 delete[],单个对象用 delete,搞混会出 bug

💻代码示例

1#include <iostream>
2using namespace std;
3
4int main() {
5 int n;
6 cin >> n; // 运行时输入数组大小
7
8 int* arr = new int[n]; // 堆上申请 n 个 int
9
10 for (int i = 0; i < n; i++) {
11 arr[i] = i * 10; // 用法和普通数组一样
12 }
13
14 for (int i = 0; i < n; i++) {
15 cout << arr[i] << " ";
16 }
17 cout << endl;
18
19 delete[] arr; // ⚠️ 数组必须用 delete[],不是 delete
20 arr = nullptr; // 释放后置空,防止野指针
21
22 // 也可以动态申请单个对象
23 int* p = new int(42); // 申请一个 int,初始值 42
24 cout << *p << endl; // 输出 42
25 delete p; // 单个对象用 delete,不用 []
26
27 return 0;
28}
29// 输入:5 → 输出:0 10 20 30 40 42

🧩互动小测

Q1:以下哪种方式能正确释放动态数组?

Q2:new 返回的是什么类型?

Q3:下面代码最大的问题是什么?
int* p = new int[100]; // 用 p 做了一些操作... // 没有 delete[] p

🏋️动手练一练

📝 编程练习

动态数组求前缀和
输入 n,然后输入 n 个整数。用 new 动态分配数组,计算并输出每个位置的前缀和。
提示:前缀和 sum[i] = a[0] + a[1] + ... + a[i],可以原地修改。
参考答案:
#include <iostream>
using namespace std;
int main() {
    int n;
    cin >> n;
    int* a = new int[n];        // 动态分配 n 个 int
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 1; i < n; i++)
        a[i] += a[i-1];         // 原地计算前缀和
    for (int i = 0; i < n; i++)
        cout << a[i] << " ";
    cout << endl;
    delete[] a;                  // 别忘了释放!
    return 0;
}

要点:① 必须用 new int[n] 而不是 int a[n];② 用完后 delete[] 释放;③ 前缀和累加从 i=1 开始。

📝易错点提醒

⚠️ delete 和 delete[] 混用:数组用 delete[],单个对象用 delete。混用在小数据量时可能不崩,但行为未定义,考试判卷直接扣分。


⚠️ 释放后继续使用:delete[] p 之后 p 变成悬空指针(dangling pointer),再 *p 是未定义行为。释放后立刻置 p = nullptr 是好习惯。


⚠️ new 失败不检查:内存不足时 new 会抛异常,竞赛中一般不用管,但真实项目要 try-catch。


⚠️ 动态数组没有边界检查:new int[5] 后访问 a[5] 不会报错但会越界,这是 C++ 的坑。


💡 GESP 考试常见坑:题目给的 n 在运行时才输入,用固定大小数组(如 int a[100000])有时能过,但严格来说应该用 new。看题目 n 的范围决定。

学完这个知识点后点一下