小甲鱼 P48 内存池---通讯录管理程序
通讯录管理程序
#include <stdio.h> #include <stdlib.h> #include <string.h> 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 **contacts); 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("联系人:%s\n", person->name); printf("电话:%s\n", 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 *temp; 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; }
内存池(Memory pool)
为什么需要内存池?
因为使用malloc函数和free函数,需要从应用层转到内核层进行申请或释放,存在时间的消耗问题。
在内存中申请了A、B、C三块内存,当A、B、C都不需要使用的时候,把它释放,并不是调用free函数还给内存,而是把它们扔到内存池里面去。
如果这时候,恰好需要同样尺寸的内存,不需要调用malloc函数在内存中申请,直接从内存池中拿出来用就可以了。
内存池是让程序额外维护一个缓存区域。
当用户申请一块内存块的时候,在内存池中查找是否有合适的垃圾内存块,如果有,直接从内存池中取出来使用。如果没有,再调用malloc函数申请。
当用户释放一块内存块时候,检查内存池中有没有空间,如果有空间,把用户释放的内存块放到内存池里面,让下一次申请可以直接从内存池中取。
使用单链表来维护一个简单的内存池。
只需要将没有用的内存空间地址依次用一个单链表记录下来;当再次需要的时候,从这个单链表中获取即可。
内存池实际就是维护多一个单链表,用这个单链表来记录没有用的内存空间。
好像例子的删除一个联系人时候, 先别调用free释放,放到内存池,下一次再需要的时候,从我这里拿。
只需要在addPerson函数、delPerson函数和main函数修改一下就OK了。
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 1024 //定义内存池的空间1024 struct Person { char name[40]; char phone[20]; struct Person *next; }; //定义内存池为全局变量 //在调用 addPerson时,在内存池中检查,是否有废弃的空间直接可以拿来使用 //在调用 delPerson时,删除联系人时,把联系人放到内存池里面,检查内存池的空间是否合适 struct Person *pool = NULL;//内齿池的单链表 int count;//统计里面有多少块垃圾 void getInput(struct Person *person); void printPerson(struct Person *person); void addPerson(struct Person **contacts); 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用 { person = pool; pool = pool->next; count--;//内存池少了一块垃圾内存 } //如果内存池为空,则调用mallc函数申请新的内存空间 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("联系人:%s\n", person->name); printf("电话:%s\n", person->phone); } struct Person *findPerson(struct Person *contacts) { struct Person *current; char input[40]; printf("请输入联系人:"); scanf("%s", input); current = contacts; //PS:找到符合条件就不进入循环了 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 *temp; struct Person *person; struct Person *current; struct Person *previous; //先找到待删除的节点指针 person = findPerson(*contacts); if (person == NULL) { printf("找不到该联系人!\n"); } else { current = *contacts; previous = NULL; //current定位到待删除的节点 //PS:找到符合条件就不进入循环了 while(current != NULL && current != person) { previous = current; current = current->next; } if (previous == NULL) { //待删除的节点是第一个节点 *contacts = current->next; } else { //待删除的节点不是第一个节点 previous->next = current->next; } // 判断内存池是不是有空位,限制内存池的尺寸,容量MAX1024 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; }