![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/392948bbfc47f43927bff69a3d1d8e66.png#pic_center)
引言——为什么使用动态内存分配
在声明数组时,你必须使用一个常量来指定数组的大小,但有时我们往往在程序运行时才知道数组所需的真正大小。
例如,一个用于计算学生成绩的程序需要一个数组来存储每个学生的成绩,但是每个班级的学生数量不同。在这种情况下我们就需要声明一个较大的数组,确保能容纳可能出现的最多元素。
但是,当程序需要的元素数量超过了声明的长度,显而易见的是声明更大的数组。但是巨型数组在处理较少数据量时造成了绝大部分的内存空间被浪费。
1.malloc和free
C函数库中提供了两个函数,malloc
和free
,在头文件stdlib.h
中声明。分别执行动态内存分配和释放。当程序另外需要一些内存时,他就调用malloc函数,malloc从堆区中提取一块内存,并向程序返回指向这块内存的指针,但是不会对这块内存执行任何初始化,可以自己动手初始化,或者调用calloc,这将会在下一节说明。
函数声明
:
malloc
void* malloc (size_t size);
malloc的参数就是需要分配的内存字节数。如果内存池中的可用内存能满足需求,则返回指向分配内存块起始位置的指针。如果堆区无法向malloc提供所需内存,则调用失败返回NULL。因此对每个从malloc返回的指针都进行检查,确保它并非为NULL
。
void free (void* ptr);
free函数中的参数要么是NULL(什么都不发生),要么是一个先前从malloc,calloc,realloc的返回值。
如果ptr没有指向用上述函数分配的内存块,则会导致未定义的行为。
注意,这个函数并没有改变ptr本身的值,因此它仍然指向相同的(现在是无效的)位置,故需让ptr=NULL,以防止ptr称为野指针。
2.calloc和realloc
另外还有两个内存分配函数,calloc
和realloc
。
calloc
void* calloc (size_t num, size_t size);
分配一个零初始化的(num*size)字节的内存块。
realloc
void* realloc (void* ptr, size_t size);
重新分配内存块
修改ptr指向的内存块的大小, 可以使内存块扩大或者缩小。
函数可以将内存块移动到一个新位置(其地址由函数返回)。
即使内存块被移动到新的位置,内存块的内容只保留较小容量的部分
。如果新分配的空间更大,则新分配的多出的部分的值是不确定的。
如果原先的内存块无法改变大小,realloc将分配另一块正确大小的内存,并把原先那块内存的内容复制到新的块上
。
如果ptr是空指针,则该函数的行为与malloc一模一样,即分配一个大小为字节的新内存块并返回指向其开头的指针。
3.使用动态分配的内存
...
int *pi;
pi=(int*)malloc(sizeof(int)*20);
if(pi==NULL)
{
printf("Out of memory!\n");
exit(EXIT_FAILURE);
}
这里malloc获得了大小为20个整型字节的内存块(4*20),并将指针返回给了pi。这就可以用间接访问或下标来访问这个内存块。例如运用循环将这个新分配的数组每个元素初始化为0:
//下标访问
int i;
for(i=0;i<20;i++)
{
pi[i]=0;
}
//间接访问
int i;
for(i=0;i<20;i++)
{
*(pi+i)=0
}
4.常见错误
这些错误包括
忘记检查内存是否成功分配
对分配的内存使用时越界
释放非动态分配的内存
试图释放分配内存的一部分
内存释放后继续使用:
假定你对一个动态分配内存的指针进行了复制,而且这个指针的几份拷贝散布于程序各处,你无法保证使用其中一个指针时它指向的内存是不是已被另一个指针释放。另一方面,确保程序中所有使用这块内存的地方在这块内存被释放之后停止对他的使用。内存泄漏
:
内存不再使用后应即使释放,这样他以后可以重新分配使用。分配内存但在使用完毕后不释放会引起内存泄漏。内存泄漏在大型程序中会逐渐榨干内存池,最终使其一无所有。