这节主要复习动态内存管理中的malloc, realloc, calloc, 以及free。
为什么使用动态内存管理
首先需要明确一下为什么需要动态内存管理。
我们平常进行开辟空间是这样开辟的:
int a = 0; // 开辟一个四个字节大小的空间, 存放整形数据。
int a[10] = { 0 }; // 开辟一个40 个字节大小的空间, 存放十个整形数据。
但是以上开辟方式, 我们开辟出来的空间是固定的。 这就有可能出现问题。 因为我们在实际生活中, 我们使用的数据大小是不一定的。 我们不知道需要开辟多少空间来满足需求, 这就需要用到动态内存分配。人们可以通过动态内存分配, 使用更加灵活。
malloc
void* malloc (size_t size);
该函数是向堆区的内存中申请一块连续的空间。并返回一个指向这块空间首地址的指针, 注意这里的指针类型是void* 类型。
假如内存不够的话会返回一个空指针。
可以通过强制类型转换转换返回指针的类型。
由于内存不够会返回一个空指针, 所以我们通常在使用malloc之后会进行判断:
如果参数size为0的话, 在c语言的定义中没有标准, 取决于编译器。
free
void free (void* ptr);
free的作用是释放一块空间。
我们在开辟内存空间使用完之后一般需要将内存空间进行释放, 不然这块空间就会一直占用, 导致内存泄漏, 容易内存不足。
需要注意的是, 如果free的空间不是动态开辟的话, 那么是c语言未定义的。
如果free的是一个空指针, free什么也不做。
calloc
void*calloc (size_t num, size_t size);
calloc函数是向堆区申请num 个 size 大小的内存空间。 并且将这些空间置为0。
想要使用的话和malloc一样(两者的区别只是在于calloc进行了初始化, 而malloc没有初始化), 需要判断是否开辟成空。 并且使用完后需要进行空间释放。
realloc
void* realloc(void* ptr, size_t size);
realloc是在原本动态内存空间的基础上重新进行调整。
这里ptr是要调整的空间的地址(只要指向这块空间, 任意一处地址都可以)。
size是要重新进行调整后的大小。
但是,我们可能遇到这么一种情况:我们调整空间时, 后续的空间不够了。 如图:
假如这里的a和b都是我们向堆区申请的内存。 然后我们想要对a进行扩容。 想要扩成原来的二倍, 那么这里是不是就空间不够了。所以realloc在定义里就分了两种情况:
一种是后续空间不够的, 一种是够的。 很显然, 假如后续空间足够, 那么直接进行调整增容调整就可以了。但是另一种情况就不同了。 realloc函数会重新在堆区找一块足够的内存空间进行申请并且将原空间数据拷贝到新空间。然后释放原空间,最后返回重新申请的空间的地址。 如果空间不够的话就申请失败返回空指针,类似于malloc。