当前位置:网站首页>【C语言进阶】动态内存管理
【C语言进阶】动态内存管理
2022-06-29 09:36:00 【皓仔活在今天】
1、为什么存在动态内存分配
1、内存中有三个区域:栈区、堆区、静态区
2、栈区中存放临时变量,静态区中存放静态变量和全局变量,堆区则用于动态内存分配
3、动态内存分配需要用到malloc,calloc,realloc,free函数
2、malloc函数和free函数
1、malloc函数的头文件“stdlib.h”
2、malloc函数使用
#include<errno.h>
#include<string.h>
#include<stdlib.h>
int main()
{
//开辟10个整型空间
int* p = (int*)malloc(40);
//malloc开辟空间是按一个字节开辟的
//所以开辟10个整型,要40个字节
if (NULL == p)//如果返回空指针,空间开辟失败
{
printf("%s\n", strerror(errno));//报错函数
return 0;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", p[i]);
}
//释放
free(p);//当释放后 p 就变成野指针了
p = NULL;//所以我们一般在释放之后将指针处理成空指针
return 0;
}
3、calloc函数
1、开辟并且 0 初始化开辟的空间
2、calloc函数的使用
#include<errno.h>
#include<string.h>
#include<stdlib.h>
int main()
{
//开辟10个整型空间
int* p = (int*)calloc(10,sizeof(int));
//calloc需要的参数是元素个数和申请元素的大小
if (NULL == p)//如果返回空指针,空间开辟失败
{
printf("%s\n", strerror(errno));//报错函数
return 0;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", p[i]);
}
//释放
free(p);//当释放后 p 就变成野指针了
p = NULL;//所以我们一般在释放之后将指针处理成空指针
return 0;
}
4、realloc函数
1、重新开辟空间的函数
2、realloc函数用例
#include<errno.h>
#include<string.h>
#include<stdlib.h>
int main()
{
//开辟10个整型空间
int* p = (int*)calloc(10, sizeof(int));
//calloc需要的参数是元素个数和每个元素的大小
if (NULL == p)//如果返回空指针,空间开辟失败
{
printf("%s\n", strerror(errno));//报错函数
return 0;
}
//使用
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", p[i]);
}
//需要扩容
int* ptr = (int*)realloc(p,80);
if (NULL != ptr)
{
p = ptr;
ptr = NULL;
}
//释放
free(p);//当释放后 p 就变成野指针了
p = NULL;//所以我们一般在释放之后将指针处理成空指针
return 0;
}
3、若realloc函数写成以下这种形式,其功能和malloc函数一样
int* p = (int*)realloc(NULL,40);
5、使用动态内存空间时常见错误
1、对NULL指针解引用
错例如下
#include <limits.h>
#include <stdlib.h>
int main()
{
int* p = (int*)malloc(INT_MAX);//申请空间过大,无法申请,返回NULL
if (p == NULL)//如果没有这句判断
return 0;//就会造成访问NULL指针的错误
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
return 0;
}
2、对动态内存开辟空间的越界访问
错例如下
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main()
{
char* p = (char*)malloc(10 * sizeof(char));
if (p == NULL)
{
printf("%s\n", strerror(errno));
}
//使用
int i = 0;
for (i = 0; i <= 10; i++)//这里<=10一共访问了11个元素
//而malloc只申请了10个空间,形成越界访问
{
*(p + i) = 'a' + i;
}
//释放
free(p);
p = NULL;
return 0;
}
3、对非动态内存使用free释放
错例如下
int main()
{
int a = 10;//栈区上申请的内存,出作用域后会自动销毁
int* p = &a;//不需要free,所以这个代码是错的
free(p);
p = NULL;
return 0;
}
4、使用free释放一块动态开辟内存的一部分
错例如下
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 0;
}
//使用内存
int i = 0;
//1~5
for (i = 0; i < 5; i++)
{
*p = i + 1;
p++;//此时这里p指针已经移动,不在原来的位置上
}
//释放
free(p);//释放动态内存不能只释放一部分,所以错误
p = NULL;
return 0;
}
5、动态开辟内存忘记释放
错例如下
void test()
{
int* p = (int*)malloc(100);
if (p == NULL)
{
return 0;
}
//使用后忘记释放,就会出现内存泄露问题,所以错误
}
int main()
{
test();
return 0;
}
6、柔性数组
柔性数组特点:
1、结构中的柔性数组成员面前必须至少有一个其他成员
2、sizeof返回的这种结构大小不包含柔性数组的内存
3、包含柔性数组成员的结构用malloc()函数进行动态内存分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小
struct S
{
int n;
int arr[];//柔性数组,大小是未指定的
}
int main()
{
//printf("%d\n",sizeof(struct S));
//计算结构体大小的时候,柔性数组大小不计
struct S* ps = (struct S*)malloc(sizeof(struct S) + 40);
ps->n = 100;
int i = 0;
for(i = 0; i < 10; i++)
{
ps->arr[i] = i;
}
//增容
struct S* ptr = (struct S*)realloc(pc, sizeof(struct S) + 80);
if(ptr == NULL)
{
return 0;
}
else
{
ps = ptr;
}
//释放
free(ps);
ps = NULL;
return 0
}
方法二、
方法二的缺陷:
1、开辟和释放的次数多,容易出错
2、开辟次数多的时候,容易出现内存碎片
struct S
{
int n;
int* arr;
}
int main()
{
struct S* ps = (struct S*)malloc(sizeof(struct S));
pc->n = 100;
ps->arr = (int*)malloc(40);
//释放(方法二的缺点,开辟和释放的次数多,容易出错)
free(ps->arr);
ps->arr = NULL;
free(ps);
ps = NULL;
return 0;
}
7、小练习
练习一、
char* GetMemory(char* p)
{
p = (char*)malloc(100);
return p;
}
void Test(void)
{
char* str = NULL;
str = GetMemory(str);
strcpy(str, "hello world");
printf(str);
//释放
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
练习二、
char* GetMemory(char* p)
{
p = (char*)malloc(100);
return p;
}
void Test(void)
{
char* str = NULL;
GetMemory(&str);
strcpy(str, "hello world");
printf(str);
//释放
free(str);
str = NULL;
}
int main()
{
Test();
return 0;
}
练习三、
#include <stdio.h>
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
str = NULL;
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
int main()
{
Test();
return 0;
}
边栏推荐
猜你喜欢

C#窗体向另一个窗体实时传值

Print leap years between 1000 and 2000 (C language)

给定两个整形变量的值,将两个值的内容进行交换 (C语言)

Hystrix fuse: Service fusing and service degradation

打印1000~2000年之间的闰年(C语言)

UserWarning: Usage of dash-separated ‘script-dir‘ will not be supported in future versions. 笔记

打印100~200之间的素数(C语言)

如何优雅的写 Controller 层代码?

MySQL innodb每行数据长度的限制

罗清启:高端家电已成红海?卡萨帝率先破局
随机推荐
Agctfb partial solution
IIS server related error
2020-9-14 introduction to advertising system
FreeRTOS porting of official website based on keil5 auto configuring STM32F103 standard library
有了这款工具,自动化识别验证码再也不是问题
Design of intelligent test paper generation system
C#中Attribute(特性)
如何快速完成磁盤分區
The product strength is not inferior to that of BYD. Geely Dihao l Raytheon hi · x delivered 10000 units in the first month
Recyclerview universal adapter package
C语言库函数--strstr()
Report card of regional industrial Internet market, the second place of Baidu intelligent yunkaiwu
Dev使用过程中的基本操作
WinForm uses zxing to generate QR code
智能组卷系统设计
Comprehensive understanding of synchronized
Print leap years between 1000 and 2000 (C language)
Voir le classement des blogs pour csdn
1-数据库了解
全面理解Volatile关键字