0
点赞
收藏
分享

微信扫一扫

通过C语言使用动态内存实现通讯录

卿卿如梦 2022-03-21 阅读 73
c语言

我们的手机都有通讯录的菜单,那么这是如何实现的呢?

文章目录

实现通讯录的总体思路

首先,要实现通讯录,就要考虑文件的封装的问题,我分成了3个文件,test.c文件是用来实现通讯录的整体框架的,contact.h作为头文件,用来定义局部变量和函数声明,而contact.c就是具体实现通讯录的功能的文件。
在明确了文件的问题以后,我们可以先将通讯录的整体框架搭建起来,将变量的定义和函数的声明写好后,就要进行通讯录最重要的功能开发的环节。

整体框架的搭建

首先我们使用 do while语句来打印出通讯录的菜单

void menu()
{
	printf("*************************************\n");
	printf("*********1.add      2.del************\n");
	printf("*********3.serach   4.modify*********\n");
	printf("*********5.sort     6.print**********\n");
	printf("*********0.exit             *********\n");
	printf("*************************************\n");

}

接着使用switch语句来实现功能的选择
那么具体应该有哪些功能呢?

由于通讯录的功能较多,使用case+数字不利于我们将函数与case 语句对号入座,所以我们通过定义枚举来使进行区分

enum Option  //定义枚举常量通常是大写(因为是枚举常量)
{
	EXIT,//0
	ADD,//1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SORT,//5
	PRINT,//6
};

标题局部变量的定义以及函数的声明

进行这一步,必须要思考清楚我们到底要记录联系人的哪些信息?

由于信息较多,可以定义一个结构体,又为了后期修改数据,所以可以使用宏定义来指定大小,由于之后的
功能函数会经常用到这个结构体,所以还可以使用typedef来将这个结构体的名称改的简单一些

#define MAX_NAME 30//,宏定义,写成这样方便修改
#define MAX_SEX 10
#define MAX_TELE 12 
#define MAX_ADDR 30
#define MAX 1000
typedef struct PeoInfo//定义结构体类型(联系人的信息)
{
	char name[MAX_NAME];//使用typedef来将struct PeoInfo改写为 PeoInfo
	char sex[MAX_SEX];
	int age;
	char tele[MAX_TELE];
	char addr[MAX_ADDR];
}PeoInfo;

我们还需要一个具体的通讯录结构体来实现数据的存放,考虑到通讯录是动态开辟内存的,所以此处我们规定

也使用typedef来简化结构体名称

在这里插入代码片typedef struct Contact
{
	PeoInfo* data;//指向动态内存申请的空间,用来存放联系人的信息
	int sz;//记录的是联系人的有效信息的个数
	int capacity;//记录通讯录的最大容量
} Contact;

初始化通讯录

首先动态开辟可以存放3个联系人大小的空间,再考虑malloc会不会指向一个空指针,所以使用if语句进行判断,如果是空指针就打印错误的位置,并return结束

void InitContact(Contact* pc)//这里的pc就是&con
{
	pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact");
		return;
	}
	pc->capacity = DEFAULT_SZ;//默认值3
	pc->sz = 0;
}

实现增加函数

要实现动态开辟,首先要判断当通讯录中联系人的信息到达3时,就要使用realloc进行动态内存开辟,为了防止出现空指针的情况,需要进行判断
接下来只需要进行依次录入联系人信息即可

void AddContact(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));
		if (ptr != NULL)
		{
			pc->data = ptr;
			pc->capacity += INC_SZ;
			printf("增容成功\n");
			return;
		}
		else
		{
			perror("AddContact");//打印错误地点
			printf("增加联系人失败\n");
			return;
		}
	}
	
		printf("请输入名字:");
		scanf("%s", pc->data[pc->sz].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pc->sz].age));//只有这个加了&,因为其他的都是数组,可以不用取地址
		printf("请输入性别:");
		scanf("%s", pc->data[pc->sz].sex);
		printf("请输入电话:");
		scanf("%s", pc->data[pc->sz].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pc->sz].addr);
		pc->sz++;
		printf("添加成功\n");
	
}

由于后面要用到打印函数
所以在这里先写打印函数

实现打印函数

```void PrintContact(const Contact* pc)
{
	//打印标题
	printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
	//打印信息            //加符号表示左对齐
	int i = 0;
	for (size_t i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name,
										pc->data[i].age, //age是int类型的,要用%d
										pc->data[i].sex, 
										pc->data[i].tele, 
										pc->data[i].addr);
	}

}



实现查找姓名函数

查找姓名函数有利于后面功能的简化

static int FindName(Contact* pc, char name[])//加上static使其他文件用不了这个函数,起保护作用
{
	int i = 0;
	for (size_t i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->data[i].name, name) == 0)
			return i;//返回找到的联系人的下标
	}
	return -1;//找不到
}
## 实现删除函数
删除要分为两步:
1.查找有没有这个联系人
2.删除

```c
void DelConntact(Contact *pc)
{
	char name[MAX_NAME]={0};
	if (pc->sz == 0)
	{
		printf("通讯录为空,无需删除\n");
		return;
	}
	//1.查找要删除的联系人(有/没有)
		printf("请输入要删除的人的名字\n");
		scanf("%s", &name);
		int pos = FindName(pc,name);
		if (pos == -1)
		{
			printf("查找不到该联系人\n");
			return;
		}
		//2.有->删除
		int i = 0;
		for (size_t i = pos; i < pc->sz-1; i++)//-1防止越界
		{
			pc->data[i] = pc->data[i + 1];//覆盖掉要删除的信息
		}
		pc->sz--;//联系人的数目减少1
		printf("删除成功\n");
}

实现查找函数

void SearchContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	printf("请输入要查找的人的名字\n");
	scanf("%s", &name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("查找不到该联系人\n");
		return;
	}
	else//拷贝一下之前写的打印函数
	{
		//打印标题
		printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
		//打印信息            //加符号表示左对齐
	
			printf("%-20s\t%-5d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name,
				pc->data[pos].age, //age是int类型的,要用%d
				pc->data[pos].sex,
				pc->data[pos].tele,
				pc->data[pos].addr);
	}
}

实现修改函数

void ModifyContact(Contact* pc)
{
	char name[MAX_NAME] = { 0 };
	printf("请输入要修改的人的名字\n");
	scanf("%s", &name);
	int pos = FindName(pc, name);
	if (pos == -1)
	{
		printf("查找不到该联系人\n");
		return;
	}
	else
	{
		printf("请输入名字:");
		scanf("%s", pc->data[pos].name);
		printf("请输入年龄:");
		scanf("%d", &(pc->data[pos].age));//只有这个加了&,因为其他的都是数组,可以不用取地址
		printf("请输入性别:");
		scanf("%s", pc->data[pos].sex);
		printf("请输入电话:");
		scanf("%s", pc->data[pos].tele);
		printf("请输入地址:");
		scanf("%s", pc->data[pos].addr);
		pc->sz++;
		printf("修改成功\n");
	}
}

实现排序函数

要实现排序,可以使用qsort函数,此处提供两种类型排序

//按姓名(由小到大)来排序
//int cmp(void*e1,void*e2)
//{
//	return strcmp((char*)e1 , (char*)e2);
//}
//按年龄(由小到大)来排序
int cmp(void* e1, void* e2)
{
	return ((PeoInfo*)e1)->age- ((PeoInfo*)e2)->age;
}
void SortContact(Contact* pc)
{
	qsort(pc->data, pc->sz, sizeof(struct PeoInfo), cmp);
}

使用free置空

当然,因为是创建了动态内存,所以最后要置空,销毁通讯录
本来数据就是存储在内存中的,又连接不上数据库,所以数据一定是会丢失的
所以最后还是要将空间还给操作系统,使用free

//销毁通讯录--置空
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->sz = 0;
	pc->capacity=0;
}

这样子就完成了整个通讯录的实现,这里面确实有很多值得推敲的地方,也会有点遗憾,没能把数据保存下来,但是我相信随着自己知识的丰富,以后一定会写出更加漂亮的代码。如有不足之处,请大家指正,共同进步。

举报

相关推荐

0 条评论