10.动态内存管理
书写程序的原则:谁申请地址,待程序执行结束后谁要释放。动态内存管理的函数包括有
malloc calloc realloc free
,其中free
函数要与前三者在一个函数中同时使用或者在同一个模块中。
一.malloc
-
函数定义:
void *malloc(size_t size);
在堆上寻找size
大小的空间,并以地址的方式返回给程序。 -
示例代码:
//基本使用
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
6 int *p = NULL;
7 p = malloc(sizeof(int)); //malloc返回值时一个指针
8
9 if(p == NULL)
10 {
11 printf("malloc() is error!");
12 exit(1);
13 }
14
15 *p = 10;
16 printf("p = %d\n",*p);
17 free(p); //释放指针指向的首地址所代表的内存空间。
18 exit(0);
19 }
//输出结果:
p = 10
为数组动态分配内存(变长数组):
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
int *p =NULL;
6 int num = 6;
7 *p = malloc(sizeof(int) * num);
8 int i;
9
10 for(i = 0;i < num; i++)
11 scanf("%d",&p[i]);
12
13 for(i = 0;i < num; i++)
14 printf("%d ",p[i]);
15 printf("\n");
16
17 exit(0);
18 }
//输出结果:
jxs@jxs-ubuntu:~/Desktop/c language/alloc$ ./arr
45
56
23
89
56
89
45 56 23 89 56 89
有关内存溢出的例子:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 void func(int *q,int n)
5 {
6 q = malloc(n);
7 if(q = NULL)
8 exit(1);
9 return;
10 }
11
12 int main()
13 {
14 int *p = NULL;
15 int num = 100;
16
17 func(p, num);
18 free(p);
19
20 exit(0);
21 }
//该程序在编译的时候不会报错,但是确实是出现了内存泄漏。
原因在于:
可以更正为:
#include <stdio.h>
#include <stdlib.h>
void func(int **q,int n) //int *q
{
*q = malloc(n); //q
if(*q = NULL) //q
exit(1);
return ;
}
int main()
{
int *p = NULL;
int num = 100;
func(&p, num); //func(p,num)
free(p);
exit(0);
}
#include <stdio.h>
#include <stdlib.h>
void *func(int *q,int n) //空类型指针
{
q = malloc(n);
if(q = NULL)
exit(1);
return q;
}
int main()
{
int *p = NULL;
int num = 100;
p = func(p, num);
free(p);
exit(0);
}
二.calloc
- 函数定义:
void *calloc(size_t nmemb, size_t size);
寻找
nmemb * size(一个 memb 占用 size 大小空间)
大小的连续空间,即为每个memb
申请siz
e大小的空间,一共有n
块同样大小且连续的空间,同样以地址的方式返回。并把空间内的每个字节初始化为0。
其他用法与malloc
相同,因此如果要求申请的内存初始化为0,就调用该函数。
三.realloc
与reallocarray
1.realloc
1). 函数定义:void *realloc(void *ptr, size_t size);
重新分配一块动态内存,比如上述函数分配的内存不够或者多了,该函数可以重新分配一块满足后来要求
size
大小的空间。
- 比如说使用
calloc
函数分配的空间100个字节不够用,而实际需要300个字节,此时,relloc
函数接收这100个字节空间的最后一个地址,接着向下连续寻址,直到一共300个字节,如果下面的地址被其他变量占用,那么就会重新寻找其他内存区域,寻找到连续的300个字节的空间,之后将原来的那块空间释放掉,返回新空间得首地址。位于原来地址的数据,都会移动到该新地址,即原来的首地址发生改变。- 如果分配的内存比实际使用的要多,为了缩减为要求的空间大小,
relloc
会逐步的将对于的地址进行缩减,直至空间达到实际要求的大小。原来的空间数据不发生变化。
2). 特点:
ptr
是要调整的内存地址,size
为调整之后的新大小;- 返回值为调整之后的内存起始位置;
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间;
2.reallocarray
1). 函数定义:void *reallocarray(void *ptr, size_t nmemb, size_t size);
改变由
ptr
指向的内存空间的大小,直至数组有足够存储的空间存储nmemb
个元素。每一个元素占用size
大小空间。
等同于realloc(ptr, nmemb * size);
但是与realloc
调用不同的是,该函数会在multiplication
时缺乏安全性会导致overflow,如果发生了溢出,该函数会返回NULL
,将errno
设置为ENOMEM
,并保持原始内存块不变。
四.free
- 函数定义:
void free(void *ptr);
free
函数用于释放指向ptr
的内存空间,其必须在先前已经调用malloc calloc realloc
函数之一才能使用,否则如果先于这三个函数调用,将会出现不可预料的错误,如果ptr
时NULL
将不会进行任何操作。free(p)
表示指针p
对其原指向的那块内存空间不再有引用权限。free
之后需要将原来的指针写成NULL
,避免野指针的出现:
//你:租客;编译器:房东
int *p ; //定义指针p (你对房东说:我要租房间p)
p = malloc(100); //指针指向分配的100个字节的空间的首地址 (你向房东说p得100平)
*p = 10; //将10存储到p指向的那块地址空间中 (你让‘10’ 住了进来,现在房间使用权在你,你可以让任何人住进来)
free(p); //释放p指向的那块地址空间,此时p 已经不再指向原来那块地址空间。 (你因某些原因退租,让房东帮忙给退了)
//因此下面的对原地址的直接引用属于野指针。所以释放空间之后:
p = NULL; //令指针为空 (房间p确定已经空了下来,等待或者已经给了下一位租客,但使用权不在你手上,而是在房东手上)
*p = 100; //因此你无权再让其他人(100)拎包入住
//除非你再重新租住。
- 示例代码:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main()
5 {
6 int *p = NULL;
7 p = malloc(sizeof(int));
8
9 if(p == NULL)
10 {
11 printf("Error!Try again!\n");
12 exit(1);
13 }
14
15 *p = 10;
16 printf("%p --> %d\n",p,*p);
17 free(p);
18
19 //p = NULL; //避免p成为野指针
20 *p = 100;
21 printf("%p --> %d\n",p,*p); //p指向的的地址可能不会发生改变,但这样使用很危险!
22
23
24
25 exit(0);
26 }
本文来自博客园,作者:code_wss,转载请注明原文链接:https://www.cnblogs.com/jxsme/p/17514694.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏