当前位置:网站首页>【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;
}
边栏推荐
- The use and difference of watch listening and computed calculation attributes
- BUUCTF--内涵的软件
- Fully understand the MESI cache consistency protocol
- mysql中的if [not] exists
- 如何快速完成磁盤分區
- Recyclerview universal adapter package
- Fully understand the volatile keyword
- 2020-9-14 introduction to advertising system
- Excel日期及数字格式处理
- MySQL中的alter table操作之add/modify/drop列
猜你喜欢
随机推荐
如何快速完成磁盘分区
C语言库函数--strstr()
September 21, 2020 referer string segmentation boost gateway code organization level
Analysis on the specific execution process of an insert statement in MySQL 8.0 (2)
拼图小游戏中学到的Graphics.h
The product strength is not inferior to that of BYD. Geely Dihao l Raytheon hi · x delivered 10000 units in the first month
C language library function --strstr()
DevExpress的双击获取单元格数据
【评论送书】适合初学者的 6 个有趣的 R 语言项目
由ASP.NET Core根据路径下载文件异常引发的探究
Attribute in C
SQL Server 数据库增删改查语句
Recyclerview sticky (suspended) head
mysql中的if [not] exists
Analysis of BlockingQueue source code of AQS
MySQL中的alter table操作之add/modify/drop列
ssh密钥泄露(B模块赛题)——应用服务漏洞扫描与利用
Comprehensive understanding of synchronized
真正的测试 =“半个产品+半个开发”?
区域工业互联网市场成绩单,百度智能云开物第二









