目录
一、为什么存在动态内存管理
内存有几个区,栈区,堆区,静态区。动态内存分配分配的就是堆区的空间。静态区存放全局和静态变量以及static,栈区存放局部变量,函数的形参。
当前我们有一些声明变量的方式,比如int a = 0这样,也可以声明数组,声明结构体等等,相应的声明的数组是全局的,那就放在静态区。不过现在要想想,当建立数组存储一个班的数据时,我们会面临一个问题,要放多少个学生的数据?
先简单建立一下
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
struct S
{
char name[20];
int age;
};
int main()
{
struct S arr[50];//假如只有20个学生,那么就产生空间浪费了
最好是想要多大就多大,我们也不能把50换成一个n,然后输入进去的数字放进n的地址,因为数组声明需要用常量表示元素个数
现在来看,这种开辟空间的方式有两个特点:
空间开辟大小固定
数组再申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
对于开辟空间,有时候事先并不知道,运行后才会知道准确的消息,所以这就需要动态分配
二、函数
malloc和free
void* malloc(size_t size)size就是开辟的空间字节大小 。
#include <stdio.h>
int main()
{
//向内存申请10个整形的空间
int* p = (int*)malloc(10 * sizeof(int));
return 0;
}
不过也有一个问题,malloc开辟空间失败,比如只有1g空间,就无法开辟3g空间。
malloc会返回一个指针,指向那个开辟好的空间。或者返回空指针。
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
//向内存申请10个整形的空间
int* p = (int*)malloc(10 * sizeof(int));
if (p == NULL)
{
//打印错误原因的一个方式
printf("%s\n", strerror(errno));
}
else
{
//正常使用空间
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
}
return 0;
}
空间使用完还需要返还,需要用到free
void free (void* memblock)
return 0 前直接加上free (p) 即可。
虽然说不写free,这个程序结束后也会还回去,但是需要整个程序结束才能返还。所以需要free及时清理空间。
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
//向内存申请10个整形的空间
int* p = (int*)malloc(10 * sizeof(int));
if (p == NULL)
{
//打印错误原因的一个方式
printf("%s\n", strerror(errno));
}
else
{
//正常使用空间
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
}
free(p);
p = NULL;//空指针是不使用的,这也有效防止p的使用
return 0;
}
即使free (p) 后,p这个指针还是指向那个地址,所以为了防止p继续被使用,地址安全,所以需要赋值为空。
如果size为0,那么malloc的这种行为是标准未定义的,c语言没有专门的说明,这样就会根据编译器不同,malloc就不同。
free要释放的空间必须是动态开辟的,否则也是标准未定义的。
如果是空指针,那么free什么也不做。
结束。