C库函数malloc,calloc,realloc,free的用法
*此博客仅用来记录博主的C语言学习路程,如果内容有帮到你,那我将感到十分的荣幸*
malloc用法
声明:
void *malloc(size)
分配所需的内存空间,并返回一个指向它的指针。(空类型,必要时可以转换)
参数(一个)
size
内存块的大小,以字节为单位。
- 案例---------用malloc动态创造一个数组
#include<stdio.h>
int main()
{
int num;
printf("Please enter a number:__\b\b");
scanf_s("%d",&num);
int* p = (int *)malloc(sizeof(int) * num);
for (int i = 0; i < num; i++)//按照数组的方式访问
{
p[i] = i;
printf("%3d\n",p[i]);
}
free(p);//用完了一定要释放内存
return 0;
}
解释:以上的代码片用malloc
函数动态分配了sizeof(int) * num
个字节,因为malloc函数返回值是一个空指针的类型,所以我在上述代码中将其类型转换成(int *)
类型的指针,并用int
类型的指针变量p
接收,因为num
的值是用户输入的,所以下一步用一个for
循环初始化一维数组,然后将其打印输出,最后释放内存,这一步必不可少,请读者务必注意,博主将在后文分析不释放内存的后果。
calloc用法
声明:
void *calloc(nitems,size)
参数(两个):
nitems -- 要被分配的元素个数。
size -- 元素的大小。(以字节为单位)
- 案例1-------用
calloc
动态创造一个数组
#include<stdio.h>
#include<Windows.h>
#include<stdlib.h>
int main()
{
int num;
printf("please enter a number:\n");
scanf_s("%d",&num);
/*double* p = (double*)malloc(sizeof(double) * num);*/
double* p = (double*)calloc(num, sizeof(double));//calloc用法跟malloc差不多,calloc前面两个参数相乘等于malloc的参数
for (double i = 0; i < num; i++)
{
p[(int)i] = i+1;//对于指针指向的内存,用下标访问
printf("%f\n",p[(int)i]);
}
free(p);//释放内存
}
解释:这次的案例跟上一个整体相当,但有两点不一样,第一个就是用calloc
动态分配内存空间,另一个是创建了一个浮点型的数组,然后根据用户输入的num
值循环初始化数组,生成1~num
之间的数据,由于数组是浮点型的,但是数组的下标却是整型的,所以要进行一次类型转换,如上图,p[(int)i] = i+1
,最后释放内存(千万别忘了!非常重要!!),至于calloc
与malloc
有什么不一样,我们后面会慢慢分析。
realloc用法
声明:
void *realloc(void *ptr, size_t size)
尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。
参数:
ptr --------- 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc
进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
size -------- 内存块的新的大小,以字节为单位。
如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。
- 案例:
#include<stdio.h>
#include<Windows.h>
#include<stdlib.h>
int main()
{
int num;
printf("Please enter a number:__\b\b");//数组开始的长度
scanf_s("%d",&num);
int* p = (int*)malloc(sizeof(int) * num);
printf("初始地址是:%p\n",p);//打印初始地址-----由malloc分配
for (int i = 0;i<num;i++)//输出由malloc动态分配的数组
{
p[i] = i + 1;
printf("%d %x\n",p[i],&p[i]);
}
int newnum;
printf("Please enter a number again:__\b\b");//数组增加后的长度
scanf_s("%d",&newnum);
int* p1 = (int *)realloc(p,newnum);//realloc返回值是一个空指针,这里将它转换成int型
printf("重新分配的地址是:%p\n",p1);//打印由realloc分配的地址,与malloc分配的相同
for (int i = 0; i < newnum; i++)//输出重新分配内存块的数组
{
p1[i] = i + 1;
printf("%d\n",p1[i]);
}
//free(p);
return 0;
}
解释:以上的代码主要分为两个部分,前半部分用malloc函数动态分配内存创造一个一维数组,但是有时候我们可能会觉得已经创造的数组长度不能满足我们的实际需要,我们想要扩大数组的长度怎么办?这个时候代码的后半部分就是解决这个问题的,realloc函数可以额外扩展内存,它主要通过两种方式扩展内存,具体细节我们稍后再谈,因为realloc跟malloc函数和calloc函数一样,返回值是一个void类型的指针,但我们创造的数组是int类型的,因此在这里我们要进行一次类型转换,并用int类型的指针p1接收,然后我们用scanf_s重新定义改变后数组的长度,为了比较扩展内存后的数组与原数组的区别,我分别打印了扩展前和扩展后数组的首地址,结果是地址相同,最后,输出扩展内存后的数组
malloc
,calloc
,realloc
的区别
malloc,calloc都是分配内存
malloc根据大小,calloc根据元素大小还有个数
malloc分配后不会初始化,calloc会把要分配的那块内存全部初始化为0
realloc就是内存不够的情况下,扩展内存
malloc
和calloc
的主要区别就是calloc
会初始化要分配的那块内存,全部初始化为0
接下来我们转到调试里面打开内存窗口
输入地址:0FFDC040
我们按照4字节整数,带符号来显示:
我们可以看到,指定区域里面全部被初始化为0
- 案例
#include<stdio.h>
int main()
{
/*
malloc,calloc都是分配内存,malloc根据大小,calloc根据元素大小还有个数
malloc分配后不会初始化,calloc会把要分配的那块内存全部初始化为0
realloc就是内存不够的情况下,扩展内存
*/
int num;
printf("Please enter a number:\n");
scanf_s("%d",&num);
int* p = (int*)malloc(sizeof(int) * num);//malloc动态分配
printf("初次动态分配的数组的首地址:%p\n",p);
for (int i = 0; i < num; i++)//初始数组
{
p[i] = i;
printf("%d\n",p[i]);
}
int newnum;
printf("请输入更改后数组的长度:");
scanf_s("%d",&newnum);
int* p1 = (int*)realloc(p,newnum);//realloc动态分配
/*
realloc重新分配内存,如果可以扩展就在原内存块的基础上往后扩展一部分区域;
扩展就是在原来地址后面增加内存
否者重新开辟一片内存,并且回收原来的内存,而且在回收之前拷贝原来的内容
*/
printf("使用realloc动态分配后数组的首地址:%p\n",p1);
for (int i = num; i < newnum; i++)//增加长度后的数组
{
p1[i] = i;
printf("%d\n",p1[i]);
}
free(p1);//释放内存
return 0;
}
古人云:“无规矩不成方圆”
虽然内存分配很方便,但凡事都要有个度,下面这个例子就是演示内存分配危害的例子
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
int main1()
{
while (1)
{
void* p = malloc(1024*1024*100);//malloc返回空类型的指针,为其分配100M内存
Sleep(1000);
free(p);//根据地址释放内存
Sleep(1000);
}
return 0;
}
int main2()
{
void* p = malloc(0xffffffff);//如何检测内存是否分配成功
if (p == NULL)//为空就是没有分配成功
{
printf("内存分配不成功\n");
}
return 0;
}
int main3()
{
int*p=(int *)malloc(sizeof(int));//分配一个元素大小的字节
*p = 5;
printf("我有%d元\n",*p);
free(p);//释放内存
int* p1 = p;//内存根据地址来释放
free(p1);//内存不可以反复释放
return 0;
}
mian1函数演示了内存的定时分配与释放,如上图所示。
main2函数演示了如果分配的内存过大的话,会导致不成功,如上图所示
main3函数展示了内存不能反复释放
free()函数根据地址来释放内存,即使重新定义了一个指针变量,但只要地址相同,就会报错
所以,根据软件工程规范,释放内存后,将指针赋值为空
free(p);
p = NULL;
但是有的人对释放后的内存充满了好奇,固执的还想要访问原来数组的元素,那么我们看看这将会发生什么事情
此时指针的地址已经为0000000
了,因为被赋值为NULL
但是如果不小心没有赋值为NULL
,而且又访问量原数组中的元素会产生什么呢?
就会产生一堆垃圾数据,毫无意义。
所以,综上分析,我们要做有意义的事情,不要给博主我添乱【Dog】
来源:CSDN
作者:Masschusates
链接:https://blog.csdn.net/qq_44486550/article/details/104117848