我的编程空间,编程开发者的网络收藏夹
学习永远不晚

怎么在C语言中实现内存管理

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

怎么在C语言中实现内存管理

这篇文章给大家介绍怎么在C语言中实现内存管理,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

C语言是什么

C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发,使用C语言可以以简易的方式编译、处理低级存储器。

1. 内存管理简介

在计算机系统,特别是嵌入式系统中,内存资源是非常 有限的。尤其对于移动端开发者来说,硬件资源的限制使得其在程序设计中首要考虑的问题就是如何 有效地管理内存资源。

常见内存使用错误:

  • 内存申请未成功,就进行使用

  • 内存申请成功,但没有初始化

  • 内存初始化成功,但越界访问

  • 忘记释放内存或者释放一部分

内存管理不当的危害?

  • 没有初始化,会造成内存出错

  • 越界访问内存可能导致崩溃

  • 忘记释放内存造成内存泄露

C语言的内存管理:

C语言为用户提供了相应内存管理的AP接口,如 malloc()free()new()等函数,需要开发者手动管理。而javaC#则有自动内存回收机制,基本无需再对内存进行操作了。

2. 内存分类 栈区(stack)

由系统自动分配

堆区(heap)

在程序的执行过程中才能分配,由程序员决定

全局区(静态区)

静态区存放程序中所有的全局变量和静态变量

常量区

常量字符串就是放在这里的

代码段:

代码段(code segment/text segment)。通常是指用来存放程序执行代码的一块內存区域。代码区的指令中包括操作码和要操作的对象(或对象地址引用)。如果是立即数(即具体的数值,如5)直接包含在代码中;如果是局部数据,将在栈区分配空间,然后引用该数据地址。

数据段:

数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

BSS段:

BSS段(Block Started by Symbol)。指用来存放程序中未初始化的全局变量的一块内存区域。
BSS段本质上也属于数据段,都用来存放C程序中的全局变量。区别在于.data段中存放初始化为非零的全局变量,而把显式初始化为0或者并未显式初始化(C语言规定未显式初始化的全局变量值默认为0)
的全局变量存在BSS段。

3. 栈区(stack)

由编译器 自动分配释放,存放函数的参数值、局部变量的值等,是一种先进后出的内存结构。

哪些是分配在栈空间?

  • 局部变量的值存放在栈上

  • 在函数体中定义的变量通常是在栈上

函数栈分配:

在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。

栈内存什么时候回收?

栈内存的分配和释放也由编译器在函数进入和退出时插入指令自动完成,生命周期和函数、局部变量一样。

栈空间的大小:

在 Windows下,栈是向低地址扩展的数据结构,是块连续的内存的区域。栈空间一般较小,栈大小与编译器有关。默认情况下,visual studio 2010的栈大小为1M。但在平时应用程序中,由于函数会使用栈结果,所以只能用略小于1M大小的栈如果申请的空间超过栈的剩余空间时,将提示Stack overflow。

怎么在C语言中实现内存管理

示例代码:

#include<stdio.h>struct  A{};class  B{};void   fun(int  a  , int  b) //参数a,b在栈上, 在函数体结束的时候,栈内存释放{   int   c;//局部变量,在栈上, 在函数体结束的时候,栈内存释放}int  main(){   int  a = 10;//局部变量在栈上,  在main函数结束的时候,栈内存释放   char  b[] = "hello";//数组变量也在栈上,  在main函数结束的时候,栈内存释放   char  *c = NULL;//在栈上,  在main函数结束的时候,栈内存释放   {       A   d;//结构体变量,  在栈上        B   e;//类对象在栈上   } //d,e 在离开这个{}时,栈内存销毁释放   //测试栈的大小   //char   buf[1024 * 1024] = { 'A' };//1M时崩溃了   char   buf[1000* 1024] = { 'A' };//栈空间略小于1M   //经过编译期设置为5M之后,栈空间变大了   char   buf[49 * 1024 * 1024 / 10] = { 'A' };//栈空间略小于5M   printf("%d" , sizeof(buf)  );   return 0;}

4. 堆区(heap)

需程序员自己申请,并可在运行时指定空间大小,并由程序员手动进行释放,容易产生 memory leak

哪些是分配在堆空间?

调用 mallocrealloccalloc函数

//分配得来得10*4字节的区域在堆区p1 = (char*)malloc(10*sizeof(int));

堆空间需要手动释放:

堆是由 malloc()等函数分配的内存块,内存释放由程序员调用free()函数手动释放

堆空间的大小:

堆空间一般较大,与64位/32位,编译器有关,受限于计算机系统中有效的虚拟内存;理论上32位系统堆内存可以达到4G的空间,实际上2G以内,64位128G以内(虚拟内存16TB)

示例代码:

#include<stdio.h>#include<stdlib.h>int  main(){   //手动分配、这里就是分配了堆内存   int  *p = (int*)malloc(10 *  sizeof(int ));   //手动释放   free(p);   int MB = 0;   while (malloc(1024 * 1024))//每次分配1M   {       MB++;   }   printf("分配了 %d MB \n", MB);    return 0;}

栈与堆的区别:


类型分配释放大小是否连续申请效率
栈区由编译器自动分配释放较小一块连续的内存区域由系统自动分配,速度快
堆区由程序员分配释放较大堆是向高地址扩展的数据结构,是不连续的内存区域速度慢,容易产生内存碎片

5. 全局区(静态区)

全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在块区域。

哪些是分配在全局静态区?

  • 全局变量

  • static静态变量

全局静态区何时释放?

全局变量、静态变量在整个程序运行的生存期都存在,所以在程序结束时才释放

示例代码:

#include<stdio.h>//储存在全局静态区int   a;  //全局变量,未初始化short   b = 10;//全局变量,已赋值char  *c = NULL;//全局变量,已赋值static  int   f = 200;//静态变量int  main(){   static  int  d = 100;   static  int  e = 200;   printf("%p\n", &a);   printf("%p\n", &b);   printf("%p\n", &c);   printf("%p\n", &d);   printf("%p\n", &e);   printf("%p\n", &f);}

怎么在C语言中实现内存管理

6. 常量区

字符串常量是放在常量区,当你初始化赋值的时候,这些常量就先在常量区开辟一段空间,保存此常量,以后相同的常量就都使用一个地址。

示例代码:

#include<stdio.h>//“AAA”是字符串常量,存放在常量区char  *p = "AAA";int  main(){   //p1是局部变量,在栈上, “AAA”是字符串常量,存放在常量区   char  *p1 = "AAA";   //p2是局部变量,在栈上,“AAA”不是字符串常量,她只是一种初始化的写法   char  p2[]= "AAA";   //p3是局部变量,在栈上, “AAA”是字符串常量,存放在常量区   char  *p3 = "AAA";   //p4是局部变量,在栈上, “AAB”是字符串常量,存放在常量区   char  *p4 = "AAB";   printf("%p\n", p);   printf("%p\n", p1);   printf("%p\n", p2);   printf("%p\n", p3);   printf("%p\n", p4);}

怎么在C语言中实现内存管理

7. malloc、calloc、realloc函数

三个函数的作用?

它们都能分配堆內存、成功返回内存的首地址,失败就返回NULL

malloc函数:

void *malloc(  size_t size);

该函数将在堆上分配一个 size byte大小的内存。不对内存进行初始化,所以新内存其值将是随机的。

calloc函数:

void *calloc(  size_t number,  size_t size);

该函数功能与 malloc相同,它将分配countsize大小的内存,自动初始化该内存空间为零。

realloc函数:

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

该函数将ptr内存大小增大或减小到newsize

realloc函数返回的两种情况:

  • 如果当前连续内存块足够 realloc的话,只是将p1所指向的空间扩大,并返回p1的指针地址。

  • 如果当前连续内存块不够长度,再找一个足够长的地方,分配一块新的内存p2,并将p1指向的内容Copy到p2,并释放p1指向的旧内存,然后返回p2。

示例代码:

#include<stdio.h>#include<stdlib.h>int  main(){   //malloc  ,参数是字节数 , 并且这块内存空间的值是随机的   int  *p = (int *)malloc(5 *  sizeof(int));   p[0] = 123;   for (int i = 0; i < 5; ++i)   {    printf("%d   ", p[i]); //后面4个值随机   }      printf("\n------------------------------------------------------------\n " );   //calloc,参数两个, 自动将内存空间初始化为0   int   *p2 = (int *)calloc(5, sizeof(int));   p2[4] = 123;   for (int i = 0; i < 5; ++i)   {   printf("%d   ", p2[i]);    }   printf("\n------------------------------------------------------------\n ");       //realloc ,可以调整内存空间的大小 ,并且拷贝原来的内容(调大,或者  缩小)   //int  *p3 =(int *) realloc(p, 6* sizeof(int));//调大一点点,两个地址相同   //int  *p3 = (int *)realloc(p, 2 * sizeof(int));//缩小,两个地址相同   int  *p3 = (int *)realloc(p, 100 * sizeof(int));//调很大,两个地址不同 ,释放原来的内存空间   for (int i = 0; i <2; ++i)   {   printf("%d   ", p3[i]);   }    printf("\np地址:  %p   ,  p3的地址:  %p   ", p,  p3);   return 0;}

怎么在C语言中实现内存管理

8. strcpy、memcpy、memmove函数

头文件:

#include <string.h>

strcpy函数

char *strcpy(  char *strDestination,  const char *strSource);

class="lazy" data-src所指由\0结束的字符串复制到dest所指的数组中。

注意事项:

class="lazy" data-srcdest所指内存区域不能重叠,且dest必须有足够的空间来容纳class="lazy" data-src的字符串,class="lazy" data-src的结尾必须是'\0',返回指向dest的指针。

memcpy函数

void *memcpy(  void *dest,  const void *class="lazy" data-src,  size_t count);

class="lazy" data-src所指内存区域复制 count个字节到dest所指内存区域。

注意事项:

函数返回指向dest的指针和 strcpy相比,memcpy不是遇到\0就结束,而一定会拷贝n个字节注意class="lazy" data-srcdest所指内存区域不能重叠,否则不能保证正确。

memmove函数

void *memmove(  void *dest,  const void *class="lazy" data-src,  size_t count);

函数功能:与 memcpy相同。

注意事项:

class="lazy" data-srcdest所指内存区域可以重叠memmove可保证拷贝结果正确,而memcpy不能保证。函数返回指向dest的指针。

memset函数

void *memset(  void *dest,  int c,  size_t count);

常用于內存空间的初始化。将已开辟内存空间s的首n个字节的值设为值c,并返回s

示例代码:

#include<stdio.h> #include<string.h>#include<assert.h> //模拟memcpy函数实现void  *  MyMemcpy(void *dest, const void *source, size_t count){   assert((NULL != dest) && (NULL != source));   char *tmp_dest = (char *)dest;   char *tmp_source = (char *)source;   while (count--)//不判断是否重叠区域拷贝   *tmp_dest++ = *tmp_source++;   return dest;}//模拟memmove函数实现void * MyMemmove(void *dest, const void *class="lazy" data-src, size_t n){   char temp[256];   int i;   char *d =(char*) dest;   const char *s =(char *) class="lazy" data-src;   for (i = 0; i < n; i++)   temp[i] = s[i];   for (i = 0; i < n; i++)   d[i] = temp[i];   return dest;}int  main(){    //strcpy进行字符串拷贝     //注意:  1. class="lazy" data-src字符串必须以'\0'结束,  2. dest内存大小必须>=class="lazy" data-src   char  a[5];   //char  b[5] = "ABC";//字符串结尾会自动的有\0 , 此处 b[4]就是'\0'    char  b[5];   b[0] = 'A';   b[1] = 'B';   b[2] = 'C';   b[3] = '\0';//必须加\0,否则strcpy一直向后寻找\0   strcpy(a, b);   printf("%s\n", a);   //memcpy函数, 直接拷贝内存空间,指定拷贝的大小   int   a2[5];   int   b2[5] = { 1,2,3,4,5 };//不需要'\0'结束   memcpy(a2, b2,   3 *sizeof(int)   );//指定拷贝的大小, 单位  字节数   printf("%d , %d  ,%d\n" , a2[0] ,  a2[1],  a2[2]);   MyMemcpy(a2 + 3, b2 + 3,   2 * sizeof(int));   printf("%d , %d \n", a2[3], a2[4]);   //演示内存重叠的情况   char  a3[6] = "123";   //MyMemcpy(a3 + 1, a3, 4); //得到11111   memcpy(a3 + 1, a3, 4);//虽然它是正确的,但是不保证,重叠拷贝应该避免使用它   printf("%s\n", a3);   //memmove功能与memcpy一样,但是了考虑了重叠拷贝的问题,可以保证正确   char  a4[6] = "123";   //MyMemmove(a4 + 1, a4, 4);//可以保证正确   memmove(a4 + 1, a4, 4);//可以保证正确   printf("%s\n", a4);   //memset比较简单, 把内存区域初始化化为某个值   char a5[6];   memset(a5, 0, 6);   for (int i = 0; i < 6; ++i)   {   printf("%d", a5[i]);   }   return 0;}

怎么在C语言中实现内存管理

9. 实现动态数组

思路:

利用 realloc函数,当数组元素满的时候,扩充内存区域,然后加入元素!

示例代码:

#include<stdio.h>#include<stdlib.h>#include<assert.h>//为了代码的可读性,将设计为C++中的类,利用struct 代替//动态数组struct  Array{   //自动构造函数,它初始化   Array()   {   grow = 3;   size = 3;   n = 0;   //分配并初始化内存   pHead = (int  *)calloc(size  , sizeof(int));   assert(pHead != NULL);    }   void   AddElem(int  e)   {   if (n >= size)//说明数组满了   {   //需要扩大内存   size += grow;    pHead = (int  *)realloc( pHead,   size * sizeof(int)  );   assert(pHead != NULL);   }   pHead[n++] = e; //添加元素   }   void  Print()   {   printf("\n\n数组总空间:%d   ,   元素个数: %d  \n",  size,  n);   for (int i = 0; i < n; ++i)   {   printf("%d  " ,  pHead[i]);   }    }   int   size;//总空间, 不是固定的,可以增大的   int   n;//当前数组的元素个数   int   grow;//每次数组内存满了的时候,增长量   int   *pHead;//数组的起始地址};int  main(){   Array  arr;    arr.AddElem(1);   arr.AddElem(2);   arr.AddElem(3);   arr.AddElem(4);   arr.AddElem(5);   arr.AddElem(6);   arr.AddElem(7);   arr.AddElem(8);     arr.Print();    arr.AddElem(11);   arr.AddElem(22);   arr.AddElem(33);   arr.AddElem(44);   arr.AddElem(55);     arr.Print();   return  0;}

怎么在C语言中实现内存管理

10. 内存越界

何谓內存访问越界,简单的说,你向系统申请了一块内存,在使用这块内存的时候,超出了你申请的范围。

  • 访问到野指针指向的区域,越界访问

  • 数组下标越界访问

  • 使用已经释放的内存

  • 企图访问一段释放的栈空间

  • 容易忽略 字符串后面的'\0'

注意:

strlen所作的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符'\0'为止,然后返回计数器值( 长度不包含'\0')。

示例代码:

#include<stdio.h>#include<stdlib.h>#include<string.h>char  * fun(){   char arr[10];    return  arr;}//arr是栈内存,离开此花括号,栈被释放回收int main(){   //1.访问到野指针指向的区域,越界访问   char  *p;//没有初始化,野指针,乱指一气   //strcpy(p, "hello");//非法越界访问   //2.数组下标越界访问   int   * p2 = (int *)calloc(10, sizeof(int));   for (size_t i = 0; i <= 10; i++)   {   p2[i] = i;//很难察觉的越界访问, 下标越界   }   //3.使用已经释放的内存   char *p3 = (char *)malloc(10);   free(p3);   if (p3 != NULL)//这里if不起作用   {   strcpy(p3, "hello");//错误,p3已经被释放   }   //4.企图访问一段释放的栈空间   char *p4 = fun();  //p4指向的栈空间已经被释放   strcpy(p4, "hello");   printf("%s\n",p4);   //5.容易忽略 字符串后面的'\0'   char  *p5 = (char *)malloc(strlen("hello"));//忘记加1   strcpy(p5, "hello");//导致p5的长度不够,越界   return 0;}

内存泄露(Memory Leak)

是指程序中己动态分配的堆內存由于某种原因程序未释放或无法释放,造成系统內存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

  • 丢失了分配的内存的首地址,导致无法释放

  • 丢失分配的内存地址

  • 企图希望传入指针变量获取对内存,殊不知是拷贝

  • 每循环一次,泄露一次内存

  • 非法访问常量区

示例代码:

#include<stdio.h>#include<stdlib.h>#include<string.h>char  * GetBuf(){   return  (char *)malloc(10);}void  GetBuf2(char *p)//p已经是一份拷贝,和原参数无任何关系{   p= (char *)malloc(10);}char  * GetBuf3(){   char  *p = "hello";//常量内存区,不可更改   return p;}int main(){   //1.丢失了分配的内存的首地址,导致无法释放   GetBuf();//忘记接收返回值了   //2.丢失分配的内存地址   char  *p1= (char *)malloc(10);   char  *p2 = (char *)malloc(10);   p1 = p2;//这一步,导致第一次分配的堆内存丢失,无法释放   //3.企图希望传入指针变量获取对内存,殊不知是拷贝   char  *p3 = NULL;   GetBuf2(p3); //应该使用指针的指针,或者引用   //strcpy(p3, "hello"); //错误,这里的p3仍然为NULL   //4.每循环一次,泄露一次内存   char  * p4 = NULL;   for (int i = 0; i < 10; ++i)   {   p4= (char *)malloc(10);   }   strcpy(p4, "hello"); // 这里的p4只指向最后一次分配的,前面的全部内存泄漏   //5.非法访问常量区   char *p5 = GetBuf3();   strcpy(p5, "hello");     return 0;}

12. 内存池技术简介

内存碎片:

内存碎片一般是由于空闲的內存空间比要连续申请的空间小,导致这些小内存块不能被充分的利用,当你需要分配大的连续内存时,尽管剩余内存的总和足够,但系统找不到连续的内存,所以导致分配失败malloc/free大量使用会造成内存碎片

为什么会产生内存碎片?

如果有100个单位的连续空闲内存,那么先申请5单元的连续内存,再申请50单元的内存这时释放一开始的5单元的内存。这时,如果你一直申请比5单元大的内存单元,那么开始的那连续的5单元就一直不能被使用。

内存池技术:

内存的申请、释放是低效的,我们只在开始申请一块大內存(不够继续申请),然后每次需要时都从这块内存取出,并标记这块内存是否被使用。释放时仅仅标记而不真的free,只有内存都空闲的时候,才释放给操作系统。这样减少了 mallocfree次数,从而提高效率。

13. C语言实现内存池

设计思路:

先分配几个大的连续内存块(MemoryBlock),每个内存块用链表链接起来,然后通过一个內存池结构(MemoryPool)管理!

代码实现:

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<assert.h>class  MemoryBlock{public:   int             nSize; //该内存块的总大小 (单元个数X每个单元大小),以字节为单位   int             nFree;  //该内存块还有多少个空闲的单元   int             nFirst; //当前可用空闲单元的序号,从0开始   MemoryBlock*    pNext;  //指向下一个MemoryBlock内存块   char            aData[1]; //用于标记分配内存开始的位置     //.....这个结构下面全是内存public:   MemoryBlock(int  unitCount, int  unitSize)   {    nSize = unitCount* unitSize;    nFree = unitCount;    nFirst = 0;    pNext = NULL;    char  *p = aData;//获取内存单元的首地址    for (int i = 0; i < unitCount -1; ++i)    {    *((short *)p) = i + 1; //第0块的下个空闲索引是不是第1块     p += unitSize;    }    *((short *)p) = -1;//最后一块没有下一个空闲空间了,为-1   }   void  *  operator new (size_t  t,  int   size)   {    int  headSize = sizeof(MemoryBlock);         return   ::operator  new(headSize + size);   }};//分配固定内存的内存池class  MemoryPool{public:   //初始大小 (每一个MemoryBlock中初始的单元个数)   int             nInitCount;    //(后面增加的MemoryBlock中单元个数)      int             nGrowSize;        //分配单元大小,MemoryBlock中每个单元的大小   int             nUnitSize;    //内存块链表   MemoryBlock*    pBlock;public:   MemoryPool( int  _nInitCount, int  _nGrowSize, int _nUnitSize)   {   nInitCount = _nInitCount;   nGrowSize = _nGrowSize;   nUnitSize = _nUnitSize;   pBlock = NULL;   }   char  *  Alloc() //每次只返回 nUnitSize 大小的内存   {   if (pBlock == NULL)   {    MemoryBlock  *   p =(MemoryBlock  *) new (nInitCount * nUnitSize) MemoryBlock(nInitCount, nUnitSize);    assert(p != NULL);    pBlock = p;   }   MemoryBlock  *  pB = pBlock;   while (pB !=NULL  &&   pB->nFree==0)   {   pB = pB->pNext;   }   if (pB == NULL)//一直没找到了可以分配的MemoryBlock,说明内存池已满   {   pB = (MemoryBlock  *) new (nGrowSize  * nUnitSize) MemoryBlock(nGrowSize, nUnitSize);   assert(pB != NULL);   pB->pNext = pBlock;   pBlock = pB;    }   //得到第一个可用的空闲内存地址   char *pFree = pB->aData + pB->nFirst * nUnitSize;   //把nFirst值改为下一个空闲的索引 (存储在当前内存的前两个字节)   pB->nFirst = *((short*)pFree);   pB->nFree--;   return  pFree;     }   void   Free(void  *p)   {     //考虑这个地址落在哪个 MemoryBlock 上   MemoryBlock  *  pB = pBlock;   while (pB  != NULL  &&   p <  pB->aData   ||  p > pB->aData+  pB->nSize   )   {   pB = pB->pNext;   }       if (pB!= NULL)//找到了p所在的MemoryBlock   {    //销毁之前先让它的前两个字节指向nFirst (当前空闲的索引)   *((short*)p) = pB->nFirst;    //nFirst的值指向当前释放的    pB->nFirst = ((char *)p - pB->aData) / nUnitSize;    pB->nFree++;   }   else   {   printf("错误,此内存并非内存池分配的!\n");   }   }   void  Print()   {   printf("\n\n\n");   MemoryBlock  *  pB = pBlock;   while (pB != NULL )   {   printf("\n首地址:%p   总大小:%d   空闲个数: %d   下一个空闲:%d  \n",   pB->aData ,  pB->nSize, pB->nFree ,pB->nFirst);   for (int i = 0; i < pB->nSize / nUnitSize; ++i)   {   printf("\t %d" ,  *  ((int *) ( pB->aData + i * nUnitSize )));   }       pB = pB->pNext;   printf("\n---------------------------------------------------------\n");   }   }};int main(){   MemoryPool   pool(3, 3, 4);   int  *p1 = (int *)pool.Alloc();   *p1 = 111;   int  *p2 = (int *)pool.Alloc();   *p2 = 222;       int  *p3 = (int *)pool.Alloc();   *p3 = 333;   pool.Print();   int  *p4 = (int *)pool.Alloc();   *p4 = 444;   pool.Print();   int  *p5 = (int *)pool.Alloc();   *p5 = 555;   pool.Print();   pool.Free( p1);   pool.Free(p2);   pool.Free(p3);   pool.Print();    p1 = (int *)pool.Alloc();   *p1 = 111;    p2 = (int *)pool.Alloc();   *p2 = 222;    p3 = (int *)pool.Alloc();   *p3 = 333;   pool.Print();   return 0;}

关于怎么在C语言中实现内存管理就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

怎么在C语言中实现内存管理

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

怎么在C语言中实现内存管理

这篇文章给大家介绍怎么在C语言中实现内存管理,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C语言是什么C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发,使用C语言可以以简易的方式编译、处理低级存储器
2023-06-14

C语言/C++内存管理是什么

本篇内容介绍了“C语言/C++内存管理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、内存在计算机中,每个应用程序之间的内存是相互独
2023-06-16

C++内存管理中简易内存池怎么实现

这篇文章主要介绍“C++内存管理中简易内存池怎么实现”,在日常操作中,相信很多人在C++内存管理中简易内存池怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++内存管理中简易内存池怎么实现”的疑惑有所
2023-06-22

C语言中动态内存管理实例分析

今天小编给大家分享一下C语言中动态内存管理实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1.动态内存开辟的原因常见的
2023-07-02

C语言与C++中内存管理的方法

这篇文章主要介绍了C语言与C++中内存管理的方法的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言与C++中内存管理的方法文章都会有所收获,下面我们一起来看看吧。内存分布主要段及其分布每个程序运行起来以后,它
2023-06-30

C语言动态内存管理的原理及实现方法

C语言动态内存管理的原理是通过malloc()函数申请一块连续的内存空间,并返回其地址,通过free()函数释放该内存空间。实现方法是通过在程序运行时动态地管理内存,即在需要内存时申请,不需要时释放,避免了静态内存分配的浪费和不足
2023-05-16

Go语言和C语言在内存管理方面的差异

Go语言和C语言是两种常用的编程语言,它们在内存管理方面有着明显的差异。本文将通过具体的代码示例来展示这两种语言在内存管理方面的不同之处。首先,让我们先来看看C语言中的内存管理。在C语言中,程序员通常需要手动分配和释放内存,这可能会导致内
Go语言和C语言在内存管理方面的差异
2024-03-10

C++ 内存管理如何与 C 语言的内存管理进行交互?

c++++ 内存管理与 c 语言的交互:兼容性:c++ 与 c 语言兼容,可以使用 c 中的指针和数组。指针和数组:c++ 指针和数组与 c 语言中类似,但 c++ 允许通过指针直接操纵内存。动态内存分配:c++ 引入了 new 和 del
C++ 内存管理如何与 C 语言的内存管理进行交互?
2024-05-24

不同语言中内存管理与Go语言内存管理的差异

go 语言的内存管理与传统语言(如 c++++、java)不同:传统语言:采用手动内存管理,程序员负责分配和释放内存块。go 语言:采用垃圾回收(gc),自动管理内存,程序员无需手动管理。这种差异导致了以下不同点:手动管理 vs. 自动管理
不同语言中内存管理与Go语言内存管理的差异
2024-04-11

详解C语言中的动态内存管理

对于数据的存储我们可以静态存储,也可以动态存储,两种方式都有自己特有的好处,这篇文章教我们如和进行动态的数据存储!!!!感兴趣的小伙伴可以跟随小编一起学习一下
2022-12-12

C语言中数据在内存中是怎么存储的

本篇文章为大家展示了C语言中数据在内存中是怎么存储的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。数据类型常见的数据类型常见的数据类型字节char字符数据类型1short短整型2int整形4long
2023-06-22

Python中怎么实现内存管理

这篇文章将为大家详细讲解有关Python中怎么实现内存管理,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。对象的内存使用赋值语句是语言最常见的功能了。但即使是最简单的赋值语句,也可以很有内涵。
2023-06-15

C语言怎么实现停车场管理

这篇文章主要介绍了C语言怎么实现停车场管理的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C语言怎么实现停车场管理文章都会有所收获,下面我们一起来看看吧。1.问题描述停车场内只有一个可停放n辆汽车的狭长通道,且只
2023-06-29

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录