- C++
C++ 动态数组
- 2025-5-29 12:00:12 @
C++ 动态数组教程
1. 静态数组 vs 动态数组
静态数组:
- 大小在编译时确定
- 使用固定大小的内存块
- 语法:
类型 数组名[大小];
动态数组:
- 大小在运行时确定
- 可以根据需要调整大小
- 通过指针和内存管理函数实现
2. 使用原始指针和 new/delete 创建动态数组
步骤:
- 使用
new[]
分配内存 - 使用指针访问元素
- 使用
delete[]
释放内存
示例:
#include <iostream>
int main() {
// 1. 声明一个指向int的指针
int* dynamicArray;
// 2. 获取用户输入的数组大小
int size;
std::cout << "请输入数组大小: ";
std::cin >> size;
// 3. 使用new[]动态分配内存
dynamicArray = new int[size];
// 4. 使用数组
for (int i = 0; i < size; i++) {
dynamicArray[i] = i * 2; // 初始化数组元素
}
// 5. 输出数组内容
std::cout << "数组内容: ";
for (int i = 0; i < size; i++) {
std::cout << dynamicArray[i] << " ";
}
std::cout << std::endl;
// 6. 使用delete[]释放内存
delete[] dynamicArray;
return 0;
}
内存管理注意事项:
- 必须使用
delete[]
释放通过new[]
分配的内存 - 忘记释放内存会导致内存泄漏
- 释放后应将指针置为
nullptr
避免野指针
3. 使用 STL 的 vector 容器
vector 简介:
- C++ 标准库提供的动态数组容器
- 自动管理内存
- 提供丰富的成员函数
示例:
#include <iostream>
#include <vector> // 必须包含vector头文件
int main() {
// 1. 声明一个存储int的vector
std::vector<int> dynamicArray;
// 2. 添加元素(自动调整大小)
dynamicArray.push_back(10); // 添加元素10
dynamicArray.push_back(20); // 添加元素20
dynamicArray.push_back(30); // 添加元素30
// 3. 访问元素
std::cout << "第一个元素: " << dynamicArray[0] << std::endl; // 输出: 10
std::cout << "第二个元素: " << dynamicArray.at(1) << std::endl; // 输出: 20
// 4. 修改元素
dynamicArray[1] = 200;
std::cout << "修改后的第二个元素: " << dynamicArray[1] << std::endl; // 输出: 200
// 5. 获取数组大小
std::cout << "数组大小: " << dynamicArray.size() << std::endl; // 输出: 3
// 6. 遍历数组
std::cout << "数组内容: ";
for (int num : dynamicArray) {
std::cout << num << " ";
}
std::cout << std::endl;
// 7. 自动释放内存(vector析构时)
return 0;
}
4. vector 的常用操作
初始化:
// 初始化为空vector
std::vector<int> v1;
// 初始化为包含5个0的vector
std::vector<int> v2(5); // [0, 0, 0, 0, 0]
// 初始化为包含3个10的vector
std::vector<int> v3(3, 10); // [10, 10, 10]
// 使用初始化列表
std::vector<int> v4 = {1, 2, 3, 4, 5};
添加元素:
std::vector<int> numbers;
numbers.push_back(10); // 在末尾添加元素
numbers.insert(numbers.begin(), 5); // 在开头插入元素
删除元素:
numbers.pop_back(); // 删除最后一个元素
numbers.erase(numbers.begin() + 1); // 删除第二个元素
调整大小:
numbers.resize(10); // 调整为10个元素,新增元素用默认值填充
numbers.resize(5); // 截断为5个元素
检查是否为空:
if (numbers.empty()) {
std::cout << "vector为空" << std::endl;
}
5. vector 的高级特性
迭代器:
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 使用迭代器遍历
for (auto it = numbers.begin(); it != numbers.end(); ++it) {
std::cout << *it << " ";
}
范围for循环:
for (int num : numbers) {
std::cout << num << " ";
}
访问最后一个元素:
std::cout << "最后一个元素: " << numbers.back() << std::endl;
内存预分配:
numbers.reserve(100); // 预分配100个元素的空间,减少重新分配次数
6. 动态二维数组
使用原始指针:
#include <iostream>
int main() {
int rows = 3;
int cols = 4;
// 分配二维数组
int** matrix = new int*[rows];
for (int i = 0; i < rows; i++) {
matrix[i] = new int[cols];
}
// 初始化
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j;
}
}
// 输出
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
std::cout << matrix[i][j] << "\t";
}
std::cout << std::endl;
}
// 释放内存(注意顺序)
for (int i = 0; i < rows; i++) {
delete[] matrix[i];
}
delete[] matrix;
return 0;
}
使用vector的vector:
#include <iostream>
#include <vector>
int main() {
int rows = 3;
int cols = 4;
// 创建3行4列的二维vector
std::vector<std::vector<int>> matrix(rows, std::vector<int>(cols));
// 初始化
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j;
}
}
// 输出
for (const auto& row : matrix) {
for (int val : row) {
std::cout << val << "\t";
}
std::cout << std::endl;
}
// 自动释放内存
return 0;
}
7. 性能考虑
vector的优缺点:
- 优点:
- 自动内存管理
- 随机访问效率高(O(1))
- 支持动态调整大小
- 缺点:
- 插入/删除操作在中间或开头较慢(O(n))
- 可能需要重新分配内存(导致性能开销)
优化建议:
- 预先知道大小时使用
reserve()
预分配内存 - 优先在尾部插入/删除元素(
push_back()
,pop_back()
) - 避免频繁调整大小
8. 原始指针 vs vector
特性 | 原始指针 | vector |
---|---|---|
内存管理 | 手动(new/delete) | 自动 |
动态调整大小 | 需手动重新分配 | 自动调整 |
边界检查 | 无 | 可通过at()提供 |
内置功能 | 基本无 | 丰富的成员函数(如size(), empty()) |
安全性 | 易出错(内存泄漏、野指针) | 更安全 |
性能 | 略高(无额外开销) | 接近原生数组 |
总结
动态数组选择建议:
- 优先使用
std::vector
,除非有特殊性能需求 - 使用原始指针时,务必小心内存管理
- 多维数组使用
vector
的vector
更方便
关键点:
- 动态数组在运行时确定大小
vector
是 C++ 首选的动态数组实现- 正确释放动态分配的内存可避免泄漏
- 利用
vector
的成员函数简化开发
通过掌握动态数组,你可以更灵活地处理不同规模的数据,开发出高效、安全的 C++ 程序。
5 条评论
-
admin SU @ 2025-6-2 21:03:35
#include <iostream> using namespace std; int main() { // 1. 声明一个指向int的指针 int* dynamicArray; // 2. 获取用户输入的数组大小 int size; cout << "请输入数组大小: "; cin >> size; // 3. 使用new[]动态分配内存 dynamicArray = new int[size]; // 4. 使用数组 for (int i = 0; i < size; i++) { //dynamicArray[i] = i * 2; // 初始化数组元素 *(dynamicArray+i) = i * 2; } // 5. 输出数组内容 cout << "数组内容: "; for (int i = 0; i < size; i++) { cout << dynamicArray[i] << " "; } cout << endl; // 6. 使用delete[]释放内存 delete[] dynamicArray; dynamicArray = nullptr;//nullptr 空指针 return 0; }
-
2025-6-2 21:02:17@
#include <iostream> using namespace std; int main() { // 1. 声明一个指向int的指针 int* dynamicArray; // 2. 获取用户输入的数组大小 int size; cout << "请输入数组大小: "; cin >> size; // 3. 使用new[]动态分配内存 dynamicArray = new int[size]; // 4. 使用数组 for (int i = 0; i < size; i++) { //dynamicArray[i] = i * 2; // 初始化数组元素 *(dynamicArray+i) = i * 2; } // 5. 输出数组内容 cout << "数组内容: "; for (int i = 0; i < size; i++) { cout << dynamicArray[i] << " "; } cout << endl; // 6. 使用delete[]释放内存 delete[] dynamicArray; return 0; }
-
2025-5-29 15:51:34@
C++ 动态内存管理:new/delete 与动态数组教程
1. 内存管理基础
静态内存分配:
- 编译时确定变量的内存位置和大小
- 栈上分配(如局部变量)
- 自动释放(函数返回时)
动态内存分配:
- 运行时按需分配内存
- 堆上分配(需要手动管理)
- 通过
new
和delete
操作符管理
2. new 和 delete 操作符
基本语法:
// 分配单个对象 类型* 指针 = new 类型; // 分配内存并返回指向该内存的指针 delete 指针; // 释放内存 // 分配数组 类型* 指针 = new 类型[大小]; // 分配数组内存 delete[] 指针; // 释放数组内存
示例:分配单个对象
int* ptr = new int; // 分配一个int大小的内存 *ptr = 42; // 赋值 std::cout << *ptr; // 输出: 42 delete ptr; // 释放内存 ptr = nullptr; // 防止野指针
3. 一维动态数组
使用 new[] 分配一维数组:
#include <iostream> int main() { int size = 5; // 分配动态数组 int* arr = new int[size]; // 分配包含5个int的数组 // 初始化数组 for (int i = 0; i < size; i++) { arr[i] = i * 10; } // 访问数组元素 for (int i = 0; i < size; i++) { std::cout << arr[i] << " "; // 输出: 0 10 20 30 40 } // 释放数组内存 delete[] arr; arr = nullptr; // 防止野指针 return 0; }
关键点:
- 使用
new[]
分配数组 - 使用
delete[]
释放数组(必须使用[]
) - 数组大小可以在运行时确定
4. 二维动态数组
方法1:使用指针数组(锯齿状数组)
#include <iostream> int main() { int rows = 3; int cols = 4; // 分配行指针数组 int** matrix = new int*[rows]; // 为每一行分配列 for (int i = 0; i < rows; i++) { matrix[i] = new int[cols]; } // 初始化矩阵 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { matrix[i][j] = i * cols + j; } } // 输出矩阵 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { std::cout << matrix[i][j] << "\t"; } std::cout << std::endl; } // 释放内存(注意顺序) for (int i = 0; i < rows; i++) { delete[] matrix[i]; // 先释放每行的列 } delete[] matrix; // 再释放行指针数组 matrix = nullptr; return 0; }
方法2:使用连续内存块
#include <iostream> int main() { int rows = 3; int cols = 4; // 分配连续内存块 int* matrix = new int[rows * cols]; // 访问元素(使用行和列索引计算偏移量) for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { matrix[i * cols + j] = i * cols + j; // 计算偏移量 } } // 输出矩阵 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { std::cout << matrix[i * cols + j] << "\t"; } std::cout << std::endl; } // 释放内存 delete[] matrix; matrix = nullptr; return 0; }
5. 多维动态数组
三维数组示例:
#include <iostream> int main() { int x = 2, y = 3, z = 4; // 分配三维数组 int*** arr3d = new int**[x]; for (int i = 0; i < x; i++) { arr3d[i] = new int*[y]; for (int j = 0; j < y; j++) { arr3d[i][j] = new int[z]; } } // 初始化 int count = 0; for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { for (int k = 0; k < z; k++) { arr3d[i][j][k] = count++; } } } // 释放内存(注意顺序) for (int i = 0; i < x; i++) { for (int j = 0; j < y; j++) { delete[] arr3d[i][j]; } delete[] arr3d[i]; } delete[] arr3d; arr3d = nullptr; return 0; }
6. 内存管理最佳实践
避免内存泄漏:
- 每个
new
必须对应一个delete
- 每个
new[]
必须对应一个delete[]
防止野指针:
- 释放内存后将指针置为
nullptr
- 避免多次释放同一内存
异常安全:
- 使用智能指针(如
std::unique_ptr
和std::shared_ptr
)管理动态内存 - 优先使用 STL 容器(如
std::vector
)代替原始动态数组
7. 使用智能指针管理动态数组
C++11 引入的智能指针:
std::unique_ptr
:独占所有权的智能指针std::shared_ptr
:共享所有权的智能指针
示例:使用
std::unique_ptr
管理一维数组#include <iostream> #include <memory> // 必须包含memory头文件 int main() { int size = 5; // 使用unique_ptr管理动态数组 std::unique_ptr<int[]> arr(new int[size]); // 初始化数组 for (int i = 0; i < size; i++) { arr[i] = i * 10; } // 自动释放内存(unique_ptr析构时) return 0; }
示例:使用
std::unique_ptr
管理二维数组#include <iostream> #include <memory> int main() { int rows = 3; int cols = 4; // 创建行指针数组 std::unique_ptr<std::unique_ptr<int[]>[]> matrix(new std::unique_ptr<int[]>[rows]); // 为每一行分配内存 for (int i = 0; i < rows; i++) { matrix[i] = std::unique_ptr<int[]>(new int[cols]); } // 自动释放内存 return 0; }
8. 常见错误与陷阱
内存泄漏示例:
void leakMemory() { int* ptr = new int[100]; // 忘记释放内存! } // 函数返回后内存无法访问,造成泄漏
野指针示例:
int* ptr = new int; delete ptr; // ptr现在是野指针 *ptr = 10; // 未定义行为!
错误的释放方式:
int* arr = new int[10]; delete arr; // 错误!应该使用delete[]
9. new/delete 与 vector 的对比
特性 new/delete std::vector 内存管理 手动 自动 边界检查 无 可通过at()提供 动态调整大小 需要手动重新分配 自动调整(push_back等) 异常安全 需要手动处理 内置支持 代码复杂度 高(管理指针和内存) 低(封装了底层细节) 总结
动态数组分配指南:
-
一维数组:
// 原始方式 int* arr = new int[size]; delete[] arr; // 智能指针方式 std::unique_ptr<int[]> arr(new int[size]);
-
二维数组(指针数组):
// 分配 int** matrix = new int*[rows]; for (int i = 0; i < rows; i++) { matrix[i] = new int[cols]; } // 释放 for (int i = 0; i < rows; i++) { delete[] matrix[i]; } delete[] matrix;
-
优先使用 vector:
// 一维vector std::vector<int> arr(size); // 二维vector std::vector<std::vector<int>> matrix(rows, std::vector<int>(cols));
关键点:
- 理解
new
/delete
和new[]
/delete[]
的配对关系 - 优先使用智能指针和 STL 容器减少内存管理负担
- 始终注意内存泄漏和野指针问题
通过合理使用动态内存分配,你可以开发出更灵活、高效的 C++ 程序。
-
2025-5-29 12:03:12@
📘 C++ 动态数组教程(
new
与delete
)使用
new
和delete
创建和释放动态数组,灵活控制内存。
🧠 为什么需要动态数组?
在 C++ 中,静态数组的大小必须在编译时确定,例如:
int arr[10]; // 固定大小为 10 的数组
但如果我们希望在程序运行过程中根据用户输入或其它条件来决定数组大小,就需要使用 动态数组(Dynamic Array)。这时就要用到
new
和delete
操作符。
✅ 使用
new
创建动态数组🔹 基本语法:
数据类型* 数组名 = new 数据类型[元素个数];
📌 示例:创建一个 int 类型的动态数组
int size; cout << "请输入数组大小:"; cin >> size; int* arr = new int[size]; // 根据用户输入创建数组
🗑️ 使用
delete[]
释放动态数组当你不再需要动态数组时,必须手动释放它占用的内存,避免内存泄漏。
🔹 基本语法:
delete[] 数组名;
📌 示例:释放前面创建的数组
delete[] arr; // 注意要用 delete[]
⚠️ 注意事项
❗ 错误 ✅ 正确 delete arr;
delete[] arr;
👉 如果你使用了
new[]
分配数组,就必须用delete[]
来释放!
💡 完整示例代码
#include <iostream> using namespace std; int main() { int size; cout << "请输入数组大小:"; cin >> size; // ✅ 使用 new 创建动态数组 int* arr = new int[size]; cout << "请输入 " << size << " 个整数:" << endl; for (int i = 0; i < size; ++i) { cin >> arr[i]; // 输入数据 } cout << "你输入的数组是:" << endl; for (int i = 0; i < size; ++i) { cout << arr[i] << " "; // 输出数组 } cout << endl; // ✅ 使用 delete[] 释放内存 delete[] arr; return 0; }
🧩 小技巧:动态数组 vs 静态数组对比
特性 静态数组 动态数组 内存分配时间 编译时 运行时 大小是否可变 不可变 可变 是否需要手动释放 否 是 使用关键字 无 new
/delete[]
推荐使用 简单、固定大小 复杂场景、运行时决定大小
📈 扩展知识:动态数组扩容(模拟 vector)
虽然不能直接改变已分配的动态数组大小,但我们可以通过以下方式实现“扩容”:
- 创建一个新的更大的数组
- 把旧数组内容复制过去
- 删除旧数组
- 返回新数组指针
int* newArr = new int[newSize]; // 新数组 for (int i = 0; i < oldSize; ++i) { newArr[i] = oldArr[i]; // 拷贝数据 } delete[] oldArr; // 删除旧数组 oldArr = newArr; // 更新指针
🎯 总结
操作 语法 说明 创建动态数组 new 数据类型[大小]
在堆中分配空间 释放动态数组 delete[] 数组名
必须使用 []
访问元素 数组名[index]
和普通数组一样访问 扩容 手动拷贝 + 替换数组 模拟 vector 功能
📘 相关推荐
- C++ STL
vector
:现代 C++ 更推荐使用std::vector
,自动管理内存。 - 智能指针:如
std::unique_ptr<int[]>
可以自动释放数组资源。
🎯 练习建议:
- 自己写一个函数,输入任意长度的字符串,动态分配 char 数组保存它。
- 实现一个动态数组类,支持扩容功能。
-
2025-5-29 12:01:50@
🧱 C++ 动态数组(Dynamic Array)教程
✅ 从零开始,详解如何在 C++ 中手动管理动态数组
📚 包括:new/delete
、构造函数、析构函数、深拷贝、运算符重载等
💡 图标丰富、代码带注释、通俗易懂
🕒 当前时间:2025年5月29日,星期四11时47分
📘 目录
- 📦 什么是动态数组?
- 🛠️ 使用
new
和delete
手动分配内存 - 🧩 自定义动态数组类(
DynamicArray
)- 构造函数 & 析构函数
- 深拷贝与浅拷贝
operator[]
重载- 添加元素(push_back)
- 🧪 示例:创建并使用你的第一个动态数组
- 🧠 小贴士 & 常见错误
- 📌 总结
1️⃣ 📦 什么是动态数组?
动态数组是一种可以在运行时根据需要扩展大小的数组。
🔹 C++ 标准库中已有
std::vector
,但学习手动实现有助于理解:- 内存管理机制
- 类的设计
- 运算符重载
- 资源释放与拷贝控制
2️⃣ 🛠️ 使用
new
和delete
手动分配内存✅ 分配内存:
int* arr = new int[10]; // 分配一个长度为10的整型数组
✅ 释放内存:
delete[] arr; // 注意使用 delete[] 而不是 delete
🔸 不要忘记释放,否则会造成内存泄漏!
3️⃣ 🧩 自定义动态数组类
DynamicArray
我们将构建一个简单的动态数组类,支持以下功能:
- 构造函数初始化容量和大小
- 析构函数自动释放资源
push_back()
添加元素[]
下标访问- 深拷贝构造函数和赋值运算符
- 打印数组内容
📁 类结构设计如下:
class DynamicArray { private: int* data; // 数据指针 int capacity; // 容量(最大能装多少个元素) int size; // 当前元素数量 public: DynamicArray(int cap = 4); // 构造函数 ~DynamicArray(); // 析构函数 DynamicArray(const DynamicArray& other); // 拷贝构造函数 DynamicArray& operator=(const DynamicArray& other); // 赋值运算符 void push_back(int value); // 添加元素 int& operator[](int index); // 下标访问 int getSize() const; // 获取当前大小 void print() const; // 打印数组 };
🔧 实现各成员函数
🟢 构造函数
DynamicArray::DynamicArray(int cap) : capacity(cap), size(0) { data = new int[capacity]; // 初始化数组 }
🔴 析构函数
DynamicArray::~DynamicArray() { delete[] data; // 释放内存 }
🟡 拷贝构造函数(深拷贝)
DynamicArray::DynamicArray(const DynamicArray& other) : capacity(other.capacity), size(other.size) { data = new int[capacity]; // 新开辟一块内存 for (int i = 0; i < size; ++i) { data[i] = other.data[i]; // 拷贝数据 } }
🟠 赋值运算符(深拷贝)
DynamicArray& DynamicArray::operator=(const DynamicArray& other) { if (this == &other) return *this; // 防止自赋值 delete[] data; // 先释放旧内存 capacity = other.capacity; size = other.size; data = new int[capacity]; for (int i = 0; i < size; ++i) { data[i] = other.data[i]; } return *this; }
🔼 添加元素函数
void DynamicArray::push_back(int value) { if (size >= capacity) { // 如果空间不足,扩容两倍 int newCapacity = capacity * 2; int* newData = new int[newCapacity]; for (int i = 0; i < size; ++i) { newData[i] = data[i]; // 拷贝旧数据 } delete[] data; // 释放旧内存 data = newData; capacity = newCapacity; } data[size++] = value; // 插入新元素 }
🔺 重载下标访问
[]
int& DynamicArray::operator[](int index) { if (index < 0 || index >= size) { throw std::out_of_range("Index out of range"); } return data[index]; }
📝 获取大小 & 打印函数
int DynamicArray::getSize() const { return size; } void DynamicArray::print() const { std::cout << "[ "; for (int i = 0; i < size; ++i) { std::cout << data[i] << " "; } std::cout << "]" << std::endl; }
4️⃣ 🧪 示例:创建并使用你的第一个动态数组
int main() { DynamicArray arr; arr.push_back(10); arr.push_back(20); arr.push_back(30); std::cout << "原始数组: "; arr.print(); // 输出: [ 10 20 30 ] arr[1] = 25; // 修改第二个元素 std::cout << "修改后: "; arr.print(); // 输出: [ 10 25 30 ] DynamicArray arr2 = arr; // 深拷贝构造 arr2.push_back(40); std::cout << "arr2 数组: "; arr2.print(); // 输出: [ 10 25 30 40 ] return 0; }
5️⃣ 🧠 小贴士 & 常见错误
✅ 推荐做法:
- 使用 RAII(资源获取即初始化)原则,确保资源自动释放
- 对于大型项目,优先使用
std::vector
- 使用异常处理来避免越界访问
- 使用命名空间组织代码
❌ 常见错误:
- 忘记释放内存 ➜ 导致内存泄漏
- 浅拷贝 ➜ 两个对象共享同一块内存
- 没有检查索引是否越界
- 使用
delete
而不是delete[]
来释放数组
6️⃣ 📌 总结图表
技术 关键词/方法 用途 动态内存 new[]
,delete[]
创建和释放数组 构造函数 DynamicArray()
初始化数组 析构函数 ~DynamicArray()
释放内存 拷贝控制 拷贝构造函数
,operator=
支持深拷贝 运算符重载 operator[]
访问数组元素 扩容机制 push_back()
自动增长数组容量
📄 下一步学习建议
- 学习使用
std::vector
替代手动实现 - 研究模板泛型,使你的动态数组支持任意类型(如
DynamicArray<T>
) - 实现插入、删除、查找等操作
- 学习智能指针(
std::unique_ptr
,std::shared_ptr
)
- 1