内容简介:这两个函数是一对好朋友,几乎是形影不离。有今天跟大家聊聊在进行下面话题之前,我们先回忆一下
这两个函数是一对好朋友,几乎是形影不离。有 malloc
的地方就应该有 free
的存在。
今天跟大家聊聊 malloc
和 free
这对好基友,这两个函数都是对堆内存进行管理的函数,另外还有 calloc
、 realloc
、 reallocf
、 valloc
等堆内存管理函数。
void *
在进行下面话题之前,我们先回忆一下 void *
是什么?
void *
表示未确定类型的指针。C/C++规定, void *
类型可以强制转换为任何其它类型的指针。
void *
也被称之为无类型指针, void *
可以指向任意类型的数据,就是说可以用任意类型的指针对 void *
赋值,如下示例:
void *p1; int *p2; p1 = p2;
但一般不会反过来使用,如下示例在有些编译器上面可以编译通过,有些就不行:
void *p1; int *p2; p2 = p1;
可以修改一下代码,将 void *
转换为对应的指针类型再进行赋值,如下示例:
void *p1; int *p2; p2 = (char *)p1;
由于 GNU 和 ANSI 对 void *
类型指针参与运算的规定不一样,所以为了兼容二者并且让程序有更好的兼容性,最好还是将 void *
转换为有明确类型的指针再参与运算,如下示例。
void *pd; char *pc = (char *)pd; pc ++; pc += 1;
malloc
函数原型:
void * malloc(size_t size);
malloc
向系统申请分配指定 size
个字节的内存空间,即 malloc
函数用来从堆空间中申请指定的 size
个字节的内存大小,返回类型是 void *
类型,如果成功,就会返回指向申请分配的内存,否则返回空指针,所以 malloc
不保证一定成功。
查看函数手册或者直接在 linux 、macOS 上面直接 man malloc
会显示对应的函数信息:
The malloc() function allocates size bytes of memory and returns a pointer to the allocated memory. If successful, malloc() function return a pointer to allocated memory. If there is an error, they return a NULL pointer and set errno to ENOMEM.
另外需要注意一个问题,使用 malloc
函数分配内存空间成功后, malloc
不会对数据进行初始化,里边数据是随机的垃圾数据,所以一般结合 memset
函数和 malloc
函数 一起使用。
int *arr; arr = (int *)malloc(10 * sizeof(int)); if (NULL != arr) { memset(arr, 0, 10 * sizeof(int)); printf("arr: %p\n", arr); }
char *arr; arr = (char *)malloc(10 * sizeof(char)); if (NULL != arr) { memset(arr, '\0', 10 * sizeof(char)); printf("arr string: %s\n", arr); }
为了安全起见,建议可以考虑使用 calloc()
函数,后面会提到它。
函数 free
、 malloc
、 calloc()
都被包含在 stdlib.h
文件中。
free
函数原型:
void free(void *ptr);
我们知道在 C 语言中, 堆上的内存空间不会自动释放(Java 有自动回收机制,而 C 语言没有),直到调用 free
函数,才会释放堆上的存储空间,即 free
函数会释放指针指向的内存分配空间。
下面是函数手册查到关于 free
函数的资料:
The free() function deallocates the memory allocation pointed to by ptr. If ptr is a NULL pointer, no operation is performed.
对于 free
函数我们要走出一个误区,不要以为调用了 free
函数,变量就变为 NULL
值了。本质是 free
函数只是割断了指针所指的申请的那块内存之间的关系,并没有改变所指的地址(本身保存的地址并没有改变)。如下示例:
char *pchar = (char *)malloc(10 * sizeof(char)); if (NULL != pchar) { strcpy(pchar, "blog"); /* pchar所指的内存被释放,但是pchar所指的地址仍然不变 */ free(pchar); /* 该判断没有起到防错作用,此时 pchar 并不为 NULL */ if (NULL != pchar) { strcpy(pchar, "it"); printf("pchar: %s", pchar); } }
正确且安全的做法是对指针变量先进行 free
然后再将其值置为 NULL
,如下下面示例:
char *pchar = (char *)malloc(10 * sizeof(char)); if (NULL != pchar) { strcpy(pchar, "blog"); /* pchar所指的内存被释放,但是pchar所指的地址仍然不变 */ free(pchar); /* 将其置为 NULL 值 */ pchar = NULL; /* 该判断没有起到防错作用,此时 pchar 并不为 NULL */ if (NULL != pchar) { strcpy(pchar, "it"); printf("pchar: %s", pchar); } }
malloc、free 小结
1、连续内存块
malloc
函数申请的是连续的一块内存,如果所申请的内存块大于目前堆上剩余内存块,则内存分配会失败,函数返回 NULL
值。
注意:上面说的 堆上剩余内存块
不是所有剩余内存块之和,而是连续的内存。
2、双宿双飞才好
调用 malloc
函数多余 free
函数会发生内存泄漏,这个很好理解,因为申请过的内存没有被释放完。调用 malloc
函数少于 free
函数,肯定会出错。换句话说,在程序中 malloc
的使用次数务必要和 free
相等,否则必有隐患或者发生错误。
如下面的例子 free
两次指针变量就会在运行时报错: malloc: *** error for object 0x10071be90: pointer being freed was not allocated
char *pchar = (char *)malloc(10 * sizeof(char)); free(pchar); free(pchar);
对指针变量进行 free
之后,一定要记得对其赋值为 NULL
,否则该指针就是一个野指针,这个在上面已经说明。
3、0字节的内存有毒
使用 malloc
函数也可以申请0字节的内存,该函数的返回值并不是 NULL
,而是返回一个正常的内存地址,所以如果使用这种方式申请的内存很危险,如下面的例子,指针 pchar
是一个使用 malloc
函数创建的占用0字节的内存空间的一个指针变量, if (NULL == pchar)
并没有生效,而是执行了 else
语句中的代码,执行到 strcpy(pchar, "blog")
就直接崩溃了。
char *pchar = (char *)malloc(0); if (NULL == pchar) { printf("malloc 0 byte memory failed.\n"); } else { printf("malloc 0 byte successfully and pchar: %s.\n", pchar); pchar = "veryitman"; strcpy(pchar, "blog"); printf("pchar: %s.\n", pchar); }
calloc、realloc、reallocf、valloc
1、calloc 函数
void * calloc(size_t count, size_t size);
在堆上,分配 n*size
个字节,并初始化为0,返回 void *
类型,返回值情况跟 malloc
一致。
函数 malloc()
和函数 calloc()
的主要区别是前者不能初始化所分配的内存空间,而后者能。如果由 malloc()
函数分配的内存空间原来没有被使用过,则其中的每一位可能都是0;反之,如果这部分内存曾经被分配过,则其中可能遗留有各种各样的数据。也就是说,使用 malloc()
函数的程序开始时(内存空间还没有被重新分配)能正常进行,但经过一段时间(内存空间还已经被重新分配)可能会出现问题。
函数 calloc()
会将所分配的内存空间中的每一位都初始化为零,也就是说,如果你是为字符类型或整数类型的元素分配内存,那么这些元素将保证会被初始化为0;如果你是为指针类型的元素分配内存,那么这些元素通常会被初始化为空指针;如果你为实型数据分配内存,则这些元素会被初始化为浮点型的零。
The calloc() function contiguously allocates enough space for count objects that are size bytes of memory each and returns a pointer to the allocated memory. The allocated memory is filled with bytes of value zero.
2、realloc() 函数
void * realloc(void *ptr, size_t size);
重新分配堆上的 void指针
所指的空间为 size
个字节,同时会复制原有内容到新分配的堆上存储空间。
注意,若原来的 void指针
在堆上的空间不大于 size
个字节,则保持不变。
The realloc() function tries to change the size of the allocation pointed to by ptr to size, and returns ptr. If there is not enough room to enlarge the memory allocation pointed to by ptr, realloc() creates a new allocation, copies as much of the old data pointed to by ptr as will fit to the new allocation, frees the old allocation, and returns a pointer to the allocated memory. If ptr is NULL, realloc() is identical to a call to malloc() for size bytes. If size is zero and ptr is not NULL, a new, minimum sized object is allocated and the original object is freed. When extending a region allocated with calloc(3), realloc(3) does not guarantee that the additional memory is also zero-filled.
3、reallocf() 函数
void * reallocf(void *ptr, size_t size);
reallocf()
函数是由 FreeBSD 实现的,它会在任何情况下释放输入的指针(即使是再分配失败之后)。 reallocf()
一样会调用 realloc
函数,但是只有我们在获得空的指针之后才会调用 free
函数。
下面是 reallocf
函数具体的实现部分:
void * reallocf(void *p, size_t size) { void *ptr = realloc(p, size); if (!p) { free(p); } return ptr; }
The reallocf() function is identical to the realloc() function, except that it will free the passed pointer when the requested memory cannot be allocated. This is a FreeBSD specific API designed to ease the problems with traditional coding styles for realloc causing memory leaks in libraries.
4、valloc() 函数
void * valloc(size_t size);
这个函数是最少见也是最少用的一个函数。
malloc
或 realloc
返回的是以8字节对齐的内存地址,在64bits上是16字节对齐。然而 memalign
或 valloc
可以更大的粒度进行字节对齐。
valloc
是一个废弃的函数,分配 size
大小的字节,返回已分配的内存地址指针,其内存地址将是页大小(page size)的倍数,如果分配失败返回 NULL
。
The valloc() function allocates size bytes of memory and returns a pointer to the allocated memory. The allocated memory is aligned on a page boundary.
锄禾日当午,汗滴禾下土,五一节快乐~
以上所述就是小编给大家介绍的《双宿双飞的 malloc 和 free》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
计算机组成:结构化方法
坦嫩鲍姆 / 刘卫东 / 人民邮电出版社 / 2006-1 / 65.00元
本书采用结构化方法来介绍计算机系统,书的内容完全建立在“计算机是由层次结构组成的,每层完成规定的功能”这一概念之上。作者对本版进行了彻底的更新,以反映当今最重要的计算机技术以及计算机组成和体系结构方面的最新进展。书中详细讨论了数字逻辑层、微体系结构层、指令系统层、操作系统层和汇编语言层,并涵盖了并行体系结构的内容,而且每一章结尾都配有丰富的习题。 本书适合作为计算机专业本科生计算机组......一起来看看 《计算机组成:结构化方法》 这本书的介绍吧!