芯源半导体CW32
直播中

陆军航空兵

9年用户 895经验值
私信 关注
[经验]

C语言内存池使用

C语言的内存管理,从来都是一个让人头秃的问题。要想更自由地管理内存,就必须去堆中申请,然后还需要考虑何时释放,万一释放不当,或者没有及时释放,造成的后果都是难以估量的。

当然如果就这些,那倒也还不算什么。问题就在于,如果大量地使用malloc和free函数来申请内存,首先使要经历一个从应用层切入系统内核层,调用完成之后,再返回应用层的一系列步骤,实际上使非常浪费时间的。更重要的是,还会产生大量的内存碎片。比如,先申请了一个1KB的空间,紧接着又申请了一个8KB的空间。而后,这个1KB使用完了,被释放,但是这个空间却只有等到下一次有刚好1KB的空间申请,才能够被重新调用。这么一来,极限情况下,整个堆有可能被弄得支离破碎,最终导致大量内存浪费。

那么这种情况下,我们解决这类问题的思路,就是创建一个内存池。

内存池,实际上就是我们让程序创建出来的一块额外的缓存区域,如果有需要释放内存,先不必使用free函数,如果内存池有空,那么直接放入内存池。同样的道理,下一次程序申请空间的时候,先检查下内存池里面有没有合适的内存,如果有,则直接拿出来调用,如果没有,那么再使用malloc。

其实内存池我们就可以使用单链表来进行维护,下面通过一个通讯录的程序来说明内存池的运用。

普通的版本:



  • //Example 04 V1
  • #include
  • #include
  • #include

  • struct Person
  • {
  • char name[40];
  • char phone[20];
  • struct Person* next;
  • };

  • void getinput(struct Person* person);
  • void printPerson(struct Person* person);
  • void addPerson(struct Person** contects);
  • void changePerson(struct Person* contacts);
  • void delPerson(struct Person** contacts);
  • struct Person* findPerson(struct Person* contacts);
  • void displayContacts(struct Person* contacts);
  • void releaseContacts(struct Person** contacts);

  • void getInput(struct Person* person)
  • {
  • printf("请输入姓名:");
  • scanf("%s", person->name);
  • printf("请输入电话:");
  • scanf("%s", person->phone);
  • }

  • void addPerson(struct Person** contacts)
  • {
  • struct Person* person;
  • struct Person* temp;

  • person = (struct Person*)malloc(sizeof(struct Person));
  • if (person == NULL)
  • {
  •   printf("内存分配失败!n");
  •   exit(1);
  • }

  • getInput(person);

  • //将person添加到通讯录中
  • if (*contacts != NULL)
  • {
  •   temp = *contacts;
  •   *contacts = person;
  •   person->next = temp;
  • }
  • else
  • {
  •   *contacts = person;
  •   person->next = NULL;
  • }
  • }

  • void printPerson(struct Person* person)
  • {
  • printf("联系人:%sn", person->name);
  • printf("电话:%sn", person->phone);
  • }

  • struct Person* findPerson(struct Person* contacts)
  • {
  • struct Person* current;
  • char input[40];

  • printf("请输入联系人:");
  • scanf("%s", input);

  • current = contacts;
  • while (current != NULL    strcmp(current->name, input))
  • {
  •   current = current->next;
  • }

  • return current;
  • }

  • void changePerson(struct Person* contacts)
  • {
  • struct Person* person;

  • person = findPerson(contacts);
  • if (person == NULL)
  • {
  •   printf("找不到联系人!n");
  • }
  • else
  • {
  •   printf("请输入联系电话:");
  •   scanf("%s", person->phone);
  • }
  • }

  • void delPerson(struct Person** contacts)
  • {
  • struct Person* person;
  • struct Person* current;
  • struct Person* previous;

  • //先找到待删除的节点的指针
  • person = findPerson(*contacts);
  • if (person == NULL)
  • {
  •   printf("找不到该联系人!n");
  • }
  • else
  • {
  •   current = *contacts;
  •   previous = NULL;

  •   //将current定位到待删除的节点
  •   while (current != NULL    current != person)
  •   {
  •    previous = current;
  •    current = current->next;
  •   }

  •   if (previous == NULL)
  •   {
  •    //若待删除的是第一个节点
  •    *contacts = current->next;
  •   }
  •   else
  •   {
  •    //若待删除的不是第一个节点
  •    previous->next = current->next;
  •   }

  •   free(person);//将内存空间释放
  • }
  • }

  • void displayContacts(struct Person* contacts)
  • {
  • struct Person* current;

  • current = contacts;
  • while (current != NULL)
  • {
  •   printPerson(current);
  •   current = current->next;
  • }
  • }

  • void releaseContacts(struct Person** contacts)
  • {
  • struct Person* temp;

  • while (*contacts != NULL)
  • {
  •   temp = *contacts;
  •   *contacts = (*contacts)->next;
  •   free(temp);
  • }
  • }

  • int main(void)
  • {
  • int code;
  • struct Person* contacts = NULL;
  • struct Person* person;

  • printf("| 欢迎使用通讯录管理程序 |n");
  • printf("|--- 1:插入新的联系人 ---|n");
  • printf("|--- 2:查找现有联系人 ---|n");
  • printf("|--- 3:更改现有联系人 ---|n");
  • printf("|--- 4:删除现有联系人 ---|n");
  • printf("|--- 5:显示当前通讯录 ---|n");
  • printf("|--- 6:退出通讯录程序 ---|n");

  • while (1)
  • {
  •   printf("n请输入指令代码:");
  •   scanf("%d",  code);
  •   switch (code)
  •   {
  •   case 1:addPerson( contacts); break;
  •   case 2:person = findPerson(contacts);
  •    if (person == NULL)
  •    {
  •     printf("找不到该联系人!n");
  •    }
  •    else
  •    {
  •     printPerson(person);
  •    }
  •    break;
  •   case 3:changePerson(contacts); break;
  •   case 4:delPerson( contacts); break;
  •   case 5:displayContacts(contacts); break;
  •   case 6:goto END;
  •   }
  • }

  • END://此处直接跳出恒循环
  • releaseContacts( contacts);

  • return 0;

  • }


运行结果如下:

复制

  • //Consequence 04 V1
  • | 欢迎使用通讯录管理程序 |
  • |--- 1:插入新的联系人 ---|
  • |--- 2:查找现有联系人 ---|
  • |--- 3:更改现有联系人 ---|
  • |--- 4:删除现有联系人 ---|
  • |--- 5:显示当前通讯录 ---|
  • |--- 6:退出通讯录程序 ---|

  • 请输入指令代码:1
  • 请输入姓名:HarrisWilde
  • 请输入电话:0101111

  • 请输入指令代码:1
  • 请输入姓名:Jack
  • 请输入电话:0101112

  • 请输入指令代码:1
  • 请输入姓名:Rose
  • 请输入电话:0101113

  • 请输入指令代码:2
  • 请输入联系人:HarrisWilde
  • 联系人:HarrisWilde
  • 电话:0101111

  • 请输入指令代码:2
  • 请输入联系人:Mike
  • 找不到该联系人!

  • 请输入指令代码:5
  • 联系人:Rose
  • 电话:0101113
  • 联系人:Jack
  • 电话:0101112
  • 联系人:HarrisWilde
  • 电话:0101111

  • 请输入指令代码:3
  • 请输入联系人:HarrisWilde
  • 请输入联系电话:0101234

  • 请输入指令代码:5
  • 联系人:Rose
  • 电话:0101113
  • 联系人:Jack
  • 电话:0101112
  • 联系人:HarrisWilde
  • 电话:0101234

  • 请输入指令代码:6


下面加入内存池:



  • //Example 04 V2
  • #include
  • #include
  • #include

  • #define MAX 1024

  • struct Person
  • {
  • char name[40];
  • char phone[20];
  • struct Person* next;
  • };

  • struct Person* pool = NULL;
  • int count;

  • void getInput(struct Person* person);
  • void printPerson(struct Person* person);
  • void addPerson(struct Person** contects);
  • void changePerson(struct Person* contacts);
  • void delPerson(struct Person** contacts);
  • struct Person* findPerson(struct Person* contacts);
  • void displayContacts(struct Person* contacts);
  • void releaseContacts(struct Person** contacts);
  • void releasePool(void);

  • void getInput(struct Person* person)
  • {
  • printf("请输入姓名:");
  • scanf("%s", person->name);
  • printf("请输入电话:");
  • scanf("%s", person->phone);
  • }

  • void addPerson(struct Person** contacts)
  • {
  • struct Person* person;
  • struct Person* temp;

  • //如果内存池不是空的,那么首先从里面获取空间
  • if (pool != NULL)
  • {
  •   person = pool;
  •   pool = pool->next;
  •   count--;
  • }
  • //内存池为空,则直接申请
  • else
  • {
  •   person = (struct Person*)malloc(sizeof(struct Person));
  •   if (person == NULL)
  •   {
  •    printf("内存分配失败!n");
  •    exit(1);
  •   }
  • }


  • getInput(person);

  • //将person添加到通讯录中
  • if (*contacts != NULL)
  • {
  •   temp = *contacts;
  •   *contacts = person;
  •   person->next = temp;
  • }
  • else
  • {
  •   *contacts = person;
  •   person->next = NULL;
  • }
  • }

  • void printPerson(struct Person* person)
  • {
  • printf("联系人:%sn", person->name);
  • printf("电话:%sn", person->phone);
  • }

  • struct Person* findPerson(struct Person* contacts)
  • {
  • struct Person* current;
  • char input[40];

  • printf("请输入联系人:");
  • scanf("%s", input);

  • current = contacts;
  • while (current != NULL    strcmp(current->name, input))
  • {
  •   current = current->next;
  • }

  • return current;
  • }

  • void changePerson(struct Person* contacts)
  • {
  • struct Person* person;

  • person = findPerson(contacts);
  • if (person == NULL)
  • {
  •   printf("找不到联系人!n");
  • }
  • else
  • {
  •   printf("请输入联系电话:");
  •   scanf("%s", person->phone);
  • }
  • }

  • void delPerson(struct Person** contacts)
  • {
  • struct Person* person;
  • struct Person* current;
  • struct Person* previous;
  • struct Person* temp;
  • {

  • };

  • //先找到待删除的节点的指针
  • person = findPerson(*contacts);
  • if (person == NULL)
  • {
  •   printf("找不到该联系人!n");
  • }
  • else
  • {
  •   current = *contacts;
  •   previous = NULL;

  •   //将current定位到待删除的节点
  •   while (current != NULL    current != person)
  •   {
  •    previous = current;
  •    current = current->next;
  •   }

  •   if (previous == NULL)
  •   {
  •    //若待删除的是第一个节点
  •    *contacts = current->next;
  •   }
  •   else
  •   {
  •    //若待删除的不是第一个节点
  •    previous->next = current->next;
  •   }

  •   //判断内存池中有没有空位
  •   if (count < MAX)
  •   {
  •    //使用头插法将person指向的空间插入内存池中
  •    if (pool != NULL)
  •    {
  •     temp = pool;
  •     pool = person;
  •     person->next = temp;
  •    }
  •    else
  •    {
  •     pool = person;
  •     person->next = NULL;
  •    }
  •    count++;
  •   }
  •   //没有空位,直接释放
  •   else
  •   {
  •    free(person);//将内存空间释放
  •   }
  • }
  • }

  • void displayContacts(struct Person* contacts)
  • {
  • struct Person* current;

  • current = contacts;
  • while (current != NULL)
  • {
  •   printPerson(current);
  •   current = current->next;
  • }
  • }

  • void releaseContacts(struct Person** contacts)
  • {
  • struct Person* temp;

  • while (*contacts != NULL)
  • {
  •   temp = *contacts;
  •   *contacts = (*contacts)->next;
  •   free(temp);
  • }
  • }

  • void releasePool(void)
  • {
  • struct Person* temp;
  • while (pool != NULL)
  • {
  •   temp = pool;
  •   pool = pool->next;
  •   free(temp);
  • }
  • }

  • int main(void)
  • {
  • int code;
  • struct Person* contacts = NULL;
  • struct Person* person;

  • printf("| 欢迎使用通讯录管理程序 |n");
  • printf("|--- 1:插入新的联系人 ---|n");
  • printf("|--- 2:查找现有联系人 ---|n");
  • printf("|--- 3:更改现有联系人 ---|n");
  • printf("|--- 4:删除现有联系人 ---|n");
  • printf("|--- 5:显示当前通讯录 ---|n");
  • printf("|--- 6:退出通讯录程序 ---|n");

  • while (1)
  • {
  •   printf("n请输入指令代码:");
  •   scanf("%d",  code);
  •   switch (code)
  •   {
  •   case 1:addPerson( contacts); break;
  •   case 2:person = findPerson(contacts);
  •    if (person == NULL)
  •    {
  •     printf("找不到该联系人!n");
  •    }
  •    else
  •    {
  •     printPerson(person);
  •    }
  •    break;
  •   case 3:changePerson(contacts); break;
  •   case 4:delPerson( contacts); break;
  •   case 5:displayContacts(contacts); break;
  •   case 6:goto END;
  •   }
  • }

  • END://此处直接跳出恒循环
  • releaseContacts( contacts);
  • releasePool();

  • return 0;

  • }

更多回帖

发帖
×
20
完善资料,
赚取积分