中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在C語言中實現內存管理

發布時間:2021-05-06 16:25:28 來源:億速云 閱讀:282 作者:Leah 欄目:開發技術

這篇文章給大家介紹怎么在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
);

src所指由\0結束的字符串復制到dest所指的數組中。

注意事項:

srcdest所指內存區域不能重疊,且dest必須有足夠的空間來容納src的字符串,src的結尾必須是'\0',返回指向dest的指針。

memcpy函數

void *memcpy(
  void *dest,
  const void *src,
  size_t count
);

src所指內存區域復制 count個字節到dest所指內存區域。

注意事項:

函數返回指向dest的指針和 strcpy相比,memcpy不是遇到\0就結束,而一定會拷貝n個字節注意srcdest所指內存區域不能重疊,否則不能保證正確。

memmove函數

void *memmove(
  void *dest,
  const void *src,
  size_t count
);

函數功能:與 memcpy相同。

注意事項:

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 *src, size_t n)
{
   char temp[256];
   int i;
   char *d =(char*) dest;
   const char *s =(char *) 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. src字符串必須以'\0'結束,  2. dest內存大小必須>=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;
}

11. 內存泄露(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語言中實現內存管理就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

全南县| 建始县| 山丹县| 鲁山县| 泌阳县| 禄丰县| 贺州市| 太康县| 丹东市| 鲁甸县| 乐安县| 香格里拉县| 龙南县| 卓资县| 德保县| 兴海县| 宝坻区| 孟州市| 西畴县| 香港| 达拉特旗| 德保县| 沙坪坝区| 介休市| 焦作市| 乐昌市| 荣昌县| 崇州市| 恩平市| 景德镇市| 长海县| 报价| 临夏县| 深圳市| 德清县| 宽城| 兴业县| 甘南县| 宣威市| 怀远县| 沙湾县|