第6天:动态内存分配
学习目标
掌握动态内存的分配与释放,理解内存管理的重要性,学会避免内存泄漏和野指针问题。
学习资源链接
📚 官方文档和教程
🎥 视频教程
📖 深入阅读
学习内容
1. 动态内存基础
- 栈内存 vs 堆内存
- new和delete操作符
- new[]和delete[]操作符
- 内存分配失败处理
2. 内存管理问题
- 内存泄漏
- 野指针和悬空指针
- 重复释放内存
- 内存碎片
3. 动态数组
- 动态数组的创建和销毁
- 多维动态数组
- 动态数组的扩容
- 与静态数组的对比
4. 内存对齐
- 内存对齐的概念
- 对齐要求和性能
- 结构体内存布局
- 自定义对齐
5. 内存调试
- 常用内存调试工具
- 内存泄漏检测
- 内存访问错误
- 最佳实践
重点概念和代码示例
基本的new和delete
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <iostream> #include <new> using namespace std;
void basicNewDelete() { cout << "=== 基本new和delete操作 ===" << endl; int* ptr = new int(42); cout << "分配的值: " << *ptr << endl; cout << "内存地址: " << ptr << endl; *ptr = 100; cout << "修改后的值: " << *ptr << endl; delete ptr; ptr = nullptr; double* dptr = new double; cout << "未初始化的double值: " << *dptr << endl; *dptr = 3.14159; cout << "赋值后: " << *dptr << endl; delete dptr; dptr = nullptr; int* zeroPtr = new int(); cout << "零初始化的int值: " << *zeroPtr << endl; delete zeroPtr; }
|
动态数组操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| void dynamicArrays() { cout << "\n=== 动态数组操作 ===" << endl; int size = 5; int* arr = new int[size]; for (int i = 0; i < size; i++) { arr[i] = (i + 1) * 10; } cout << "动态数组内容: "; for (int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; delete[] arr; arr = nullptr; int* arr2 = new int[3]{10, 20, 30}; cout << "初始化的数组: "; for (int i = 0; i < 3; i++) { cout << arr2[i] << " "; } cout << endl; delete[] arr2; int* zeroArr = new int[4](); cout << "零初始化数组: "; for (int i = 0; i < 4; i++) { cout << zeroArr[i] << " "; } cout << endl; delete[] zeroArr; }
|
内存分配异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| void memoryExceptionHandling() { cout << "\n=== 内存分配异常处理 ===" << endl; try { size_t hugeSize = SIZE_MAX / 2; int* hugeArray = new int[hugeSize]; cout << "成功分配大量内存" << endl; delete[] hugeArray; } catch (const bad_alloc& e) { cout << "内存分配失败: " << e.what() << endl; } int* ptr = new(nothrow) int[1000000]; if (ptr == nullptr) { cout << "nothrow版本分配失败" << endl; } else { cout << "nothrow版本分配成功" << endl; delete[] ptr; } set_new_handler([]() { cout << "内存不足,尝试清理..." << endl; throw bad_alloc(); }); }
|
动态二维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| void dynamic2DArray() { cout << "\n=== 动态二维数组 ===" << endl; int rows = 3, cols = 4; int** matrix1 = new int*[rows]; for (int i = 0; i < rows; i++) { matrix1[i] = new int[cols]; } for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { matrix1[i][j] = i * cols + j + 1; } } cout << "二维数组内容:" << endl; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { cout << matrix1[i][j] << "\t"; } cout << endl; } for (int i = 0; i < rows; i++) { delete[] matrix1[i]; } delete[] matrix1; int* matrix2 = new int[rows * cols]; auto getElement = [&](int r, int c) -> int& { return matrix2[r * cols + c]; }; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { getElement(i, j) = (i + 1) * (j + 1); } } cout << "\n连续内存二维数组:" << endl; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { cout << getElement(i, j) << "\t"; } cout << endl; } delete[] matrix2; }
|
实践练习
练习1:动态字符串处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| class DynamicString { private: char* data; size_t length; size_t capacity; public: DynamicString(const char* str = "") { length = strlen(str); capacity = length + 1; data = new char[capacity]; strcpy(data, str); } DynamicString(const DynamicString& other) { length = other.length; capacity = other.capacity; data = new char[capacity]; strcpy(data, other.data); } DynamicString& operator=(const DynamicString& other) { if (this != &other) { delete[] data; length = other.length; capacity = other.capacity; data = new char[capacity]; strcpy(data, other.data); } return *this; } ~DynamicString() { delete[] data; } size_t getLength() const { return length; } const char* c_str() const { return data; } void append(const char* str) { size_t newLength = length + strlen(str); if (newLength + 1 > capacity) { capacity = (newLength + 1) * 2; char* newData = new char[capacity]; strcpy(newData, data); delete[] data; data = newData; } strcat(data, str); length = newLength; } friend ostream& operator<<(ostream& os, const DynamicString& str) { os << str.data; return os; } };
void exercise1() { cout << "\n=== 练习1:动态字符串处理 ===" << endl; DynamicString str1("Hello"); cout << "str1: " << str1 << " (长度: " << str1.getLength() << ")" << endl; DynamicString str2 = str1; cout << "str2 (拷贝): " << str2 << endl; str1.append(" World!"); cout << "str1 追加后: " << str1 << " (长度: " << str1.getLength() << ")" << endl; cout << "str2 未变: " << str2 << endl; str2 = str1; cout << "str2 赋值后: " << str2 << endl; }
|
练习2:动态栈实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| template<typename T> class DynamicStack { private: T* data; int top; int capacity; void resize() { capacity *= 2; T* newData = new T[capacity]; for (int i = 0; i <= top; i++) { newData[i] = data[i]; } delete[] data; data = newData; } public: DynamicStack(int initialCapacity = 10) : capacity(initialCapacity), top(-1) { data = new T[capacity]; } ~DynamicStack() { delete[] data; } void push(const T& value) { if (top + 1 >= capacity) { resize(); } data[++top] = value; } T pop() { if (isEmpty()) { throw runtime_error("Stack is empty"); } return data[top--]; } T peek() const { if (isEmpty()) { throw runtime_error("Stack is empty"); } return data[top]; } bool isEmpty() const { return top == -1; } int size() const { return top + 1; } int getCapacity() const { return capacity; } };
void exercise2() { cout << "\n=== 练习2:动态栈实现 ===" << endl; DynamicStack<int> stack; for (int i = 1; i <= 15; i++) { stack.push(i); cout << "推入 " << i << ", 栈大小: " << stack.size() << ", 容量: " << stack.getCapacity() << endl; } cout << "\n弹出元素: "; while (!stack.isEmpty()) { cout << stack.pop() << " "; } cout << endl; }
|
练习3:内存池简单实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| class SimpleMemoryPool { private: struct Block { Block* next; }; char* pool; Block* freeList; size_t blockSize; size_t poolSize; public: SimpleMemoryPool(size_t blockSize, size_t blockCount) : blockSize(max(blockSize, sizeof(Block))) { poolSize = this->blockSize * blockCount; pool = new char[poolSize]; freeList = reinterpret_cast<Block*>(pool); Block* current = freeList; for (size_t i = 1; i < blockCount; i++) { current->next = reinterpret_cast<Block*>( pool + i * this->blockSize); current = current->next; } current->next = nullptr; } ~SimpleMemoryPool() { delete[] pool; } void* allocate() { if (freeList == nullptr) { return nullptr; } Block* block = freeList; freeList = freeList->next; return block; } void deallocate(void* ptr) { if (ptr == nullptr) return; Block* block = static_cast<Block*>(ptr); block->next = freeList; freeList = block; } bool isFromPool(void* ptr) const { char* charPtr = static_cast<char*>(ptr); return charPtr >= pool && charPtr < pool + poolSize; } };
void exercise3() { cout << "\n=== 练习3:内存池实现 ===" << endl; SimpleMemoryPool pool(sizeof(int), 10); vector<void*> allocatedBlocks; for (int i = 0; i < 10; i++) { void* ptr = pool.allocate(); if (ptr) { *static_cast<int*>(ptr) = i + 1; allocatedBlocks.push_back(ptr); cout << "分配块 " << i + 1 << ", 地址: " << ptr << endl; } else { cout << "分配失败" << endl; break; } } cout << "分配的值: "; for (void* ptr : allocatedBlocks) { cout << *static_cast<int*>(ptr) << " "; } cout << endl; for (size_t i = 0; i < allocatedBlocks.size() / 2; i++) { pool.deallocate(allocatedBlocks[i]); } void* newPtr = pool.allocate(); if (newPtr) { *static_cast<int*>(newPtr) = 999; cout << "重新分配的值: " << *static_cast<int*>(newPtr) << endl; pool.deallocate(newPtr); } for (size_t i = allocatedBlocks.size() / 2; i < allocatedBlocks.size(); i++) { pool.deallocate(allocatedBlocks[i]); } }
|
算法练习题
LeetCode相关题目
- 合并两个有序链表 - 动态创建链表节点
- 删除链表的倒数第N个节点 - 链表内存管理
- 复制带随机指针的链表 - 复杂内存分配
练习4:动态链表实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| template<typename T> class LinkedList { private: struct Node { T data; Node* next; Node(const T& value) : data(value), next(nullptr) {} }; Node* head; Node* tail; size_t size; public: LinkedList() : head(nullptr), tail(nullptr), size(0) {} ~LinkedList() { clear(); } LinkedList(const LinkedList& other) : head(nullptr), tail(nullptr), size(0) { Node* current = other.head; while (current) { push_back(current->data); current = current->next; } } LinkedList& operator=(const LinkedList& other) { if (this != &other) { clear(); Node* current = other.head; while (current) { push_back(current->data); current = current->next; } } return *this; } void push_front(const T& value) { Node* newNode = new Node(value); if (head == nullptr) { head = tail = newNode; } else { newNode->next = head; head = newNode; } size++; } void push_back(const T& value) { Node* newNode = new Node(value); if (tail == nullptr) { head = tail = newNode; } else { tail->next = newNode; tail = newNode; } size++; } void pop_front() { if (head == nullptr) return; Node* temp = head; head = head->next; if (head == nullptr) { tail = nullptr; } delete temp; size--; } void clear() { while (head) { Node* temp = head; head = head->next; delete temp; } tail = nullptr; size = 0; } bool empty() const { return size == 0; } size_t getSize() const { return size; } void print() const { Node* current = head; while (current) { cout << current->data << " -> "; current = current->next; } cout << "nullptr" << endl; } };
void exercise4() { cout << "\n=== 练习4:动态链表实现 ===" << endl; LinkedList<int> list; for (int i = 1; i <= 5; i++) { list.push_back(i); } cout << "链表内容: "; list.print(); cout << "大小: " << list.getSize() << endl; list.push_front(0); cout << "头部添加0后: "; list.print(); list.pop_front(); cout << "删除头部后: "; list.print(); LinkedList<int> list2 = list; cout << "拷贝的链表: "; list2.print(); list.clear(); cout << "原链表清空后大小: " << list.getSize() << endl; cout << "拷贝链表仍存在: "; list2.print(); }
|
常见错误与注意事项
1. 内存泄漏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void memoryLeakExample() { void badFunction() { int* ptr = new int(42); if (someCondition) { return; } delete ptr; } void goodFunction() { int* ptr = new int(42); delete ptr; } }
|
2. 悬空指针
1 2 3 4 5 6 7 8 9 10 11 12 13
| void danglingPointerExample() { int* ptr = new int(42); delete ptr; ptr = nullptr; if (ptr != nullptr) { *ptr = 100; } }
|
3. 重复释放
1 2 3 4 5 6 7 8
| void doubleFreeExample() { int* ptr = new int(42); delete ptr; ptr = nullptr; }
|
学习检查点
完整示例程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| #include <iostream> #include <vector> #include <stdexcept> #include <new> #include <cstring> using namespace std;
int main() { cout << "=== C++ 动态内存分配学习 ===" << endl; try { basicNewDelete(); dynamicArrays(); memoryExceptionHandling(); dynamic2DArray(); exercise1(); exercise2(); exercise3(); exercise4(); } catch (const exception& e) { cout << "异常: " << e.what() << endl; } return 0; }
|
返回第一周 | 上一天:引用 | 下一天:const关键字