欢迎光临
我们一直在努力

【C语言 动态内存分配管理】

动态内存管理

通过这两个函数,程序员可以对自己申请的空间字节设置想要的生存周期
1.malloc : 申请空间 :设置这片空间的开始周期
2.free : 释放空间 : 设置这片空间的结束周期

管理堆区空间的使用和权限是第一个字节的地址,程序员在使用时,
必须使用栈区的指针变量进行有效保存才可以使用。

#include<stdlib.h>//动态内存的书籍
void* malloc(size_t size);

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
  • 返回值类型是void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候,使用者自己决定。

int main(){
void* p=malloc(80);
//void*p=calloc(20,4);calloc 会对所有字节初始化为0
char*p1=p;//p1将这80Byte看成了80个成员的字符数组
int*p2=p;//p2将这80Byte看成了20个成员的整形数组
double*p3=p;//p3将这80Byte看成了10个成员的double数组
double**p4=p;//p4将这80Byte看成了20个成员的double*数组
return 0;
}
p1~p4:悬空指针:指向了一片自己没有权限的空间

  • 如果参数size为0,malloc的行为是标准的,是未定义的,取决于编译器 。

扩容:

  • 堆区空间可以灵活进行扩容 你需要多少可以申请多少 你再次需要多少可以扩容

void* realloc(void* ptr,size_t size);

  • ptr: 之前malloc calloc 得到第一个字节的地址
  • size :新空间大小
  • 返回值为调整之后的内存起始位置
  • 这个函数调整原内存空间大小的基础上,还会将原内存中的数据移动到 新 的空间。
  • Realloc函数的实现

void* My_Realloc(void*p,int Newnum,int Oldnum){
void* q=malloc(p,80);
if(q==NULL)return NULL;
My_Memmove(q,p,Oldnum);
free(p);
p=NULL;
return q;
}

这里需要用到一个My_Memmove函数实现内存空间中数据的移动

void My_Memmove(void*d,void*s,size_t num){
char*pd=d,*ps=s;
if(d==s)return ;
else if(d<s)for(int i=0;i<num;i++){
pd[i]=ps[i];
}
else if(d>s)for(int i=num–1;i>=0;i—){
pd[i]=ps[i];
}
}

realloc在调整内存空间时存在两种情况:
情况1:原空间之后有足够大的空间

当是情况1的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。

情况2:原空间之后没有足够大的空间

当是情况2的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小连续空间来使用,这样函数返回的是一个新的内存地址。

这里讲一个面试必考点:内存泄漏

内存泄露指的就是 : 将堆区空间需要释放空间时那第一个字节的地址 弄丢了,地址的丢失导致堆区空间无法释放

1.程序员永远无法释放这片空间
2.计算机对这片空间也失去了权限
3.程序员没有这个地址永远使用不了这片内存

这里有两种情况:
下面展示一些 内联代码片。

第一种情况:

void Init_Arr(){
void* p=malloc(80);
if(p==NULL){
printf("申请内存空间失败\\n");
return 0;
}
}//受限于栈区变量生存周期的限制,管理堆区空间地址的指针p,在未被释放前就已经被销毁,永远找不到这第一个字节的地址1,导致内存泄露。

第二种情况:

int main(){
void* p=malloc(80);
if(p==NULL){
printf("申请内存空间失败\\n");
int a=10;
p=&a;//管理堆区空间地址的指针p,被程序员改变了,永远找不到第一个字节的地址1,导致内存泄露。
return 0;
}

这里有几个关于动态内存分配和栈内存的区分 需要注意:

1.动态内存分配在堆上,栈内存是自动分配和释放的
2.动态内存分配的空间大小可以灵活调整,栈内存大小一般固定
3.动态内存分配可能会导致内存碎片,栈内存一般不会
4.动态内存分配的变量和栈内存变量都可以通过指针在函数间传递

在这里有几个变量的区分:

栈区变量:生存周期和大小 异常严格 统一由计算机进行管理
1.全局变量:在主函数之外创建的变量,使用00字节进行填充 默认初始化为0。生存周期:从创建开始直到整个文件结束,被销毁
2.局部变量:在主函数之内创建的变量,使用cc进行字节填充 , 生存周期:从创建开始直到整个主函数结束,被销毁
3.块域变量:在{ }之内创建的变量。 使用cc进行字节填充 生存周期:从创建开始直到整个{ } 结束,被销毁

堆区空间一般往往大于栈区,程序员自己可以操作的空间远远大于计算机所能操作的空间

释放内存空间

free:只能free申请的堆区空间的第一个字节的地址,其他的所有情况都会报错。

赞(0)
未经允许不得转载:171主机测评 » 【C语言 动态内存分配管理】
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址