realloc和malloc和calloc的区别和用法(个人学习笔记)
思路:先讲下realloc malloc 和 calloc 有啥用法
有一点需要说明的是,他们都是用来开辟内存空间的,其中malloc是在栈区中分配一个内存空间,calloc与realloc都
是在堆区中分配内存的。访问栈中的内存一般都会比堆区的快,但是有一点是,栈区的内存容量是比较小的,因此要
注意栈区的内存溢出等问题和越界等问题。
在我们学习的时候一般都是先接触的是malloc 然后再接触calloc和realooc
所以思路:malloc -- > calloc --->realloc
malloc
原型:void* malloc(unsigned size); void* calloc(size_t nelem, size_t elsize);
用法:#include <stdlib.h>
功能:在堆区开辟一个可控的内存
说明:size 为需要分配的内存空间的bai大小,以字节(Byte)计。如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。
当内存不再使用时,应使用free()函数将内存块释放。
注意:这个是开辟的是一个新的未初始化的内存,要注意初始化和赋值
#include <stdio.h>
#include <windows.h>
void TextMalloc()
{ /*由于malloc 返回的是void*类型 或者 unsigned int 类型*/
int * p = (int*)malloc(10*sizeof(int)) ; // 在这里申请使用内存,(int*)转换成int*类型
int i;
for (i = 1; i< 10;i++)
{
p[i] = i;
printf("%d\n",p[i]);
}
free(p);
}
int main(void)
{
TextMalloc();
system("pause");
}
用malloc的时候要注意的几点是:
1.返回的是开辟空间的首地址
2.返回的类型是void* 类型 ,可以随便转换类型,所以灵活使用,使用完要返还给内存,用free函数
3.不仅能开辟常用类型(int char double等),还能开辟组合类型(结构体等)
4.申请不一定成功,该函数申请失败返回NULL,故判断空间指向指针为NULL是申请不成功,不能使用 // 可以以下代码用来检测
if (p != NULL)
{
free(p);
printf("OK\n");
}
5.即使我们用了free函数将指针所指向空间释放了,但是指针还保留有开辟空间的起始地址,当我们进行解引用时,就会产生指针所指空间不属于自己,但我们去使用了,导致一些未知性错误(free后指针置NULL)
if (p != NULL)
{
free(p);
printf("OK\n");
}
p = NULL ; // 置空
6.动开辟的空间是连续的,同数组一样使用,都要防止越界访问 如下
void Text()
{
int* p=(int *)malloc(10*sizeof(int));
int i=0;
for(i=0;i<10;i++)
{
*(p+i)=i;
}
if(p==NULL)
{
printf("%s\n",strerror(errno));
exit(1);
}
free(p);
p=NULL;
if(p==NULL)
{
printf("%s\n",strerror(errno));
exit(1);
}
}
int main(void)
{
// TextMalloc();
Text();
system("pause");
}
calloc
1.函数原型:void *calloc( size_t num, size_t size );
2。malloc 的注意事项也同样适用(如上),只不过calloc多了一个参数size_t num,
还有一个就是calloc分配了内存之后会将所分配的内存空间置零。(和malloc相比省
去了一个menset()函数)
int* p=(int *)calloc(10,sizeof(int)); // 前面的10是分配的个数,后面的是分配的大小
char* cp=(char*)=calloc(100,sizeof(char));
其他的就和malloc一样的啦
realloc
原型:extern void *realloc(void *mem_address, unsigned int newsize);
用法:#include <stdlib.h> 有些编译器需要#include <alloc.h>
功能:改变mem_address所指内存区域的大小为newsize长度。
说明:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。
当内存不再使用时,应使用free()函数将内存块释放。
注意:这里原始内存中的数据还是保持不变的。
由于个人的表述能力不行,附上一个大牛 的解释
1、如果有足够空间用于扩大mem_address指向的内存块,则分配额外内存,并返回mem_address
这里说的是“扩大”,我们知道,realloc是从堆上分配内存的,当扩大一块内存空间时, realloc()试图直接从堆上现存的数据后面的那些字节中获得附加的字节,如果能够满足,自然天下太平。也就是说,如果原先的内存大小后面还有足够的空闲空间用来分配,加上原来的空间大小= newsize。那么就ok。得到的是一块连续的内存。
2、如果原先的内存大小后面没有足够的空闲空间用来分配,那么从堆中另外找一块newsize大小的内存。
并把原来大小内存空间中的内容复制到newsize中。返回新的mem_address指针。(数据被移动了)。
老块被放回堆上。
具体的代码就是这样子的
// realloc.c
#include <syslib.h>
#include <alloc.h>
main()
{
char *p;
clrscr(); // clear screen
p=(char *)malloc(100);
if(p)
printf("Memory Allocated at: %x",p);
else
printf("Not Enough Memory!/n");
getchar();
p=(char *)realloc(p,256);
if(p)
printf("Memory Reallocated at: %x",p);
else
printf("Not Enough Memory!/n");
free(p);
getchar();
return 0;
}
#include <malloc.h>
char *p,*q;
p = (char * ) malloc (10);
q=p;
p = (char * ) realloc (p,20);
// 这里我要进行补充的是
relloc 和 malloc 返回都是void * 类型,但是realooc需要一个类型转换(这一点和malloc有点不一样,malloc在有的编译器里会自动给你进行类型转换)
在一位CSDN大佬(我的算不算)的文章中一小段摘要中:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
/*realloc原型是extern void *realloc(void *mem_address, unsigned int newsize);*/
/*指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)。*/
void TextRelloc()
{
int aaa ;
int *num3 = (int*)malloc(sizeof aaa);
int i ;
for (i = 0;i< 10;i++)
{
num3[i] = i;
}
int *num = (int*)realloc(num3,10*sizeof(char));
for (i = 0;i< 10;i++)
{
printf("%d\n",num3[i]); /*得到的结果是0 但是要知道,malloc是不会置于0的*/
}
free(num3);
}
/*malloc 和 calloc 都是在栈区分配空间的,relloc是在堆区分配空间的*/
int main(void)
{
TextRelloc();
system("pause");
}
假设整个堆其中都没有不论什么一处的内存可以满足realloc的需求。则此次分配失败,返回值为NULL。,可以看到我给定的内存空间太大导致分配不成功,后面的代码失效