C语言中的动态内存管理的学习
我们在写程序时,想要自己控制内存,因此动态内存管理非常有必要学习。
动态内存管理常用的函数
使用时需要引入<stdlib.h>头文件
malloc函数
void* malloc(size_t size) // malloc函数的定义,返回值和参数
size为开辟的空间大小
开辟成功返回值是开辟的内存空间的起始位置,开辟失败返回空指针 。返回值需要检查。
使用完申请的空间后需要用free函数来释放空间,再将那个指针变量赋值为NULL。而且free函数只能释放动态开辟的内存空间,否则会发生错误。
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int main() {
int arr[10] = { 0 };
// 动态内存开辟
//int* p = (int*)malloc(INT_MAX); // 错误的申请
int* p = (int*)malloc(40);
// 检查返回值
if (p == NULL) {
printf("%s\n", strerror(errno));
return 1; // 异常返回1
}
// 开辟成功,使用内存
int i = 0;
for (i = 0; i < 10; i++) {
*(p + i) = i;
printf("%d ", *(p + i));
}
// 释放申请的空间
free(p);
// 将变量改为NULL
p = NULL;
return 0;
}
calloc函数
void* calloc (size_t num,size_t size);
这个函数给num个元素(每个元素的大小为size)开辟一片空间,并将初始值设置为0.
与malloc函数的区别这个函数会将开辟的空间的每个字节初始化为0。
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
int main() {
// 开辟时会将初始值复制为0
// 开辟10个整形的空间
int* p = (int*)calloc(5, 10);
if (p == NULL) {
printf("%s\n", strerror(errno));
return 1;
}
int i = 0;
for (i = 0; i < 10; i++) {
printf("%d ", *(p + i));
}
// 释放
free(p);
p = NULL;
return 0;
}
realloc函数
void* realloc(void* ptr, size_t size);
该函数是用来调整动态开辟的内存大小的,ptr是要调整的内存地址,size是调整后的内存大小,返回值为调整之后的内存起始位置,在调整内存大小的基础上,会将原内存中的数据移到新的空间。
如果调整后的空间会覆盖到其他被使用的空间则会另外寻找一片新的空间,并将这片空间的起始地址返回而且会将原空间释放掉,否则会返回当前空间的起始地址。
不要直接用原来的指针接收返回值,可能会返回空指针,应该先用一个新的指针来接收重新开辟后的指针,判断重新开辟后的指针是否为NULL,不为NULL再赋值给原来的指针。
int main() {
realloc(NULL, 80); // 等价于malloc(40);
int* p = (int*)malloc(40);
if (p == NULL) {
printf("%s\n", strerror(errno));
return 1;
}
int i = 0;
// 将开辟空间的元素复制为1,2,3,4,5,6,7,8,9,10
for (i = 0; i < 10; i++) {
*(p + i) = i + 1;
}
// 扩容
int* ptr= (int*)realloc(p, 100);
if (ptr != NULL) { // 判断是否开辟成功
p = ptr; // 将新的地址空间赋值给原来的指针
}
free(p);
free(ptr);
p = NULL;
ptr = NULL;
return 0;
}
使用注意点
- 接收动态开辟空间的返回值后需要判断返回值是否不为NULL,为NULL则不能使用
- 不要越界访问动态开辟的空间
- 不要free释放不是动态开辟的内存空间
- 不要只释放动态开辟的空间的一部分
- 不要多次释放同一块动态开辟的空间
- 不要忘记释放动态开辟的空间!!!(内存泄漏)释放语句可能不执行