C&C++快速入门
12、指针与内存管理
1、课程目标
- 掌握指针的概念和使用
- 理解指针与数组的关系
- 掌握动态内存分配与释放
- 了解常见的内存错误
2、名词解释
| 术语 | 说明 |
|---|---|
| 指针 | 存储内存地址的变量 |
| 解引用 | 通过指针访问指向的数据,使用* |
| 取地址 | 获取变量的内存地址,使用& |
| 空指针 | 值为NULL的指针 |
| 野指针 | 未初始化或指向已释放内存的指针 |
| 悬空指针 | 指向已释放内存的指针 |
| 内存泄漏 | 分配的内存未释放 |
| 堆 | 动态分配内存的区域(Heap) |
| 栈 | 局部变量存储区域(Stack) |
3、代码实现
1. 指针基础
#include <stdio.h>
int main() {
printf("=== 指针基础 ===\n\n");
int value = 42;
int* ptr = &value; // ptr存储value的地址
printf("【基本操作】\n");
printf("value = %d\n", value);
printf("&value = %p\n", (void*)&value);
printf("ptr = %p\n", (void*)ptr);
printf("*ptr = %d\n", *ptr); // 解引用
// 通过指针修改值
*ptr = 100;
printf("\n修改后 value = %d\n", value);
// 指针的指针
int** pptr = &ptr;
printf("\n【二级指针】\n");
printf("pptr = %p\n", (void*)pptr);
printf("*pptr = %p\n", (void*)*pptr);
printf("**pptr = %d\n", **pptr);
return 0;
}
2. 指针运算
#include <stdio.h>
int main() {
printf("=== 指针运算 ===\n\n");
int arr[] = {10, 20, 30, 40, 50};
int* p = arr;
// 指针加减
printf("【指针加减】\n");
printf("p = %p, *p = %d\n", (void*)p, *p);
printf("p+1 = %p, *(p+1) = %d\n", (void*)(p+1), *(p+1));
printf("p+2 = %p, *(p+2) = %d\n", (void*)(p+2), *(p+2));
// 指针相减
printf("\n【指针相减】\n");
int* end = &arr[4];
printf("元素间隔: %td\n", end - p); // 4
// 数组下标与指针
printf("\n【等价写法】\n");
printf("arr[2] = %d\n", arr[2]);
printf("*(arr+2) = %d\n", *(arr+2));
printf("*(p+2) = %d\n", *(p+2));
printf("p[2] = %d\n", p[2]);
return 0;
}
3. 动态内存分配
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
printf("=== 动态内存分配 ===\n\n");
// malloc: 分配未初始化的内存
printf("【malloc】\n");
int* arr1 = (int*)malloc(5 * sizeof(int));
if (arr1 == NULL) {
printf("内存分配失败!\n");
return 1;
}
printf("分配成功: %p\n", (void*)arr1);
// calloc: 分配并初始化为0
printf("\n【calloc】\n");
int* arr2 = (int*)calloc(5, sizeof(int));
if (arr2) {
printf("初始化为0: %d %d %d\n", arr2[0], arr2[1], arr2[2]);
}
// realloc: 重新分配大小
printf("\n【realloc】\n");
arr1[0] = 100;
int* arr3 = (int*)realloc(arr1, 10 * sizeof(int));
if (arr3) {
printf("扩展后原数据保留: %d\n", arr3[0]);
arr1 = arr3; // 更新指针
}
// free: 释放内存
free(arr1); // arr3和arr1指向同一内存
free(arr2);
printf("\n内存已释放\n");
return 0;
}
4. Windows内存管理API
#include <stdio.h>
#include <windows.h>
int main() {
printf("=== Windows内存API ===\n\n");
// VirtualAlloc: 分配虚拟内存
printf("【VirtualAlloc】\n");
LPVOID pMem = VirtualAlloc(
NULL, // 系统选择地址
4096, // 大小
MEM_COMMIT | MEM_RESERVE, // 分配类型
PAGE_READWRITE // 保护属性
);
if (pMem) {
printf("分配地址: %p\n", pMem);
strcpy((char*)pMem, "Hello VirtualAlloc!");
printf("内容: %s\n", (char*)pMem);
// VirtualFree: 释放
VirtualFree(pMem, 0, MEM_RELEASE);
printf("内存已释放\n");
}
// HeapAlloc: 堆内存分配
printf("\n【HeapAlloc】\n");
HANDLE hHeap = GetProcessHeap();
LPVOID pHeapMem = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, 256);
if (pHeapMem) {
printf("堆内存: %p\n", pHeapMem);
HeapFree(hHeap, 0, pHeapMem);
printf("堆内存已释放\n");
}
return 0;
}
5、课后作业
5.1、作业1:实现动态数组
实现可动态增长的数组(简单的vector)。
5.2、作业2:内存分配封装
封装一个安全的内存分配函数,包含分配失败检查。
5.3、作业3:内存拷贝
实现memcpy函数,处理内存重叠情况。