使用动态内存分配时必须的头 #include<stdlib.h> 或#include<malloc.h>
一、malloc 函数(memory allocation 内存分配) :
用于申请一块连续的指定大小的内存区域,如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定,是随机的垃圾值),否则返回空指针NULL。
例如:
int *p1 = (int*)malloc(n*sizeof(int));
向系统申请一个大小为 4n 字节的连续空间,这种写法是为了便于理解。
由于申请内存空间时还不知道用户是用这段空间来存储什么类型的数据,所以其默认返回的是未确定类型的指针(void*),但我们这里是要存储整型数据,所以在前面对其进行强制转型。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p1 = (int*)malloc(5*sizeof(int)); //申请一个20字节的动态内存,保存整型数据
for(int i = 0; i < 5; i++)
{
p1[i] = i * 10;
printf("%d\n",p1[i]);
}
return 0;
}
其输出结果为:
二、realloc 函数 (reset allocation 重置分配)
将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来所指的内存区域(自动释放,不需使用free),同时返回新分配的内存区域的首地址。若重新分配失败,则返回空指针NULL。
注意,新分配的部分由于未初始化,其中是随机的垃圾值。另外,操作系统不会回应缩小内存的请求,比如,不能把原来20字节的动态内存,通过realloc重新分配为10字节。
int *p2 = (int*)realloc(p1,n*sizeof(int)); (p1为原来的动态内存首地址)
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p1 = (int*)malloc(5*sizeof(int));
for(int i = 0; i < 5; i++)
{
p1[i] = i * 10;
}
int *p2 = (int*)realloc(p1,10*sizeof(int));
p2[9] = 90;
for(int i = 0; i < 10; i++)
{
printf("%d\n",p2[i]);
}
return 0;
}
其输出结果为:
三、calloc 函数 (clear allocation 清零分配)
与malloc只有一点不同,calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据。
int *p3 = (int*)calloc(n , sizeof(int)); (注意:这里的参数是两个,用逗号分割,与malloc不同)
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p1 = (int*)malloc(5*sizeof(int));
int *p3 = (int*)calloc(5,sizeof(int));
for(int i = 0; i < 5; i++)
{
printf("%d\n",p1[i]);
}
printf("\n");
for(int i = 0; i < 5; i++)
{
printf("%d\n",p3[i]);
}
return 0;
}
其输出结果为:
四、free 函数
释放动态内存。
其语句很简单:free(p1);
free(p2);
free的时候不需要说明所释放内存的长度,因为其头尾信息就存在于动态内存中。
如果说我们在程序中创建了一段动态内存,我们使用了这个动态内存后,该动态内存没有存在意义时,我们就需要将其用free函数释放掉,否则就会造成内存泄漏(Memory Leak)。
内存泄漏(Memory Leak)
指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。内存泄漏缺陷具有隐蔽性、积累性的特征,比其他内存非法访问错误更难检测。因为内存泄漏的产生原因是内存块未被释放,属于遗漏型缺陷而不是过错型缺陷。此外,内存泄漏通常不会直接产生可观察的错误症状,而是逐渐积累,降低系统整体性能,极端的情况下可能使系统崩溃。
有时候我们使用free时,会造成系统崩溃,其原因主要有以下几点:
1、 越界。如:realloc第二个参数写错
2、 修改了指针的指向。如:p++
3、 重复释放同一段内存
4、 释放非动态内存
以上四点需要格外注意。