一 动态内存申请
- 数组的长度是预先定义好的,在整个程序中固定不变;
- 但在实际应用中,往往有这种情况,所需要的内存空间取决于实际输入的数据,而无法预先确定
- 为了解决上面的问题,C语言提供了一些内存管理函数,这些内存管理函数可以安装需要动态的分配内存空间,也可以把不再使用的内存空间回收再利用
二 静态分配内存和动态分配内存
2.1 静态分配内存
- 在程序编译或运行过程中,按事先规定好的大小分配内存空间的分配方式;
- 必须事先知道所需空间的大小;
- 空间是分配在栈区或全局变量区的;
- 按计划分配
2.2 动态分配内存
- 在程序运行过程中按需要自由分配所需空间;
- 按需分配;
- 空间是分配在堆区的,一般使用特点函数来分配
三 动态内存申请的相关函数
3.1 分配内存空间函数 malloc
函数功能: 在内存的动态存储器(堆区)中分配一块长度为size字节的连续内存空间,用来存放类型说明符指定的数据类型
函数原型: void *malloc(unsigned int num_bytes);
形参num_bytes是需要申请内存空间的字节数
调用形式: (类型说明符*) malloc(size)
返回值:
分配成功:分配的内存空间的起始地址
分配失败:NULL
注意事项:
1. 对malloc的返回值一定要强制类型转换;
2. malloc申请的内存空间的内容不确定,一般需要使用memset进行清空;
3. 调用malloc后,一定要判断一下,是否申请内存成功;
4. 如果多次malloc申请的内存,第一次和第二次申请的内存不一定连续;
3.2 free函数 (释放内存函数)
函数说明:free函数释放ptr指向的内存
函数定义:void free(void *ptr)
注意事项:ptr指向的内存必须是malloc,calloc,relloc动态申请的内存
3.3 案例一:从堆区申请一个int类型的空间
[root@ansible9 ~]
int main(int arg, char *argv[])
{
int *p=NULL;
p=(int *)malloc((int)sizeof(int));
if(p==NULL)
{
printf("malloc err\n");
return 1;
}
printf("用malloc申请的内存空间中的内容是不确定的:%d\n",*p);
memset(p,0,(int)sizeof(int));
printf("用memset清0后的内存空间中的内容是:%d\n",*p);
printf("请输入一个int数值:");
scanf("%d",p);
printf("%d\n",*p);
free(p);
}
[root@ansible9 ~]
用malloc申请的内存空间中的内容是不确定的:0
用memset清0后的内存空间中的内容是:0
请输入一个int数值:111
111
3.4 案例二:从堆区申请一个数组,数组的大小由用户决定
步骤:
- 从键盘获取要申请的数组的大小;
- 根据大小,从内存堆区申请空间;
- 对空间读写操作;
- 释放该空间;
[root@ansible9 ~]
int main(int arg, char *argv[])
{
printf("请输入数值元素的个数:");
int n=0;
scanf("%d",&n);
printf("将要为元素个数为%d个的数组申请内存空间\n",n);
int *p=NULL;
p=(int *)malloc(n*(int)sizeof(int));
if(p==NULL)
{
perror("malloc error!");
return 1;
}
memset(p,0,n*(int)sizeof(int));
int i=0;
printf("请输入%d个int数组",n);
for(i=0;i<n;i++)
{
scanf("%d",p+i);
}
for(i=0;i<n;i++)
{
printf("%d\n",p[i]);
}
free(p);
}
[root@ansible9 ~]
请输入数值元素的个数:5
将要为元素个数为5个的数组申请内存空间
请输入5个int数组10 20 30 40 50 60 70 80
10
20
30
40
50
3.5 calloc函数
函数原型:void * calloc(size_t nmemb, size_t size);
参数: size_t是无符号整形,是在头文件中用typeof定义出来的
返回值:申请失败:返回NULL;申请成功:返回申请的内存的首地址
函数功能:在内存的堆区,申请nmemb块,每块大小为size字节的连续内存空间
注意事项:
1. calloc函数申请的内存空间已经自动被清0了,不用再用memset清0;
2. calloc函数申请的内存空间字节数为nmemb和size的乘积;
[root@ansible9 ~]
int main(int arg, char *argv[])
{
printf("请输入数值元素的个数:");
int n=0;
scanf("%d",&n);
printf("将要为元素个数为%d个的数组申请内存空间\n",n);
int *p=NULL;
p=(int *)calloc(n, (int)sizeof(int));
if(p==NULL)
{
perror("calloc error!");
return 1;
}
int i=0;
printf("请输入%d个int数组",n);
for(i=0;i<n;i++)
{
scanf("%d",p+i);
}
for(i=0;i<n;i++)
{
printf("%d\n",p[i]);
}
free(p);
}
[root@ansible9 ~]
请输入数值元素的个数:5
将要为元素个数为5个的数组申请内存空间
请输入5个int数组10 20 30 40 50 60 70
10
20
30
40
50
3.5 realloc函数(重新申请内存空间)
函数原型:void* realloc(void* s, unsigned int newsize);
形参:s原先开辟内存的地址 newsize:新申请内存的大小
返回值:新申请内存的首地址
函数功能:在原先s执行的内存基础上重新申请内存,新的内存大小为newsize字节,如果原先内存后面有足够大的空间就追加;如果没有则realloc函数会在内存堆区找一个newsize字节大小的空间来申请,将原先内存中的数据拷贝过来,然后释放原先的内存,最后返回新内存的地址
[root@ansible9 ~]
int main(int arg, char *argv[])
{
printf("请输入数值元素的个数:");
int n=0;
scanf("%d",&n);
printf("将要为元素个数为%d个的数组申请内存空间\n",n);
int *p=NULL;
p=(int *)calloc(n, (int)sizeof(int));
if(p==NULL)
{
perror("calloc error!");
return 1;
}
int i=0;
printf("请输入%d个int数组元素",n);
for(i=0;i<n;i++)
{
scanf("%d",p+i);
}
for(i=0;i<n;i++)
{
printf("%d\n",p[i]);
}
printf("想要为数组增加几个元素:");
int m=0;
scanf("%d",&m);
printf("您想要增加%d个元素\n",m);
p=(int *)realloc(p,(n+m)*(int)sizeof(int));
if(p==NULL)
{
perror("calloc error!");
return 1;
}
printf("请输入%d个新int数组元素",m);
for(i=n;i<(m+n);i++)
{
scanf("%d",p+i);
}
for(i=0;i<(n+m);i++)
{
printf("%d\n",p[i]);
}
printf("数组现有%d个元素\n",(n+m));
int h=0;
printf ("想减少几个元素:");
scanf("%d",&h);
printf("您想减少%d个元素\n",h);
p=(int *)realloc(p,(n+m-h)*(int)sizeof(int));
if(p==NULL)
{
perror("calloc error!");
return 1;
}
for(i=0;i<(n+m-h);i++)
{
printf("%d\n",p[i]);
}
free(p);
}
[root@ansible9 ~]
请输入数值元素的个数:3
将要为元素个数为3个的数组申请内存空间
请输入3个int数组元素10 20 30
10
20
30
想要为数组增加几个元素:2
您想要增加2个元素
请输入2个新int数组元素40 50
10
20
30
40
50
数组现有5个元素
想减少几个元素:4
您想减少4个元素
10
四 动态内存申请的注意事项
4.1 指向堆区的指针变量不要随意更改指向,会导致calloc申请的内存空间泄漏
[root@ansible9 ~]
int main(int arg, char *argv[])
{
int *p = (int *)malloc(4*(int)sizeof(int));
int num=10;
p=#
}
4.2 不要操作已经释放的空间,因为该空间内容已经不能确定了
[root@ansible9 ~]
int main(int arg, char *argv[])
{
int *p = (int *)malloc((int)sizeof(int));
memset(p,0,(int)sizeof(int));
*p=100;
free(p);
printf("%d\n",*p);
}
4.3 不要对堆区空间重复释放
[root@ansible9 ~]
int main(int arg, char *argv[])
{
int *p = (int *)malloc((int)sizeof(int));
memset(p,0,(int)sizeof(int));
*p=100;
free(p);
free(p);
}
[root@ansible9 ~]
[root@ansible9 ~]
free(): double free detected in tcache 2
Aborted (core dumped)
4.4 如何防止对堆区空间重复释放?
四 内存泄漏
|