小甲鱼 P48 内存池---通讯录管理程序--单链表的应用

小甲鱼 P48 内存池---通讯录管理程序

 

小甲鱼 P45 单链表1---头插法

小甲鱼 P46 单链表2---尾插法和遍历

小甲鱼 P47 单链表3---单链表插入和删除

 

通讯录管理程序

#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;
}