动态分配内存函数:malloc(),calloc(),realloc(),以及memset(),free() 详细总结

以下资料大部分来源网络,个人进行了汇总和添加。

 

内存可分为下面几个类别:


堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的,变量生命长度:函数结束即释放内存。


堆区(heap):一般由程序员分配与释放,即程序员不释放,程序结束时可能由操作系统回收(C/C++没有此等回收机制,Java/C#有),注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。


全局区(静态区)(static):全局变量和静态变量的存储是放在一块儿的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。


文字常量区:常量字符串是放在这里的,程序结束后由系统释放。


程序代码区:存放函数体的二进制代码。


C 标准函数库提供了许多函数来实现对堆上内存管理,其中包括:malloc函数,free函数,calloc函数和realloc函数。使用这些函数需要包含头文件stdlib.h。它们的声明如下:


void * malloc(int n);
void free (void * p);
void *calloc(int n,int size);
void * realloc(void * p,int n);

以上函数对内存的操作都是堆上的内存,生命周期:程序员主掌生死,free()函数结束。


1.   malloc函数


malloc函数可以从堆上获得指定字节的内存空间,其函数声明如下:


void * malloc(int n);

malloc returns a void pointer to the allocated space, or NULL if there is insufficient memory available. To return a pointer to a type other than void, use a type cast on the return value. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item. Always check the return from malloc, even if the amount of memory requested is small.


其中,形参n为要求分配的字节数。如果函数执行成功,malloc返回获得n个字节的内存空间的首地址;如果函数执行失败,那么返回值为NULL。

由于 malloc函数值的类型为void型指针,因此,需要将其值类型强行转换后赋给任意类型指针,这样就可以通过操作该类型指针来操作从堆上获得的内存空间。


     需要注意的是,malloc函数分配得到的内存空间是未初始化的。(有可能申请到的内存空间之前被用过,里面存在垃圾数据,不初始化程序有安全隐患)

    因此,一般在使用该内存空间时,要调用另一个函数memset来将其初始化为全0。memset函数的声明如下:


    void * memset (void * p,int c,int n) ;


       该函数可以将指定的内存空间按字节单位置为指定的字符c。其中,p为要清零的内存空间的首地址,c为要设定的值,n为被操作的内存空间的字节长度。如果要用memset清0,变量c实参要为0。

 

malloc函数和memset函数的操作语句一般如下:

int * p=NULL;



p=(int *)malloc(sizeof(int));



if(p==NULL)



    printf(“Can’t get memory!\n”);



memset(p,0,siezeof(int));


注意:通过malloc函数得到的堆内存必须使用memset函数来初始化。c++中的new 使用更方便,1.会自动计算数据类型所需内存大小 2.返回相应类型指针值,无需type cast.

 
2. free()函数

       从堆上获得的内存空间在程序结束以后,系统不会将其自动释放(java有垃圾回收机制,会自动释放,c/c++没有),需要程序员来自己管理。一个程序结束时,必须保证所有从堆上获得的内存空间已被安全释放,否则,会导致内存泄露。


free函数可以实现释放内存的功能。其函数声明为:


void free (void * p);


    由于形参为void指针,free函数可以接受任意类型的指针实参。


    但是,free函数只是释放指针的指向的内容,表明指向的内存可以被别人使用,而该指针仍然指向原来指向的地方,此时,指针为野指针,如果此时操作该指针会导致不可预期的错误。安全做法 是:在使用free函数释放指针指向的空间之后,将指针的值置为NULL。
语句如下:


free(p);
p=NULL;
  

    free函数的注意几点:

    1.调用free释放掉所分配的内存后,表明该内存可以被别人使用,也就是说,其他地方调用malloc后,可以分配到该内存
                             

     2.关于free释放该内存后,该内存中的数据,我们只能认为是脏数据;也就是说以下几种可能:

                                    A 还是原来的值

                                    B 被清空为0,取决于平台和编译器的处理

                                    C 被别人分配去了,已经修改了值

    3.free(p)的一个错误理解:free(p)之后p的指针指向仍然是原来的内存地址,只是说告诉系统此内存可以被其他程序申请,不是说把p的指向给改掉了。

    这也是为什么free(p)要加一个p = NULL 的原因。

   例如: ,输出结果:hello     (释放后,还可以对p指向内存的数据进行输出.不过是危险操作)

注意:使用malloc函数分配的堆空间在程序结束之前必须释放。


3. calloc函数


calloc函数的功能与malloc函数的功能相似,都是从堆分配内存。其函数声明如下:


void *calloc(int n,int size);


函数返回值为void型指针。如果执行成功,函数从堆上获得size X n的字节空间,并返回该空间的首地址。如果执行失败,函数返回NULL。

该函数与malloc函数的一个显著不同时是,calloc函数得到的内存空间是 经过初始化的,其内容全为0。

即:

int * p=NULL;



p=(int *)malloc(sizeof(int));



memset(p,0,siezeof(int));


与这段效果一样

int *p=NULL;



p = (int *)calloc(1,siezeof(int));

 

calloc函数适合为数组申请空间(会自动初始化),可以将size设置为数组元素的空间长度,将n设置为数组的容量。


提示:calloc函数的分配的内存也需要自行释放。


4. realloc函数


realloc函数的功能比malloc函数和calloc函数的功能更为丰富,可以实现内存分配和内存释放的功能,其函数声明如下:


void * realloc(void * p,int n);


其中,指针p必须为指向堆内存空间的指针,即由malloc函数、calloc函数或realloc函数分配空间的指针。realloc函数将指针 p指向的内存块的大小改变为n字节。如果n小于或等于p之前指向的空间大小,那么。保持原有状态不变。

如果n大于原来p之前指向的空间大小:

1.如果 当前连续内存块足够 realloc 的话,只是将p所指向的空间扩大,并返回p的指针地址。

2.如果 当前连续内存块不够长度,再找一个足够长的地方,分配一块新的内存q,并将 p指向的内容 copy到 q,返回 q。并将p所指向的内存空间删除。

这样也就是说 realloc 有时候会产生一个新的内存地址 有的时候不会。所以在分配完成后。我们需要判断下 p 是否等于 q。并做相应的处理。

这里有点要注意的是要避免 p = (int *)realloc(p,2048); 这种写法。有可能会造成 realloc 分配失败后,p原先所指向的内存地址丢失。

正确写法:

              p = (int *)mallocsizeof(int)*24);

memset(p,0,sizeof(int)*24);
q
= (int *)realloc(p,sizeof(int)*48); //将p指向内存空间从24int扩充到48个int if(q != NULL)//realloc函数执行成功,将p释放,q为新内存指针 { free(p); p = NULL; }



注意:使用malloc函数,calloc函数和realloc函数分配的内存空间都要使用free函数或指针参数为NULL的realloc函数来释放。




注意:如果要使用realloc函数分配的内存,须使用memset函数对其内存初始化


下面要注意的几点是:


函数malloc()和calloc()都可以用来动态分配内存空间。 malloc()函数有一个参数,即分配的内存空间的大小,malloc在分配内存的时候会保留一定的空间用来记录分配情况,分配的次数越多,这些记录占 用的空间就越多。另外,根据malloc实现策略的不同,malloc每次在分配的时候,可能分配的空间比实际要求的多些,多次分配会导致更多的这种浪 费,当然,这些都跟malloc的实现有关; calloc()函数有两个参数,分别为元素的个数和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小。如果调用成功,它们都将返回所分配内 存空间的首地址。
函数malloc()和calloc()的主要区别是前者不能初始化所分配的内存空间,而后者可以。
realloc()可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或者缩小,原有内存中的内容将保持不变。当然,对于缩小,则被缩小的那一部分的内容会丢失。
realloc()并不保证调整后的内存空间和原来的内存空间保持同一内存地址,相反,relloc返回的指针很可能指向一个新地址。所以在代码中,我们必 须将relloc的返回值,重新赋值给p : p=(int *) realloc (p,sizeof(int)*15);

你可能感兴趣的:(malloc)