【C语言项目实战】使用单链表实现通讯录

csdn推荐

目录

一、引言

在数字化时代,通讯录作为我们日常生活中不可或缺的一部分,扮演着记录和管理联系人信息的重要角色。随着智能手机的普及,人们对于通讯录的功能和性能要求也在不断提高。为了更好地满足这些需求,我们有必要对通讯录的实现方式进行深入研究和探索。

在众多的数据结构中,单链表以其独特的优势成为了实现通讯录的一种理想选择。单链表是一种线性数据结构,它通过每个节点中的指针链接在一起,形成一个有序的链表。相比于数组等其他数据结构,单链表在插入、删除操作上具有更高的效率,因为它不需要像数组那样移动大量的元素。此外,单链表在内存使用上也更加灵活,可以根据需要动态地分配和释放内存空间。

因此,本文旨在探讨如何使用单链表来实现一个高效、灵活的通讯录项目。我们将首先介绍单链表的基本概念和基本操作,然后分析通讯录项目的需求,并设计相应的数据结构和接口。接下来,我们将详细实现通讯录类的各个功能,并进行测试和验证。最后,我们将对项目进行总结和反思,并提出改进方向。

通过本文的介绍和实践,读者将能够深入理解单链表在通讯录项目中的应用,掌握使用单链表实现通讯录的基本方法和技巧。同时,本文也为读者提供了一个实际的项目案例,有助于提升读者的编程能力和解决问题的能力。

二、单链表的基本概念

通讯录项目的实现直接借用了单链表实现的头文件SLinkList.h和源文件SLinkList.c

关于单链表的问题请参照前置文章

【数据结构/C语言】单链表的实现-CSDN博客

对单链表有了深入的理解之后才能更好的实现通讯录项目

三、通讯录项目的需求分析 能够存储较多的联系人信息,并且能够高效地管理内存,避免不必要的内存浪费能够保存用户信息:名字、性别、年龄、电话、地址等增加联系⼈信息删除指定联系⼈查找指定联系⼈修改指定联系⼈显示联系⼈信息实现数据的导入导出

四、通讯录的数据结构

以下是用结构体记录通讯录单个联系人信息的信息,对应单链表单个节点的数据部分的数据类型

#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100
typedef struct PersonInfo
{
    char name[NAME_MAX];//姓名
    char sex[SEX_MAX];  //性别
    int age;            //年龄
    char tel[TEL_MAX];  //电话
    char addr[ADDR_MAX];//地址
}PeoInfo;

同时,单链表头文件中对单链表结构的数据部分定义有所修改

typedef PeoInfo SLTDataType;//类型重定义
typedef struct SListNode
{
	SLTDataType data;//数据
	struct SListNode* next;//指针
}SLTNode;

注意:

因为单链表的头文件需要用到通讯录的头文件的联系人结构体定义,所以在单链表头文件中包含了通讯录头文件。

但通讯录头文件中又需要用到单链表中对节点的定义,头文件不能互相包含,所以应当在通讯录头文件中包含一条对单链表的结构体的前置声明

typedef struct SListNode contact;//声明并重命名

接下来,就可以来实现通讯录项目的方法了

五、通讯录的接口

通讯录的基本方法接口包括

需要对单链表数据进行修改的函数,应该传址调用,实参传递地址,形参使用二级指针接收

//初始化通讯录
void InitContact(contact** con);
//添加通讯录数据
void AddContact(contact** con);
//删除通讯录数据
void DelContact(contact** con);
//展示通讯录数据
void ShowContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact** con);
//销毁通讯录数据
void DestroyContact(contact** con);

1.通讯录初始化 / 导入外部数据

单链表实现的通讯录因为不带有额外的头节点,并且链表每个节点都是独立的,所以初始化不需要额外的操作,只需要从外部文件导入通讯录数据即可

这里将导入数据单独封装成一个函数,以便代码复用

由初始化函数来调用导入数据函数

导入外部数据的函数功能:

void LoadContact(contact** con)//导入数据到通讯录
{
	FILE* pf = fopen("contact.txt", "rb");//以二进制读方式打开文件
	if (pf == NULL)//判空
	{
		perror("fopen");
		return;
	}
	PeoInfo po;
	while (fread(&po, sizeof(po), 1, pf))//循环读取数据
	{
		SLTPushBack(con, po);//尾插到单链表
	}
	printf("数据载入成功!n");
	fclose(pf);
	pf = NULL;
}

/初始化通讯录
void InitContact(contact** con)
{
	LoadContact(con);//导入外部数据
}

2.添加联系人信息

添加联系人信息的函数功能:

//添加通讯录数据
void AddContact(contact** con)
{
	assert(con);//二级指针判空
	PeoInfo po;
	printf("请按提示输入要添加的联系人信息n");
	printf("请输入姓名:n");
	scanf("%s", po.name);
	printf("请输入性别:n");
	scanf("%s", po.sex);
	printf("请输入年龄:n");
	scanf("%d", &po.age);
	printf("请输入电话:n");
	scanf("%s", po.tel);
	printf("请输入地址:n");
	scanf("%s", po.addr);
	SLTPushBack(con, po);//调用单链表函数尾插
	printf("添加联系人成功n");
}

3.删除联系人信息

删除联系人记录需要封装一个查找联系人函数(单独实现查找,无其他功能)

单独的查找函数的函数功能:

//封装的单独查找函数
contact* FindByname(contact*con,char name[])
{
	assert(con);//二级指针判空
	contact* pcur = con;//遍历链表的指针
	while (pcur)
	{
		if (strcmp(pcur->data.name, name) == 0)//字符串比对
			return pcur;
		pcur = pcur->next;
	}
	return NULL;
}

删除联系人记录的函数功能:

//删除通讯录数据
void DelContact(contact** con)
{
	assert(con&&*con);//二级指针判空,链表判空
	printf("请输入要删除的联系人姓名:");
	char name[NAME_MAX];
	scanf("%s", name);
	contact* del = FindByname(*con, name);//调用单独的查找函数
	if (del == NULL)
	{
		printf("要删除的联系人不存在!n");
		return;
	}
	SLTErase(con, del);//调用单链表删除指定元素
	printf("删除联系人成功!n");
}

4.查找联系人信息

查找联系人信息的函数功能:

//查找通讯录数据
void FindContact(contact* con)
{
	
	printf("请输入要查找的联系人姓名:");
	char name[NAME_MAX];
	scanf("%s", name);
	contact* pcur = FindByname(con, name);//调用已经实现的查找函数
	if (pcur == NULL)
	{
		printf("要查找的联系人不存在!n");
		return;
	}
	printf("%-10s%-10s%-10s%-10s%-10sn",
		"姓名", "性别", "年龄", "电话", "地址"
	);//打印该联系人信息
	printf("%-10s%-10s%-10d%-10s%-10sn",
		pcur->data.name,
		pcur->data.sex,
		pcur->data.age,
		pcur->data.tel,
		pcur->data.addr
	);
}

5.修改联系人信息

修改联系人信息的函数功能:

//修改通讯录数据
void ModifyContact(contact** con)
{
	assert(con);
	printf("请输入要修改的联系人姓名:");
	char name[NAME_MAX];
	scanf("%s", name);
	contact* pcur = FindByname(*con, name);//调用已经实现的查找函数
	if (pcur == NULL)
	{
		printf("要修改的联系人不存在!n");
		return;
	}
	printf("请输入修改后的联系人姓名: ");
	scanf("%s", pcur->data.name);
	printf("请输入修改后的联系人性别: ");
	scanf("%s", pcur->data.sex);
	printf("请输入修改后的联系人年龄: ");
	scanf("%d", &pcur->data.age);
	printf("请输入修改后的联系人电话: ");
	scanf("%s", pcur->data.tel);
	printf("请输入修改后的联系人地址: ");
	scanf("%s", pcur->data.addr);
	printf("修改联系人信息成功!n");
}

6.展示联系人信息

展示联系人信息的函数功能:

//展示通讯录数据
void ShowContact(contact* con)
{
	if (con == NULL)//对空链表的特殊处理
	{
		printf("NULLn");
		return;
	}
	printf("%-10s%-10s%-10s%-10s%-10sn",
		"姓名", "性别", "年龄", "电话", "地址"
	);//表头
	contact* pcur = con;
	while (pcur)//遍历链表,打印每个节点的联系人信息
	{
		printf("%-10s%-10s%-10d%-10s%-10sn",
			pcur->data.name,
			pcur->data.sex,
			pcur->data.age,
			pcur->data.tel,
			pcur->data.addr
		);
		pcur = pcur->next;
	}
}

7.导出数据到文件

数据导出的函数功能:

//导出数据
void SaveData(contact* con)
{
	FILE* pf = fopen("contact.txt", "wb");//以二进制写方式打开文件
	if (pf == NULL)
	{
		perror("fopenn");
		exit(1);
	}
	contact* pcur = con;
	while (pcur)//遍历链表,将通讯录数据输出到文件中
	{
		fwrite(pcur, sizeof(contact), 1, pf);
		pcur = pcur->next;
	}
	fclose(pf);
	free(pf);
	pf = NULL;
}

8.通讯录销毁

通讯录销毁的函数功能:

//销毁通讯录数据
void DestroyContact(contact** con)
{
	SaveData(*con);//调用函数导出数据到文件
	SListDesTroy(con);//调用单链表函数销毁通讯录
}

六、主函数中通讯录操作 1.通讯录菜单

菜单函数的功能:

void menu()
{
	printf("n######################################n");
	printf("###########--——通讯录菜单——--#########n");
	printf("#####1.添加联系人   2.删除联系人######n");
	printf("#####3.修改联系人   4.查找联系人######n");
	printf("#########  5.展示全部联系人 ##########n");
	printf("#########  0.退出通讯录程序 ##########n");
	printf("######################################nn");
}

2.通讯录人机交互操作

通讯录人机交互部分功能:

contact* con = NULL;
InitContact(&con);//初始化
int op = 0;//选项
do {
	menu();
	printf("请选择您的操作:  ");
	scanf("%d", &op);
	switch (op)
	{
	case 1:
		AddContact(&con);//添加
		break;
	case 2:
		DelContact(&con);//删除
		break;
	case 3:
		ModifyContact(&con);//修改
		break;
	case 4:
		FindContact(con);//查找
		break;
	case 5:
		ShowContact(con);//展示
		break;
	case 0:
		printf("退出通讯录!n");
		break;
	default:
		printf("您选择的数字有误,请重新输入;n");
		break;
	}
} while (op);
DestroyContact(&con);//销毁

七、各文件的实现代码

单链表中已有文件——

SLinkList.h

文章来源:https://blog.csdn.net/2302_78391795/article/details/138818650



微信扫描下方的二维码阅读本文

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容