动态内存的开辟
前言
关于数据的存储,数据存储是指将数据以某种格式记录在计算机内部或外部存储介质上,以便后续使用和检索,数据的存储可以分为静态内存存储和动态内存存储。
![]()
路漫漫其修远兮,吾将上下而求索
目录
一、动态内存管理
1.1 动态内存管理和静态内存管理的区别
一、内存分配时机
动态内存管理:在程序运行时根据实际需求动态地分配和释放内存。
静态内存管理:在程序编译时就确定了所需的内存空间大小并进行分配。
二、内存分配方式
动态内存管理:通常使用特定的函数或操作符来分配内存。
静态内存管理:通过在代码中直接声明变量或数据结构来分配内存。内存的分配位置是固定的,通常在程序的数据段或栈上,并且在程序的整个运行期间不会改变。
三、内存释放方式
动态内存管理:需要程序员显式地调用特定的函数来释放不再使用的内存。
静态内存管理:通常由编译器或操作系统自动管理内存的释放。
1.2 为什么要有动态内存管理
动态内存管理在资源分配上面至关重要,其原因如下:
- 适应不同场景需求
- 提高内存利用率
- 支持复杂数据结构
- 提高程序的可扩展性
- 适应多任务环境
1.2.1 在C语言中内存开辟都是在栈上进行的
int a=2;//在栈上开辟了4个字节
int arr[10]={0};//在栈上开辟了40个字节
这样开辟的特点是:
①所开辟出来的空间是固定的
②数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配
对于开辟空间来说,有时候我们并不知道我们空间开辟的需要,有时候空间开大了可能会造成空间的浪费,空间开小的话会造成信息溢出的现象,这时候动态内存就能够帮助我们用多少开辟多少内存,从而实现内存的最优化。
1.3 动态内存的介绍
1.3.1 malloc 和 free
C语言提供了一个动态内存开辟的函数:
void * malloc (size_t size);
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回值的类型是viod*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候,使用者自己来决定。
- 如果参数size为0,malloc标准未定义,取决编译器。
free专门用来做动态内存的释放和回收
void free (void * ptr);
#include<stdio.h>
#include<stdlib.h> //malloc 和free 都在stdlib.h的头文件里
int main()
{
int arr[10] ={0}; //这是在栈中申请连续的四十个空间 是静态的
int * arr1;
int *ptr ;
ptr =(int*)malloc (10*sizeof(int)); //申请一个动态内存空间为40字节
if(ptr==NULL) //防止申请空间失败传入了空指针
{
perror("ptr");
}
arr1=ptr;
free(arr1); //结束后要进行一个空间的释放
arr1=NULL; //然后在指向空指针防止出现了野指针
//这就是申请一个动态内存空间的套用过程
return 0;
}
1.3.2 calloc
calloc 与 malloc区别在于两个函数的参数不一样,再一就是一个初始化,一个不初始化,其他都一样。
void* calloc (size_t num, size_t size);
函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。
#include<stdio.h>
#include<stdlib.h> //malloc 和free 都在stdlib.h的头文件里
int main()
{
int arr[10] ={0}; //这是在栈中申请连续的四十个空间 是静态的
int * arr1;
int *ptr ;
ptr =(int*)calloc (10,sizeof(int)); //申请一个动态内存空间为40字节
if(ptr==NULL) //防止申请空间失败传入了空指针
{
perror("ptr");
}
arr1=ptr;
free(arr1); //结束后要进行一个空间的释放
arr1=NULL; //然后在指向空指针防止出现了野指针
//这就是申请一个动态内存空间的套用过程
return 0;
}
1.3.3 realloc (让动态内存管理更加灵活)
realloc 使我们申请的的动态内存空间变得灵活,在申请动态内存空间的时候,有时候我们申请的过大,或者申请的过小的时候,我们可以通过realloc也对我们申请的空间进行一个合理的调整改变。
void* realloc (void* ptr, size_t size);
- realloc有可能找不到合适的空间来调整大小,这是就返回NULL。
#include<stdio.h>
#include<stdlib.h> //malloc 和free 都在stdlib.h的头文件里
int main()
{
int arr[10] ={0}; //这是在栈中申请连续的四十个空间 是静态的
int * arr1;
int *ptr ;
ptr =(int*)calloc (10,sizeof(int)); //申请一个动态内存空间为40字节
if(ptr==NULL) //防止申请空间失败传入了空指针
{
perror("ptr");
}
arr1=ptr;
arr1 =(int*)realloc (arr1,10000); //改变原有的内存空间
free(arr1);
arr1=NULL;
ptr=NULL;
return 0;
}
1.4 常见的动态内存错误
1.4.1 对NULL指针的解引用操作
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *ptr;
ptr=(int*)malloc(sizeof(int));
*ptr=1;
free(ptr);
ptr=NULL;
return 0;
}
1.4.2 对动态开辟空间的越界访问
#include<stdio.h>
#include<stdlib.h> //malloc 和free 都在stdlib.h的头文件里
int main()
{
int *ptr ;
ptr =(int*)malloc(40); //申请一个动态内存空间为40字节
if(ptr==NULL) //防止申请空间失败传入了空指针
{
perror("ptr");
}
for(int i=0;i<=11;i++)
{
*(ptr+i)=i; //申请的是四十个字节,这里产生了越界
}
for(int i=0;i<=11;i++)
{
printf("%d ",*(ptr+i));
}
free(ptr);
ptr=NULL;
return 0;
}
1.4.3 对非动态开辟内存使用free释放
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p;
*p=10;
free(p); //这里的p并不是动态内存空间仍然进行了释放
return 0;
}
1.4.4 使用free释放一块动态开辟内存的一部分
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p=(int*)malloc(sizeof(int)*2);
if(p==NULL)
{
perror("p");
}
p++;
free(p); //这里的p的地址并不是起始地址,只是进行了部分的释放
p=NULL;
}
1.4.5 对同一块动态内存多次释放
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *p=(int*)malloc(sizeof(int)*2);
if(p==NULL)
{
perror("p");
}
free(p);
// ~~~~~~~~~~
free(p); // 已经释放p了有进行了释放
p=NULL;
}
1.4.6 动态开辟内存忘记释放(内存泄漏)——比较严重
#include<stdio.h>
#include<stdlib.h>
void test(int *p)
{
p=(int*)malloc(sizeof(int)*2);
if(p==NULL)
{
perror("p");
}
}
int main()
{
int *ptr;
test(ptr); //这里就是没有对内存进行释放
}
补充:
关于动态内存开辟的空间,有两种回收方式:
1、主动 free
2、程序结束
总之,动态内存为程序提供了灵活性,但也需要程序员谨慎管理,以确保程序的正确性和稳定性。
最后,本篇文章到此就结束了,如果有帮助到你,请多多支持!!!