通讯录管理系统(C语言实现) 动态扩容,文件读写

通讯录可以用来存储个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址。而一个通讯录的管理系统,应该至少具备增、删、查、改等几项功能,并要对其进行拓展。
所以我们要实现的功能如下:

  1. 添加联系人信息
  2. 删除指定联系人信息
  3. 查找指定联系人信息
  4. 修改指定联系人信息
  5. 显示所有联系人信息
  6. 清空所有联系人
  7. 对联系人进行排序
  8. 通讯录应该是可扩容而非定长的
  9. 通讯录的数据应该存储在文件当中,以便多次使用

明确了目标,下面开始实现。

首先我们要选择合适的数据结构,对于这种线性的通讯录,顺序表无疑是最好的选择,在设置结构体的同时,还需要考虑到内存对齐的因素,将占用空间较小的成员尽量集中到一起。
同时为了通讯录的长度合适,我们运用了动态内存管理,当通讯录不够时自动扩容

typedef struct info
{
	char name[NAME_MAX_SIZE];
	char tel[TEL_MAX_SIZE];
	char addr[ADDR_MAX_SIZE];
	char gender[GENDER_MAX_SIZE];
	int age;
	//先存放四个字符型再存放整形,利用内存对齐来达到空间利用最大化
}info;

typedef struct 
{
	info* data;
	int capacity;
	int size;
}contact, *pcontact;
//采用顺序表的数据类型来存放数据

首先我们要对通讯录进行初始化

void InitContact(pcontact p)
{
	p->data = (info*)malloc(CONTACT_SIZE * sizeof(info));
	if (NULL == p->data)
	{
		printf("初始化失败!!!\n");
		exit(0);
	}
	p->capacity = CONTACT_SIZE;
	p->size = 0;
}

通讯录扩容

int CheckCapacity(pcontact p)
{
	assert(p);
	if (p->size == p->capacity)
	{
		printf("通讯录已满,进行扩容\n");
		;
		info *temp = realloc(p->data, (p->capacity + CONTACT_SIZE) * sizeof(info)); 
		if (NULL == temp)
		{
			printf("扩容失败\n");
			return 0;
		}
		else
		{
			p->data = temp;
			p->capacity += CONTACT_SIZE;
			printf("扩容成功!!!\n");
		}
	}
	return 1;
}

添加联系人信息

void AddContact(pcontact p)
{
	assert(p); //防止传入空指针,后面会一直使用
	system("cls");  //清空之前的屏幕,防止画面太过杂乱
	if (0 == CheckCapacity(p))  //判断通讯录是否已满,如果通讯录满且扩容失败将返回
	{
		printf("通讯录已满,添加失败\n");
		return;
	}
	printf("请输入姓名:\n");
	scanf("%s", p->data[p->size].name);
	printf("请输入电话:\n");
	scanf("%s", p->data[p->size].tel);
	printf("请输入性别:\n");
scanf("%s", p->data[p->size].gender);
	printf("请输入地址:\n");
	scanf("%s", p->data[p->size].addr);
	printf("请输入年龄:\n");
	scanf("%d", &(p->data[p->size].age));

	printf("添加成功!!!\n");
	p->size++;
}

添加联系人信息

void DelContact(pcontact p)
{
	assert(p);
	system("cls");
	int pos, i;
	char name[NAME_MAX_SIZE];
	if (!p->size)
	{
		printf("通讯录为空\n");
		return;
	}

	printf("请输入要删除的人的姓名:\n");
	scanf("%s", name);
	pos = GetPosition(name, p);

	if (-1 == pos)
	{
		printf("此人不存在\n");
	}
	else
	{
		for (i = pos; pos < p->size - 1; i++)
		{
			p->data[i] = p->data[i + 1];
		}
		p->size--;
		printf("删除成功!!!\n");
	}
}

按照名字获取通讯录的位置
这一个是为了给后面的查找和删除模块获取位置

int GetPosition(char* name, pcontact p)
{
	assert(p);
	int pos;
	for (pos = 0; pos < p->size; pos++)
	{
		if (0 == strcmp(name, p->data[pos].name))
		{
			return pos;
		}
	}
	return -1;
}

查找联系人信息

void SearchContact(pcontact p)
{
	assert(p);
	system("cls");
	char name[NAME_MAX_SIZE];
	int pos;
	printf("请输入要查找的人的姓名:\n");
	scanf("%s", name);
	pos = GetPosition(name, p);
	if (-1 == pos)
	{
		printf("此人不存在:\n");
	}
	else
	{
		printf("*******************************************\n");
		printf("姓名:%s \n", p->data[pos].name);
		printf("性别:%s \n", p->data[pos].gender);
		printf("年龄:%d \n", p->data[pos].age);
		printf("地址:%s \n", p->data[pos].addr);
		printf("电话:%s \n", p->data[pos].tel);
		printf("*******************************************\n");
		printf("查找成功!!!\n");
	}
}

修改联系人信息

void ModifyContact(pcontact p)
{
	assert(p);
	system("cls");
	char name[NAME_MAX_SIZE];
	int pos;
	printf("请输入要修改的人的姓名:\n");
	scanf("%s", name);
	pos = GetPosition(name, p);

	if (-1 == pos)
	{
		printf("此人不存在\n");
	}
	else
	{
		printf("请输入修改后的姓名:\n");
		scanf("%s", p->data[pos].name);
		printf("请输入修改后的电话:\n");
		scanf("%s", p->data[pos].tel);
		printf("请输入修改后的性别:\n");
		scanf("%s", p->data[pos].gender);
		printf("请输入修改后的年龄:\n");
		scanf("%d", &(p->data[pos].age));
		printf("请输入修改后的地址:\n");
		scanf("%s", p->data[pos].addr);
		printf("修改成功!!!\n");
	}
}

显示所有联系人信息

void ShowContact(pcontact p)
{
	assert(p);
	system("cls");
	int i;
	if (!p->size)
	{
		printf("通讯录为空\n");
		return;
	}

	for (i = 0; i < p->size; i++)
	{
		printf("*******************************************\n");
		printf("**********    第 %d 位联系人     **********\n", i + 1);
		printf("姓名:%s \n", p->data[i].name);
		printf("性别:%s \n", p->data[i].gender);
		printf("年龄:%d \n", p->data[i].age);
		printf("地址:%s \n", p->data[i].addr);
		printf("电话:%s \n", p->data[i].tel);
		printf("*******************************************\n");
		
	}
}

清空通讯录

void EmptyContact(pcontact p)
{
	assert(p);
	system("cls");
	if (!p->size)
	{
		printf("通讯录为空\n");
		return;
	}
	else
	{
		free(p->data);
		p->data = NULL;
		p->size = 0;
		p->capacity = 0;
		printf("通讯录清空成功!!!\n");
	}
}

为了通讯录方便我们查看,我们还需要排序,因为数据量过少以及排序不是这里的主体,所以采用最简单的冒泡排序

void SortContact(pcontact p)
{
	assert(p);
	system("cls");
	int i, j, flag = 1;
	info temp = { 0 };
	for (i = p->size; i > 0 && flag; i--)
	{
		flag = 0;
		for (j = 1; j < p->size; j++)
		{
			if (strcmp(p->data[j].name, p->data[j - 1].name) < 0)
			{
				temp = p->data[j];
				p->data[j] = p->data[j - 1];
				p->data[j - 1] = temp;
				flag = 1;
			}
		}
	}
	printf("排序成功!!!\n");
}

同时,一个通讯录不可能每次使用都要重新输入数据,并且数据在关闭的时候会清空,所以我们要将数据的内容进行保存,而保存的方式我选择用二进制的形式保存,因为二进制的存储方式比ascii的存储方式操作更加简单和安全。唯一的缺点就是不方便查看。
保存数据

void SaveContact(pcontact p)
{
	assert(p);
	system("cls");
	FILE* pf = fopen("contact.dat", "wb");
	int i;
	if (NULL == pf)
	{
		printf("文件打开失败\n");
		return;
	}
	for (i = 0; i < p->size; i++)
	{
		fwrite(&(p->data[i]), sizeof(info), 1, pf);
	}
	printf("通讯录保存成功\n");
	fclose(pf);
	pf = NULL;
}

读取数据

void LoadContact(pcontact p)
{
	assert(p);
	system("cls");
	FILE* pf = fopen("contact.dat", "rb");
	if (NULL == pf)
	{
		printf("文件打开失败\n");
		return;
	}
	while (fread(&(p->data[p->size]), sizeof(info), 1, pf))
	{
		if (CheckCapacity(p))
		{
			p->size++;
		}
	}
	printf("通讯录读取成功\n");
	fclose(pf);
	pf = NULL;
}

同时,在结束时还要进行内存的释放,防止内存溢出

void EndContact(pcontact p)
{
	free(p->data);
	p->data = NULL;
	p->size = 0;
	p->capacity = 0;
	exit(0);
}

在主函数方面,为了简化代码和去掉重复代码,我选择用函数指针数组来实现菜单

void Test()
{
	int input;
	contact book;
	void (*p[10])(pcontact p) =
	{
		EndContact,
		AddContact,
		DelContact,
		ModifyContact,
		SearchContact,
		SortContact,
		ShowContact,
		EmptyContact,
		SaveContact,
		LoadContact,
	};
	//利用函数指针数组简化不必要的代码

	InitContact(&book);
	//初始化

	do
	{
		Menu();
		printf("请输入要进行的操作:");
		scanf("%d", &input);
		if ((input <= 9 && input >= 0))
		{
			(*p[input])(&book);
		}
		else
		{
			printf("输入错误:\n");
		}
	} while (input);
}

就这样,一个简单的通讯录管理系统就完成了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
简单演示一下,剩下的部分就不再演示了

完整代码如下:
头文件部分Contact book.h

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<Windows.h>
#define NAME_MAX_SIZE 20
#define TEL_MAX_SIZE 20
#define ADDR_MAX_SIZE 30
#define GENDER_MAX_SIZE 10
#define CONTACT_SIZE 10

typedef struct info
{
	char name[NAME_MAX_SIZE];
	char tel[TEL_MAX_SIZE];
	char addr[ADDR_MAX_SIZE];
	char gender[GENDER_MAX_SIZE];
	int age;
	//先存放四个字符型再存放整形,利用内存对齐来达到空间利用最大化
}info;

typedef struct 
{
	info* data;
	int capacity;
	int size;
}contact, *pcontact;
//采用顺序表的数据类型来存放数据

void InitContact(pcontact p);
void AddContact(pcontact p);
void DelContact(pcontact p);
void SearchContact(pcontact p);
void SortContact(pcontact p);
void ShowContact(pcontact p);
void ModifyContact(pcontact p);
void EmptyContact(pcontact p);
int CheckCapacity(pcontact p);
int GetPosition(char* name, pcontact p);
void SaveContact(pcontact p);
void LoadContact(pcontact p);
void EndContact(pcontact p);

函数实现部分Contact book.c:

#include "Contact Book.h"

void InitContact(pcontact p)
{
	p->data = (info*)malloc(CONTACT_SIZE * sizeof(info));
	if (NULL == p->data)
	{
		printf("初始化失败!!!\n");
		exit(0);
	}
	p->capacity = CONTACT_SIZE;
	p->size = 0;
}

void AddContact(pcontact p)
{
	assert(p);
	system("cls");
	if (0 == CheckCapacity(p))
	{
		printf("通讯录已满,添加失败\n");
		return;
	}
	printf("请输入姓名:\n");
	scanf("%s", p->data[p->size].name);
	printf("请输入电话:\n");
	scanf("%s", p->data[p->size].tel);
	printf("请输入性别:\n");
scanf("%s", p->data[p->size].gender);
	printf("请输入地址:\n");
	scanf("%s", p->data[p->size].addr);
	printf("请输入年龄:\n");
	scanf("%d", &(p->data[p->size].age));

	printf("添加成功!!!\n");
	p->size++;
}

void DelContact(pcontact p)
{
	assert(p);
	system("cls");
	int pos, i;
	char name[NAME_MAX_SIZE];
	if (!p->size)
	{
		printf("通讯录为空\n");
		return;
	}

	printf("请输入要删除的人的姓名:\n");
	scanf("%s", name);
	pos = GetPosition(name, p);

	if (-1 == pos)
	{
		printf("此人不存在\n");
	}
	else
	{
		for (i = pos; pos < p->size - 1; i++)
		{
			p->data[i] = p->data[i + 1];
		}
		p->size--;
		printf("删除成功!!!\n");
	}
}

void ShowContact(pcontact p)
{
	assert(p);
	system("cls");
	int i;
	if (!p->size)
	{
		printf("通讯录为空\n");
		return;
	}

	for (i = 0; i < p->size; i++)
	{
		printf("*******************************************\n");
		printf("**********    第 %d 位联系人     **********\n", i + 1);
		printf("姓名:%s \n", p->data[i].name);
		printf("性别:%s \n", p->data[i].gender);
		printf("年龄:%d \n", p->data[i].age);
		printf("地址:%s \n", p->data[i].addr);
		printf("电话:%s \n", p->data[i].tel);
		printf("*******************************************\n");
		
	}
}

void ModifyContact(pcontact p)
{
	assert(p);
	system("cls");
	char name[NAME_MAX_SIZE];
	int pos;
	printf("请输入要修改的人的姓名:\n");
	scanf("%s", name);
	pos = GetPosition(name, p);

	if (-1 == pos)
	{
		printf("此人不存在\n");
	}
	else
	{
		printf("请输入修改后的姓名:\n");
		scanf("%s", p->data[pos].name);
		printf("请输入修改后的电话:\n");
		scanf("%s", p->data[pos].tel);
		printf("请输入修改后的性别:\n");
		scanf("%s", p->data[pos].gender);
		printf("请输入修改后的年龄:\n");
		scanf("%d", &(p->data[pos].age));
		printf("请输入修改后的地址:\n");
		scanf("%s", p->data[pos].addr);
		printf("修改成功!!!\n");
	}
}

void SearchContact(pcontact p)
{
	assert(p);
	system("cls");
	char name[NAME_MAX_SIZE];
	int pos;
	printf("请输入要查找的人的姓名:\n");
	scanf("%s", name);
	pos = GetPosition(name, p);
	if (-1 == pos)
	{
		printf("此人不存在:\n");
	}
	else
	{
		printf("*******************************************\n");
		printf("姓名:%s \n", p->data[pos].name);
		printf("性别:%s \n", p->data[pos].gender);
		printf("年龄:%d \n", p->data[pos].age);
		printf("地址:%s \n", p->data[pos].addr);
		printf("电话:%s \n", p->data[pos].tel);
		printf("*******************************************\n");
		printf("查找成功!!!\n");
	}
}

int GetPosition(char* name, pcontact p)
{
	assert(p);
	int pos;
	for (pos = 0; pos < p->size; pos++)
	{
		if (0 == strcmp(name, p->data[pos].name))
		{
			return pos;
		}
	}
	return -1;
}

void EmptyContact(pcontact p)
{
	assert(p);
	system("cls");
	if (!p->size)
	{
		printf("通讯录为空\n");
		return;
	}
	else
	{
		free(p->data);
		p->data = NULL;
		p->size = 0;
		p->capacity = 0;
		printf("通讯录清空成功!!!\n");
	}
}

int CheckCapacity(pcontact p)
{
	assert(p);
	if (p->size == p->capacity)
	{
		printf("通讯录已满,进行扩容\n");
		;
		info *temp = realloc(p->data, (p->capacity + CONTACT_SIZE) * sizeof(info));
		if (NULL == temp)
		{
			printf("扩容失败\n");
			return 0;
		}
		else
		{
			p->data = temp;
			p->capacity += CONTACT_SIZE;
			printf("扩容成功!!!\n");
		}
	}
	return 1;
}

void SortContact(pcontact p)
{
	assert(p);
	system("cls");
	int i, j, flag = 1;
	info temp = { 0 };
	for (i = p->size; i > 0 && flag; i--)
	{
		flag = 0;
		for (j = 1; j < p->size; j++)
		{
			if (strcmp(p->data[j].name, p->data[j - 1].name) < 0)
			{
				temp = p->data[j];
				p->data[j] = p->data[j - 1];
				p->data[j - 1] = temp;
				flag = 1;
			}
		}
	}
	printf("排序成功!!!\n");
}

void SaveContact(pcontact p)
{
	assert(p);
	system("cls");
	FILE* pf = fopen("contact.dat", "wb");
	int i;
	if (NULL == pf)
	{
		printf("文件打开失败\n");
		return;
	}
	for (i = 0; i < p->size; i++)
	{
		fwrite(&(p->data[i]), sizeof(info), 1, pf);
	}
	printf("通讯录保存成功\n");
	fclose(pf);
	pf = NULL;
}

void LoadContact(pcontact p)
{
	assert(p);
	system("cls");
	FILE* pf = fopen("contact.dat", "rb");
	if (NULL == pf)
	{
		printf("文件打开失败\n");
		return;
	}
	while (fread(&(p->data[p->size]), sizeof(info), 1, pf))
	{
		if (CheckCapacity(p))
		{
			p->size++;
		}
	}
	printf("通讯录读取成功\n");
	fclose(pf);
	pf = NULL;
}

void EndContact(pcontact p)
{
	free(p->data);
	p->data = NULL;
	p->size = 0;
	p->capacity = 0;
	exit(0);
}

测试部分:
test.c

#include "Contact Book.h"

void Menu()
{
	printf("************************************************\n");
	printf("**    0.退出程序          1.添加联系人        **\n");
	printf("**    2.删除联系人        3.修改联系人        **\n");
	printf("**    4.查找联系人        5.通讯录排序        **\n");
	printf("**    6.显示所有联系人    7.删除所有联系人    **\n");
	printf("**    8.保存通讯录        9.读取通讯录        **\n");
	printf("************************************************\n");
}

void Test()
{
	int input;
	contact book;
	void (*p[10])(pcontact p) =
	{
		EndContact,
		AddContact,
		DelContact,
		ModifyContact,
		SearchContact,
		SortContact,
		ShowContact,
		EmptyContact,
		SaveContact,
		LoadContact,
	};
	//利用函数指针数组简化不必要的代码

	InitContact(&book);
	//初始化

	do
	{
		Menu();
		printf("请输入要进行的操作:");
		scanf("%d", &input);
		if ((input <= 9 && input >= 0))
		{
			(*p[input])(&book);
		}
		else
		{
			printf("输入错误:\n");
		}
	} while (input);
}

int main()
{	
	Test();
	return 0;
}

github链接:https://github.com/HONGYU-LEE/test/tree/master/project/Contact%20Book

发布了60 篇原创文章 · 获赞 78 · 访问量 6322

猜你喜欢

转载自blog.csdn.net/qq_35423154/article/details/103340376