当前位置:网站首页>【C语言】动态内存管理
【C语言】动态内存管理
2022-07-24 12:43:00 【Ahao_te】
1、动态内存管理
1.1、为什么要有动态内存
我们在此之前,已经掌握了一些开辟内存的方式。
比如
int n = 4; //开辟了4个字节空间
int arr[20] = {
0}; //开辟了一段连续的空间
上述的方式都有这固定的几个特点:
- 空间是固定的。
- 开辟数组的时候必须指定长度。
但有时我们对空间开辟的大小是需要在程序运行之后才能确定的,所以就有了动态内存。
1.2、malloc和free
C语言提供的一个内存开辟函数
void* malloc (size_t size);
开辟的空间储存在堆区,size代表着准备开辟多少字节的空间。
- 如果开辟成功,将返回这个空间的起始地址
- 如果开辟失败,将返回空指针
- 返回值是void*,所以在开辟后需要使用者决定
- 如果size为0,这个行为是未定义的,取决于编译器。
free函数是用来释放堆区开辟的内存,如果用来释放栈区的内存,将会报错。
void free (void* ptr);
- ptr代表空间的起始地址
- ptr为NULL的时候,free函数什么也不做。
- 如果不对开辟的动态内存进行free操作,可能会造成内存泄漏。
malloc和free的使用
int main()
{
//申请空间的大小没法改变
int a = 10;
int arr[10];
//需要动态的内存
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", *(p + i));
}
//没有free
//并不是说内存空间就不回收了
//当程序退出的时候,系统会自动回收内存空间的
free(p);
p = NULL;
return 0;
}
1.3、calloc和realloc
calloc也是开辟内存函数,和malloc不同的是传参以及开辟的空间内数据都将初始化为0。
void* calloc (size_t num, size_t size);
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = (int*)calloc(10, sizeof(int)); //开辟40字节空间
if(NULL != p)
{
//...
}
free(p);
p = NULL;
return 0;
}
realloc函数让内存开辟变得更加灵活,realloc能将原本的动态内存空间进行调整,如果增大,那么原本的内存块将保留,新的内存块将在后面添加,如果变小,那么将截断原本空间的后面部分。
void* realloc (void*ptr, size_t size);
- 参数ptr代表需要扩充的空间的起始指针,size代表最后需要扩充到多大的空间。
- ptr如果为NULL,就和malloc的功能一样。
- void*代表开辟后返回起始空间的指针,这个指针最好不要和一开始需要扩充的空间起始指针一样,不然当内存扩充失败的时候,原来的指针就变为了NULL。
- realloc调整指针存在两种情况,第一种是当原本空间后连续有足够的空间可以扩容,这种情况能使得它们空间连续,起始指针的地址不变。第二种是当原本空间后没有连续的空间可以扩容,那么会在其它位置找到足够的空间进行开辟空间,而原本空间的指针就变了。(最终都是变成一块空间)
1.4、使用动态内存分配
这是一个开辟动态内存的例子。
int* p = (int*)malloc(sizeof(int)* 10);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
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=NULL;
符号NULL定义于stdio.h,字面值常量是0。它对于开辟动态内存空间的成功与否有着很大作用,在开辟内存后,一定要对返回指针进行判断是否为空。如果不为空,那么就成功得到一个p指针指向的有着10个int类型的空间。
sizeof(int)* 10 这样的写法好在就算跨平台,也能得到正确的结果。
如果想对开辟成功的内存进行访问,在得到p指针可以分别以 * (p+i)、p[ i ]方式访问。
在free ( p ) 后,最好将p至为空(p=NULL),防止非法访问。
1.5、常见的动态内存错误
1. 不检查从malloc函数返回的指针是否为NULL,对NULL指针进行了解引用
void test()
{
int* p = (int*)malloc(INT_MAX); //内存池没有这么大的空间能够分配,开辟失败返回空指针。
*p = 20;//这里需要对p进行检查,如果内存分配失败 就是对NULL指针解引用
free(p);
}
2. 访问动态分配的内存之外的区域
int main()
{
int* p = (int*)malloc(40);
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
int i = 0;
for (i = 0; i <= 10; i++)
{
p[i] = i; //越界访问
}
free(p);
p = NULL;
return 0;
}
3. 向free 函数传递一个并非由 malloc 函数返回的指针
void test()
{
int a = 10;
int* p = &a;
free(p);
//free非动态内存会报错
//freeNULL指针会不动
}
4.使用free释放一块动态开辟内存的一部分
void test()
{
int* p = (int*)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
5.在动态内存被释放后再访问它
void Test(void)
{
char* str = (char*)malloc(100);
strcpy(str, "hello");
free(str); //先将空间给释放了
//释放应当制空
*str = 'h';
}
int main()
{
Test();
return 0;
}
6.动态开辟内存忘记释放(内存泄漏)
void test()
{
int* p = (int*)malloc(100);
//....
int flag = 0;
scanf("%d", &flag);//5
if (flag == 5)
return;
free(p);
p = NULL;
}
int main()
{
test();
//......
return 0;
}
内存泄漏:
当动态分配的内存不在需要使用时,它应该被释放,这样它以后可以被重新分配使用。分配内存但在使用后不释放将引起内存泄漏。在那些所有程序共享一个通用内存池的操作系统中,内存泄漏将一点点地榨干可用内存,最终使其一无所有。要拜托这个困境,只有重新启动系统。
1.6、柔性数组
结构中的最后一个元素允许是未知大小的数组,这就叫做 柔性数组成员
struct S
{
int n;
int arr[0]; //柔性数组成员
};
有些编译器会报错无法编译可以改成:
struct S
{
int n;
int arr[]; //柔性数组成员
};
柔性数组的特点:
- 结构中的柔性数组成员前面必须至少有一个其它成员
- sizeof返回的这种结构大小不包括柔性数组的内存,arr未开辟内存时称作标记
- 包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
struct S
{
int n;
int arr[]; //柔性数组成员
};
printf("%d\n",sizeof(struct S)); //4
柔性数组的使用:
struct S
{
int n;
int arr[]; //不用int* p的原因
};
//如果用int* p; 需要给结构体成员p再开辟一个内存空间让p指向。
//不用int* p的原因
//1.用int*p需要开辟两个不同的空间,free的时候要释放两次,带arr[]只要free一次方便释放
//2.开辟两个不同空间,会出现内存碎片,连续的内存有益于访问速度的提高
int main()
{
struct S* ps = (struct S*)malloc(sizeof(struct S) + 40);
if (ps == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
ps->n = 100;
int i = 0;
for (i = 0; i < 10; i++)
{
ps->arr[i] = i;
}
for (i = 0; i < 10; i++)
{
printf("%d ", ps->arr[i]);
}
struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 80);
if (ptr != NULL)
{
ps = ptr;
ptr = NULL;
}
free(ps);
ps = NULL;
return 0;
}
边栏推荐
- Cluster construction based on kubernetes v1.24.0 (III)
- Raspberry pie self built NAS cloud disk -- automatic data backup
- Raspberry pie self built NAS cloud disk -- raspberry pie built network storage disk
- Zabbix5.0.8-odbc monitoring Oracle11g
- for mysql
- Shell script case ---2
- TypeNameExtractor could not be found
- sql的where+or的用法丢失条件
- 元宇宙更多的功能和作用在于对于传统生活方式和生产方式的深度改造
- STM32——C语言基础
猜你喜欢

基于Kubernetes v1.24.0的集群搭建(三)

How to realize the function of grabbing red envelopes in IM system?
Learn some programming: anti unemployment "vaccine"

The price of domestic flagship mobile phones is nearly 6000, but they can't even beat iphone12. It's clear who users choose
![ERROR: [Synth 8-439] module ‘xxx‘ not found not found 错误解决办法](/img/47/bb03cc26e254332bf815c80bafb243.png)
ERROR: [Synth 8-439] module ‘xxx‘ not found not found 错误解决办法

Implement is by yourself_ default_ constructible
让一套代码完美适配各种屏幕

With the strong development of cloud native, how should enterprises seize business opportunities

Aruba learning notes 04 Web UI -- Introduction to configuration panel

nacos部署
随机推荐
Error: [synth 8-439] module 'xxx' not found not found error solution
有没有2、3w前期适合一个人干的创业项目呢?做自媒体可以吗?
How to mount NFS shares using autofs
Is it safe for Huatai Securities to open a remote account? Is there any guarantee?
Solutions to problems in IE6 browser
Learn some programming: anti unemployment "vaccine"
Ape anthropology topic 5
for mysql
Is it safe to contact the account manager online to open a fund account?
The price of domestic flagship mobile phones is nearly 6000, but they can't even beat iphone12. It's clear who users choose
How to find out the function calling process of complex code running as soon as possible
如何使用autofs挂载NFS共享
Wechat applet generates QR code
Leecode-268. missing numbers (Application of XOR, find numbers that do not appear, find numbers that only appear once)
使用TypeFace设置TextView的文字字体
[rust] reference and borrowing, string slice type (& STR) - rust language foundation 12
Raspberry pie self built NAS cloud disk -- automatic data backup
Buckle practice - sum of 34 combinations
让一套代码完美适配各种屏幕
Implementing deep learning framework from zero -- further exploration of the implementation of multilayer bidirectional RNN