(C语言)单链表实现通讯录基础版,保证看完都直呼easy

246 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

(C语言)单链表实现通讯录基础版,保证看完都大呼简单!

—————————————————————————————————
首先在写通讯录之前,必须明确我们的需求
因为是基础版,我在这里暂时只实现以下一些需求(绝不是因为我暂时只写了这么些):

/*
添加联系人信息
删除指定联系人信息
查找指定联系人信息
修改指定联系人信息
显示所有联系人信息
清空所有联系人
*/

—————————————————————————————————
首先是创建我们的联系人结构体

typedef struct Contacts 
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char address[ADDRESS_MAX];
	char numbers[NUMBERS_MAX];
	struct Contacts* next;
}Contacts;

—————————————————————————————————
添加联系人
这里最大的要点,也是经常有人会犯错误的点,就是传入结构体头指针时,必须得是二级指针,因为我们是要对指针进行修改的。
而且我们需要对链表一开始是否为NULL进行分类讨论

void ConInfor(Contacts* con)
{
	printf("请输入姓名:");
	scanf("%s", con->name);
	printf("请输入年龄:");
	scanf("%d", &con->age);
	printf("请输入性别:");
	scanf("%s", con->sex);
	printf("请输入家庭地址:");
	scanf("%s", con->address);
	printf("请输入电话号码:");
	scanf("%s", con->numbers);
	con->next = NULL;
}

void AddContacts(Contacts** pphead)//一定是二级指针!!!!!
{
	Contacts* new_contacts = (Contacts*)malloc(sizeof(Contacts));
	ConInfor(new_contacts);
	if (*pphead == NULL)
	{
		*pphead = new_contacts;
	}
	else
	{
		Contacts* cur = *pphead;
		while (cur->next != NULL)
		{
			cur = cur->next;
		}
		cur->next = new_contacts;
	}
}

这里有个小细节,就是我把输入联系人单独封装成了一个函数,因为这块代码一定会在我们修改联系人那一个功能上用到。
—————————————————————————————————
删除联系人
我认为这一块是实现单链表通讯录的一个难点之一。
难点其一,还是二级指针
其二,就是如何在删除结点的同时,再连接被删除位置前后的结点。
其三,就是针对链表为NULL,只有一个结点和不止一个结点的三种情况的不同解决方法。

解决方法:1,链表为空,直接返回
2.仅有一个结点,删除(释放)结点,头结点置成NULL
3.多个结点,使用双指针,分别记录当前结点地址,和当前结点上一个的地址。

void DelContacts(Contacts** pphead)
{
	printf("请输入被删除联系人姓名:");
	char name[NAME_MAX];
	scanf("%s", name);
	int flag = 1;
	if (*pphead == NULL)//链表为空
	{
		printf("删除失败,通讯录为空!\n");
		return;
	}
	else if ((*pphead)->next==NULL)//链表有一个结点
	{
		if (strcmp(name, (*pphead)->name) == 0)
		{
			*pphead = NULL;
			printf("删除成功!\n");
			flag = 0;
		}
	}
	else//链表有多个结点
	{
		Contacts* prve =*pphead;
		Contacts* cur = *pphead;
		if (strcmp(name, cur->name) == 0)
		{
			*pphead = cur->next;
			printf("删除成功!\n");
			return;
		}
		while (cur != NULL)
		{
			if (strcmp(name,cur->name) == 0)
			{
				prve->next = cur->next;
				free(cur);
				flag = 0;
				printf("删除成功!\n");
				break;
			}
			prve = cur;
			cur = cur->next;
		}
	}
	if (flag == 1)
	{
		printf("查无此人,无法删除!\n");
	}
}

—————————————————————————————————
查找联系人
这一块就很简单了,和删除联系人的函数有很大的重叠部分,因为我们删除的时候就需要找到被删的联系人对不对?这里对一二级指针要求就不严格了,但我建议是用一级指针,防止误操作

void CheckContacts(Contacts* phead)
{
	Contacts* cur = phead;
	printf("请输入所要查找联系人姓名:");
	char name[NAME_MAX];
	scanf("%s", name);
	while (cur != NULL)
	{
		if (strcmp(name, cur->name) == 0)
		{
			printf("已找到!\n");
			printf("姓名                  年龄   性别   电话号码              住址\n");
			Print(cur);
			return;
		}
		cur = cur->next;
	}
	printf("查无此人!\n");
}

显示所有联系人信息
按照查找的方式,遍历链表时打印就欧克了。

void PrintContacts(Contacts* phead)
{
	if (phead == NULL)
	{
		printf("通讯录为空\n");
	}
	else
	{
		printf("姓名                  年龄   性别   电话号码              住址\n");
		while (phead != NULL)
		{
			Print(phead);
			phead = phead->next;
		}
	}
}

void Print(Contacts* phead)
{
	printf("%-20s  ", phead->name);//这里的-是左对齐,20是域宽
	printf("%-5d  ", phead->age);//这里的-是左对齐,5是域宽
	printf("%-5s  ", phead->sex);//这里的-是左对齐,5是域宽
	printf("%-20s  ", phead->numbers);
	printf("%-20s  \n", phead->address);
}

—————————————————————————————————
清空联系人
这一块就得注意了,可不能以为给头指针置NULL就拍拍屁股走人了,这就是典型的穿上裤子就不认人了,我们可不能做这样的程序猿。必须得挨个给每个结点释放了,防止内存泄漏。这里依然要用到双指针!!

void ClearContacts(Contacts** pphead)
{
	Contacts* prve = *pphead;
	Contacts* cur = *pphead;
	while (cur != NULL)
	{
		prve = cur;
		cur = cur->next;
		free(prve);
	}
	*pphead = NULL;//最后置NULL,才是负责的程序猿
	printf("已清空!\n");
}

以上呢,就是基础的通讯录实现啦,还有很多功能还未完善,比如排序同名同姓处理方法等,大家不妨可以关注我,我会马不停蹄的更新的进阶版的!!!
—————————————————————————————————