malloc()和free()的基本概念以及基本用法
malloc()
malloc() 的函数原型
原型: extern void *malloc(unsigned int num_bytes)。
头文件: #include
功能:分配长度为 num_bytes 字节的内存块。
当内存不再使用时,应使用free()函数将内存块释放。
举例:
#include<stdio.h>
#include<malloc.h>
int main()
{
char *p;
p = (char *)malloc(100);
if(p)
printf("Memory Allocated at: %x/n",p);
else
printf("Not Enough Memory!/n");
free(p);
return 0;
}
malloc() 的函数声明(函数原型)
void *malloc(int size);
malloc 向系统申请分配指定 size 个字节的内存空间。返回类型是 void 类型。void 表示未确定类型的指针,如果分配成功则返回指向被分配内存的指针,否则返回空指针NULL。C,C++规定,void* 类型可以强制转换为任何其它类型的指针。这个在 MSDN 上可以找到相关的解释,具体内容如下:
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.
malloc 与 new 的不同点
从函数声明上可以看出。malloc 和 new 至少有两个不同: new 返回指定类型的指针,并且可以自动计算所需要大小。
int *p;
p = new int; //返回类型为int* 类型(整数型指针),分配大小为 sizeof(int);
或:
int* parr;
parr = new int [100]; //返回类型为 int* 类型(整数型指针),分配大小为 sizeof(int) * 100;
而 malloc 则必须由我们计算要字节数,并且在返回后强行转换为实际类型的指针。
int* p;
p = (int *) malloc (sizeof(int));
第一、malloc 函数返回的是 void 类型,如果你写成:p = malloc (sizeof(int)); 则程序无法通过编译,报错:“不能将 void 赋值给 int 类型变量”。所以必须通过 (int ) 来将强制转换。
第二、函数的实参为 sizeof(int) ,用于指明一个整型数据需要的大小。如果你写成:
int* p = (int *) malloc (1);
代码也能通过编译,但事实上只分配了1个字节大小的内存空间,当你往里头存入一个整数,就会有3个字节无家可归,而直接“住进邻居家”!造成的结果是后面的内存中原有数据内容全部被清空。
malloc 也可以达到 new [] 的效果,申请出一段连续的内存,方法无非是指定你所需要内存大小。
比如想分配100个int类型的空间:
int* p = (int *) malloc ( sizeof(int) * 100 ); //分配可以放得下100个整数的内存空间。
另外有一点不能直接看出的区别是,malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的。
除了分配及最后释放的方法不一样以外,通过malloc或new得到指针,在其它操作上保持一致。
malloc(0) 搞事情
在C语法中, malloc(0)无疑是对的,并且也一定是分配了对应的内存空间,但是有一点可能理解有点困难,那就是分配了内存空间为0的内存大小,内存空间大小是0的时候由于无法存储内容,导致无法被使用,对于malloc而言也就是返回了一个让你无法使用的指针;
在操作系统的层面,由于操作系统在内存管理的时候会将内存分成2部分:棧内存和堆内存,棧和堆除了数据结构上的区别之外,对于棧而言,棧有自己的机器指令而堆没有,而malloc分配的是堆内存,由于堆没有自己的机器指令,所以要由系统自己写算法来管理这部分内存,而最常见的管理是用链表来管理,在每片被分配的内存前加一个表头,里面存储了被分配的内存的起始位置和大小,而malloc函数返回的指针就是表头里的起始指针,这个地址由一系列的算法获得,通常而言不会分配0空间大小,一旦内存分配成功就会返回一个有效的指针,对于分配0空间来说,算法已经算出可用内存的起始地址,但是你占用0空间,所以对那个指针操作就是错误的,操作系统一般不知道其终止地址,因为有占用大小就可以推出终止地址,还有就是即使分配0空间也要释放它,其实是释放的链表结点。还有,返回的指针是可用地址的起始地址,可用大小是固定的,在VC6下是56字节,这个大小可能就是链表的大小。既然malloc另外分配内存来维护该内存块(算法链表占用大小),也就是说分配来用于维护该内存块的内存的大小也是有限的,那么到底是多少呢?
#include
int main()
{
char *ptr;
ptr = malloc(0*sizeof(char));
if (NULL == ptr)
printf("got a NULL pointer\n");
else
{
printf("got a Valid pointer\n");
// 有10个a,另外有一个字节用于保存''\0'
strcpy(ptr,"aaaaaaaaaa");
//printf("the value at %X is:%c\n",ptr,*ptr);
printf("the string at %x is :%s\n",ptr, ptr);
// free(ptr);
}
return 0;
}
此时没有把 free(ptr)编译进来,同样会发生异常,程序输出很多个10个a,如果把 free(ptr); 编译进来,就会发生运行错误!
malloc() 的总结
malloc()函数其实就在内存中找一片指定大小的空间,然后将这个空间的首地址范围给一个指针变量,这里的指针变量可以是一个单独的指针,也可以是一个数组的首地址,这要看 malloc() 函数中参数 size 的具体内容。我们这里 malloc 分配的内存空间在逻辑上连续的,而在物理上可以连续也可以不连续。对于我们程序员来说,我们关注的是逻辑上的连续,因为操作系统会帮我们安排内存分配,所以我们使用起来就可以当做是连续的。
那么在理解了malloc的基本内容之后,对于malloc、alloc、calloc、realloc的区别浅显的理解,请移步:对于malloc、alloc、calloc、realloc的区别浅显的理解.
free()
malloc, alloc, free 是 c 定义的一组内存管理的 API 函数,free 可以释放 calloc, malloc, realloc 动态分配的空间,当你调用 malloc、alloc 分配内存时,不仅仅是从堆里面分配得到了可用内存,实际上内存管理子系统还会维护了内存列表(你定义的普通指针不会出现这个列表中)。
free() 的函数原型
而对于使用 new, GlobalAlloc 之类的方式分配的内存可不可以使用 free 呢。我的回答是,尽量不要,大部分情况都会带来风险,这里面涉及 new, malloc, GlobalAlloc, HeapAlloc, LocalAlloc,VirtualAlloc 等函数的区别。
那么对于自己定义的普通指针呢,首先要说一下,你要释放的不是你定义的指针,而是你定义的指针指向的空间。至于你定义的普通指针是不是可以通过 free 释放,这个要看情况。如果你定义的指针指向动态分配的地址空间,则可以使用 free 释放指针指向的这段空间;否则,就不能使用 free 释放指针指向的空间。
下面举个例子:
current = head
while (current != null )
{
free(current);
current = current->next;
}
printf(“Bye!\n”);
head 是一个指向一个链表头元素的指针,这段代码的作用是释放这个链表 malloc 的内存。
current 既然已经 free 了,怎么还可以使用 current = current->next 呢,而且并没有报错!
上面示例代码的错误原因:
1.free只是释放了malloc所申请的内存,并没有改变指针的值。
2.由于指针所指向的内存空间已经被释放,所以其他代码有机会改写其中的内容,相当于该指针从此指向了自己无法控制的区域,也成为野指针(野指针指指向一个已删除的对象或未申请访问受限内存区域的指针。与空指针不同,野指针无法通过简单地判断是否为NULL避免)。
3.为了避免错误,所以最好在free之后,使指针指向NULL。