【C语言】动态内存分配(malloc,realloc,calloc,free)的基本理解和区别
一.为什么要使用动态内存分配???
以一个数组为例:在定义一个数组时给定了其内存空间,只要给定足够大的空间,就可以放入你所需的数据元素。但当内存空间小于所需放入的元素个数时,我们就需要给这个内存空间去增容,以此来满足你的需求。
上述定义数组时设置足够大的内存空间看似简单,但却有以下缺点:
1.如果内存空间很大,数据却很少就会使内存空间浪费。
2.如果内存空间不足就会出现溢出的现象。
二.malloc
1. 函数原型:
//头文件
#include<malloc.h>
//函数原型
void *malloc(sizt_t size);
malloc的参数就是需要所分配的字节数。
2. malloc在C语言中不是关键字而是C函数库中提供的函数。如果需要进行内存分配时在调用malloc时就是在内存池中提取一块内存空间(在堆上申请一块空间),但是这块空间是连续的空间。,并向该程序返回一个这块内存的指针。
注意:在申请完空间后需要自己去初始化这块空间,如果懒得动手那就可以用realloc(下面会介绍)
3.malloc进行内存分配的特点:
(1.)所申请的空间是连续的
(2.)在有的编译器下申请的空间略大于你请求申请的内存空间
(3.)malloc所返回的内存起始位置将始终能够满足对边界对齐
4.malloc是如何知道你所申请的内存空间是什么类型?
这是因为在使用malloc进行内存分配时会返回void*类型的指针,但是这个指针可以转化为任意类型的指针。(但是有些老式的编译器需要你去强转你所需要的类型)
#include<Windows.h>
#include<stdio.h>
#include<malloc.h>
int main()
{
int* p = NULL;
printf("%x\n", p);
p = (int*)malloc(sizeof(int)* 25);
if (NULL == p)
{
printf("申请失败!!!");
return 0;
}
printf("%x\n", p);
system("pause");
return 0;
}
二.calloc
函数原型:
//有文件
#include<stdlib.h>
//源文件
void* calloc(size_t num_elements,size_t element_size);
calloc和calloc的动态分配内存是有相同之处,他们的主要区别在于:
(1.)在函数原型中calloc多了一个参数(他的参数是由所需元素的个数和每个元素的字节数组成)
(2.)最大区别:calloc在调用完后返回指向内存的指针之前把他初始化为0
#include<Windows.h>
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
int main()
{
int* p = NULL;
int* p1 = NULL;
p = (int*)malloc(sizeof(int)* 5);
if (NULL == p)
{
printf("申请失败!!!");
return 0;
}
printf("malloc:\n");
for (int i = 0; i < 5; i++)
{
printf(" %d-->", *p);
*p++;
}
printf("\n");
p1 = (int*)calloc(5, sizeof(int));
if (NULL == p1)
{
printf("申请失败!!!");
return 0;
}
printf("calloc:\n");
for (int j = 0; j < 5; j++)
{
printf(" %d-->",*p1);
*p1++;
}
system("pause");
return 0;
}
注意:在调用完calloc后也要进行判断是否申请成功
三.realloc
函数原型:
//头文件
#include<stdlib.h>
//原型
void realloc(void *ptr, size_t new_size);
ptr是指向原来地址的指针。
这个函数用于修改一个原先已经分配内存块的大小。
使用:
1.可以使一块内存扩大或缩小(原来的内存块可以扩大缩小)
(1.)如果是扩大一个内存块,则将原来的内存块保留在他的后边新增一块内存块(但是新增的内存块并未初始化)
(2.)如果是缩小一块内存块,则将该内存块的后半部分直接拿掉,剩余部分内存块及其内容保留。
2.原来的内存块无法扩大缩小
如果是着这种情况,realloc会重新开辟一个新的内存空间,并把原来的内存空间的内容拷贝到新的内存空间里。
注意:再调用完realloc后就不能使用指向就内存的指针,而是用返回的新的指针。
值得一提的是:如果realloc中的第一个参数如果为空则和malloc一样。
#include<Windows.h>
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
int main()
{
const int size = 2000;
int *p = (int *)malloc(20 * sizeof(int));
int *p1 = (int *)realloc(p, size*sizeof(int));
printf("%x\n", p);
printf("%x\n", p1);
system("pause");
return 0;
}
四.free(释放空间)
函数原型:
free(void* pointer);
free的参数必须要不时空,要不然就必须是malloc,calloc,realloc中返回值。
注意:在使用malloc,calloc,realloc进行内存分配后一定要进行释放空间。
五.内存空间
以上的操作都是在堆上进行