C语言动态存储分配
在程序运行时,分配“堆区”的存储空间。
为了动态地分配存储空间,需要调用三种内存分配函数的一种,这些函数都声明在<stdlib.h>
头文件中。
- malloc 函数——分配内存块,但是不对内存块进行初始化。
- calloc 函数——分配内存块,并且对内存块进行清零。
- realloc 函数——调整先前分配的内存块大小。
在这三种函数中,malloc函数是最常用的一种。因为 malloc 函数不需要对分配的内存块进行清零,所以它比 calloc 函数更高效。
当为申请内存块而调用内存分配函数时,函数会返回void *
类型的值。
指向任意类型对象的指针能隐式转换成指向 void 的指针。
空指针
当调用内存分配函数时,如果找不到满足我们需要的足够大的内存块,函数会返回空指针(null pointer)。
空指针是不指向任何地方的指针,这是一个区别于所有有效指针的特殊值。
C语言中,空指针用名为 NULL 的宏来表示。
malloc 函数
函数原型:
void * malloc(size_t size);
malloc 函数分配 size 个字节的内存块,并且返回指向该内存块的指针。
注意,size 的类型是 size_t,这是在C语言库中定义的无符号整数类型。
/* 分配一个整型数的存储空间 */
int *p = malloc(sizeof(int));
/* 连续分配N个整型数的存储空间,即数组 */
int *p = malloc(N * sizeof(int));
/* 连续分配N+1个字符型的存储空间,即字符串 */
char *c = malloc((N+1)*sizeof(char)); //加上结束符
char *c = malloc( (strlen(str)+1)*sizeof(char) );
calloc 函数
函数原型:
void * calloc(size_t nmenb,size_t size);
calloc 函数为 nmemb 个元素的数组分配内存空间,其中每个元素的长度都是 size 个字节。
在分配了内存之后,calloc 函数会通过把所有位设置为 0 的方式进行初始化。
例如, calloc 函数调用:
/*为N个整数的数组分配存储空间,并为所有整数初始化为0*/
int *p = calloc(N,sizeof(int));
realloc 函数
函数原型:
void * realloc(void *ptr,size_t size);
当调用 realloc 函数时,ptr 必须指向先前通过 malloc、calloc或 realloc 的调用获得的内存块。size 表示内存块的新尺寸,新尺寸可能会大于或小于原有尺寸。
C标准列出了几条关于 realloc 函数的规则:
- 当扩展内存块时,realloc 函数不会对添加进内存块的字节进行初始化。
- 如果 realloc 函数不能按要求扩大内存块,那么它会返回空指针,并且在原有的内存块中的数据不会发生改变。
- 如果 realloc 函数被调用时以空指针作为第一个实际参数,那么它的行为就将像 malloc 函数一样。
- 如果 realloc 函数被调用时以0作为第二个实际参数,那么它会释放掉内存块。
在要求减少内存块大小时,realloc 函数应该在原先的内存块上直接进行缩减,而不需要移动存储在内存块中的数据。
同理,扩大内存块时也不应该对其进行移动。如果无法扩大内存块,realloc 函数会在别处分配新的内存块,然后把旧块中的内容复制到新块中。
free 函数
函数原型:
void free(void *ptr);
用于释放 ptr 指向的不再需要的内存块,将 malloc 函数或 calloc 函数返回的指针作为参数,传给 free 函数以释放内存。
关于动态地分配存储注意的问题
问题1:以下代码生成此警告,因为如果内存不足,则 malloc 调用可能会返回 NULL:
#include <stdlib.h>
void f()
{
char *p = ( char * ) malloc( 10 );
*p = '\0';
free( p );
}
若要更正此警告,请检查指针以获取 NULL 值,如以下代码所示:
#include <stdlib.h>
void f( )
{
char *p = ( char * )malloc ( 10 );
if ( p != NULL )
{
*p = '\0';
free( p );
}
}
问题2:将返回值从 realloc 赋给 x。如果 realloc 失败并返回 null 指针,则不会释放指向 x 的原始内存:
#include <stdlib.h>
void f()
{
char *x = (char *) malloc(10);
if (x != NULL)
{
x = (char *) realloc(x, 512);
free(x);
}
}
若要解决此问题,可以创建一个临时变量来存储 realloc 的返回值。 此更改允许在失败时 realloc 安全地释放以前分配的内存:
#include <stdlib.h>
void f()
{
char *x = (char *) malloc(10);
if (x != NULL)
{
char *temp = (char *) realloc(x,512);
if (temp != NULL)
{
x = temp;
}
free(x);
}
}