内存动态分配函数
主要涉及malloc/calloc/realloc和free四个函数,头文件:#include <stdlib.h>
(1)malloc
函数原型:
void *malloc(size_t size);
说明
向系统申请分配一个长度为size大小字节的内存块,并返回内存块的起始地址。
返回值
如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。
演示示例:
#include <stdio.h>
#include <stdlib.h>
int main()
{
/* 1. malloc返回的是void *类型,在需要时候的时候要做一个适合目标指针类型的转换,比如这里转换成int *;
如果是 char *p_a = (char *)malloc(10);
*/
int *p_a = (int *)malloc(10 * sizeof(int));
//int *p_a = (int *)malloc((size_t)(1024*1024*1024*2)); //执行此句就会执行失败,
//所以malloc之后一定要做一个是否申请内存成功的判断
if (!p_a)
{
printf("malloc 失败, p_a = %p\n", p_a);
exit(1);
}
// 2.malloc分配的内存它的值是随机
printf("malloc刚申请的一段内存其值是:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p_a + i));
}
printf("\n");
// 赋初值
for (int i = 0; i < 10; i++)
{
*(p_a + i) = i;
}
printf("初始化后的数据:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p_a + i));
}
printf("\n");
printf("free前的p_a = %p\n", p_a);
free(p_a);
//p_a = NULL;
// 3. 测试free后指向的内存区域数值
printf("free后的p_a = %p\n", p_a);
printf("测试free后指向的内存区域数值:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p_a + i));
}
printf("\n");
/*
printf("测试free还往其指向的内存空间写数据:\n");
for (int i = 0; i < 10; i++)
{
*(p_a + i) = i; //往free后的空间写数据,程序出错
}
*/
printf("程序结束\n");
return 0;
}
使用结论:
(1)malloc返回的是void *类型,在需要时候的时候要做一个适合目标指针类型的转换,
比如char *p_a = (char *)malloc(10);
(2)malloc分配的内存它的值是随机;比如分配的字符串空间char *p_a = (char *)malloc(10),如果我们直接操作strlen(p_a)则结果不确定。可以用memset去赋予初值。
(3)在free后就不要再去操作该段内存区(不管是读还是写)。
(4)malloc后要判断内存是否申请成功。
(2)calloc
函数原型:
void *calloc(size_t n, size_t size);
返回值
如果分配成功则返回指向被分配内存的指针(此存储区中的初始值已被设置为0),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。
与malloc的区别
(1)传入参数不一样;
比如申请同样10个int的内存空间
int *p_a = (int *)malloc(10*sizeof(int));
int *p_b = (int *)calloc(10, sizeof(int));
(2)calloc申请的内存是有将其值初始化为0,而malloc则是随机的;
和malloc相同之处
(1)都是要用free去释放申请的内存;
(2)该段内存被free后都不要再去操作该段内存(不管读还是写)
什么使用calloc或malloc呢?
(1)如果你想把申请的内存区域初始化为0,可以使用calloc;
初始化为0是要花时间的。
(2)如果你的应用在内存申请后会手动赋予值,可以使用malloc。
即使你用了malloc,但是想把数据初始化为0,则用memset去初始化就可以了。
代码演示:
#include <stdio.h>
#include <stdlib.h>
int main()
{
//int *p_a = (int *)malloc(10*sizeof(int));
// 1. calloc的参数和malloc有区别
int *p_a = (int *)calloc(10, sizeof(int));
if (!p_a)
{
printf("malloc 失败, p_a = %p\n", p_a);
exit(1);
}
// 2. calloc申请的一段内存空间其值都被初始化为0
printf("calloc刚申请的一段内存其值是:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p_a + i));
}
printf("\n");
for (int i = 0; i < 10; i++)
{
*(p_a + i) = i;
}
printf("初始化后的数据:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p_a + i));
}
printf("\n");
printf("free前的p_a = %p\n", p_a);
free(p_a);
//p_a = NULL;
// 3. 测试free后指向的内存区域数值
printf("free后的p_a = %p\n", p_a);
printf("测试free后指向的内存区域数值:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p_a + i));
}
return 0;
}
结果:
(3)realloc
函数原型
void* realloc(void* ptr, unsigned newsize);
给一个已经分配了地址的指针重新分配空间,参数ptr为原有的空间地址,newsize是重新申请的地址长度。
返回值
如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。
说明
realloc可以对给定的指针所指的空间进行扩大或者缩小,无论是扩大或是缩小,原有内存的中内容将保持不变。当然,对于缩小,则被缩小的那一部分的内容会丢失。
realloc并不保证调整后的内存空间和原来的内存空间保持同一内存地址。
比如
相反,realloc返回的指针很可能指向一个新的地址。
图示理解:比如要重新分配已经malloc的内存
代码演示:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p_a = (int *)malloc(10 * sizeof(int)); //申请10*sizeof(int)字节的空间
// 1. 给p_a指向的内存做初始化
for (int i = 0; i < 10; i++)
{
*(p_a + i) = i; // 赋值
}
printf("\n初始化p_a指向内存的数值:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", *(p_a + i));
}
// 1. 扩充数据,从10个int变为15个int
printf("\n扩充之前p_a = %p\n", p_a);
p_a = (int *)realloc(p_a, 15 * sizeof(int));
printf("扩充之后p_a = %p\n", p_a);
printf("\n扩充之后的的数值:\n"); // 扩充后地址空间是很有可能发生变化的
for (int i = 0; i < 15; i++)
{
printf("%d ", *(p_a + i)); // 原有的内容的数值没有变化, 但扩充之后的数值是不确定的
}
// 2. 缩减数据
p_a = (int *)realloc(p_a, 5 * sizeof(int));
printf("\n缩减之后p_a = %p\n", p_a);
printf("\n缩减之后的的数值:\n"); //
for (int i = 0; i < 15; i++)
{
printf("%d ", *(p_a + i)); // 缩减内存后被缩减部分的数据有变化
}
// 测试越界使用
for (int i = 0; i < 10; i++)
{
*(p_a + i) = i; // 赋值
}
free(p_a);
p_a = NULL; // 内存释放后将p_a置为NULL,这是良好的编程习惯
printf("程序结束\n");
return 0;
}
结果:
注意:
* (1)realloc扩充内存时,原有的数据不变,但扩充的内存的数值是不确定的;
* (2)扩展内存后其指针和原来可能不一样;
* (3)缩减内存后只能使用其指定长度的数据,不要越界使用。
思考:
使用malloc,memcpy和free去实现一个类似realloc的函数?
//待补充
(4)free
函数原型:
void free(void *ptr)
释放ptr指向的存储空间(ptr指向的内存需要由malloc/calloc或realloc动态申请)。
说明:
在释放内存后,建议将指针置为NULL,这是良好的编程习惯,如