一.Malloc函数
1.概述
Malloc函数用于在内存的动态存储区(堆区)中分配一块长度为 size 字节的连续区域,用来存放类型说明符指定的类型。函数原型返回 void*指针,使用时必须做相应的强制类型转换 ,分配的内存空间内容不确定,一般使用memset 初始化。
头文件:
2.使用
(1)函数原型
注意:
malloc申请的内存中存放的内容是随机的,不确定的
函数原型:void* malloc(size_t size);
-
size_t
是一个无符号整型,通常用来表示大小或长度
(2)返回值
注意:
- 要对malloc的返回值进行判断,判断内存是否申请成功
- 单次申请的内存空间是连续的,多次申请的就不一定了
返回值:
- 分配空间的起始地址(分配成功)
- NULL(分配失败,通常是因为内存不足)
3.示例代码
通过malloc
动态申请的内存区域的指针当作数组来使用,因为其返回的是一块连续的内存区域
# include
# include
/*根据输入的整形来确定要申请内存的大小
申请成功后对其进行内容填充*/
int main() {
int num;
printf("请输入要申请的大小: ");
scanf_s("%d", &num);//使用scanf_s是因为Vs Studio认为单纯的scanf不安全
//malloc的实参通俗点将就是要申请内存的大小
int* p = (int*)malloc(num * sizeof(int));
if (p == NULL) {
printf("内存申请失败");
return 0;
}
//因为malloc动态申请的内存可以看作是一块连续的内存空间,所以可以将其视为是一个数组
for (int i = 0; i < num; i++) {
p[i] = i;
}
for (int i = 0; i < num; i++)
{
printf("p[%d]=%d\n", i, p[i]);
}
//释放动态申请的内存
free(p);
return 0;
}
二.Free函数
1.概述
**概述:**Free是用来释放内存的函数,其释放传入指针所指向由malloc
,calloc
,relloc
动态申请的内存
头文件:
2.使用
函数原型:void free(void *ptr);
-
void *prt
:指向要释放内存的指针
注意事项:
- **指针有效性:**必须是由
malloc
,calloc
,relloc
动态申请的内存 - **多次释放:**尝试释放同一块内存多次也是未定义行为。在释放内存后,应立即将指向该内存的指针设为
NULL
,以防止误用。
3.示例
char *p = (char *)malloc(100);
free(p);
三.calloc函数
1.概述
**功能:**在内存的堆中,申请nmemb块,每块的大小为size个字节的连续区域函数的返回值
头文件:
2.使用
(1)函数原型
注意:
calloc
函数申请的内存中的内容均为0,区别于malloc
函数原型:void* calloc(size_t nmemb,size_t size);
-
size_t nmemb
:无符号整形,用于指定申请内存的块数 -
size_t size
:无符号整形,用于指定每块内存的大小
(2)返回值
单次申请的内存是连续的,两次申请的两块内存不一定连续
- 分配空间的起始地址(分配成功)
- NULL(分配失败,通常是因为内存不足)
3.示例
# include
# include
int main() {
int num;
printf("请输入要申请的大小: ");
scanf_s("%d", &num);//使用scanf_s是因为Vs Studio认为单纯的scanf不安全
//使用calloc申请内存
int* p = (int*)calloc(num, sizeof(int));
if (p == NULL) {
printf("内存申请失败");
return 0;
}
//因为malloc动态申请的内存可以看作是一块连续的内存空间,所以可以将其视为是一个数组
for (int i = 0; i < num; i++) {
p[i] = i;
}
for (int i = 0; i < num; i++)
{
printf("p[%d]=%d\n", i, p[i]);
}
//释放动态申请的内存
free(p);
return 0;
}
四.realloc函数
1.概述
**功能:**用于调整已经申请内存大小的函数,此操作可以保持内存的连续性
头文件:``
2.使用
(1)函数原型
函数原型:void* realloc(void* ptr, size_t newSize);
-
ptr
:指向之前分配的内存块的指针- 如果
ptr
是NULL
,则会分配一个新的内存块
- 如果
-
newSize
:新的内存块大小,是调整后的内存大小
(2)返回值
① newSize
小于原内存,会去掉多余的内存
![image-20240206091712953](https://honescos.oss-cn-hangzhou.aliyuncs.com/img/image-20240206091712953HO7CEEFvTa202402060917ce23ecd0eada5ccf.png)
② newSize
大于原内存
-
原内存后空间够,在它后面新增内存块
-
原内存后空间不足,会在堆区新申请一个内存,将原内存内容复制过去,并将这个新内存的地址返回
3.示例
char *p;
//使用malloc申请100字节的内存
p=(char *)malloc(100);
//发现100字节有点多余,故使用reallco进行调整
p=(char *)realloc(p,50);//新的内存小于原内存,原内存后的50字节会被释放
五.内存泄露
自述:我感觉拿个小本本记住哪个内存没有释放貌似也不错( •̀ ω •́ )y
1.概念
**概述:**指定的动态内存申请的内存,指向它的首地址即指针丢失了,无法找回,也无法使用和释放的情况
2.示例
(1)内存指针指向其它位置
将本应该指向申请内存的指针指向了其它位置,导致申请内存指针丢失,进而导致内存泄露
int main(){
//用指针p来记录申请的内存
char *p = (char *)malloc(100);
//将申请内存的指针指向了helloworld
p = "helloworld";
//从此以后,再也找不到申请的那100个字节了
return 0;
}
(2)函数内申请不释放
在函数内动态申请了内存,且在函数结束时没有对其进行释放,导致函数结束后指针p被释放了,没有指针指向内存,进而导致内存泄露
void fun(){
//光申请最后没有释放
char *p = (char *)malloc(100);
//...后继使用省略
}
int main(){
//每调用以此函数,就有100字节内存泄露
fun();
fun();
return 0;
}
3.解决方案
总之保证一件事,申请内存的首地址即指针不能丢
(1)函数内申请、释放
在函数内申请内存,在函数结束前即刻释放
void fun(){
char *p = (char *)malloc(100);
//...后继使用省略
free(p);
}
int main(){
fun();
fun();
return 0;
}
(2)返回函数申请内存指针
将函数内申请内存的指针作为函数的返回值进行返回,后继由接收处处理这个指针
char * fun(){
char *p = (char *)malloc(100);
//...后继使用省略
return p;
}
int main(){
//接收函数返回的申请内存的指针
char *q = fun();
//在接收函数内部进行释放
free(q);
return 0;
}