(c语言)通讯录管理系统

(c语言)通讯录管理系统

🌟开头的话

​ 这是一篇干货满满的c语言程序,既然来都来了,要不就往下看看吧

在这里插入图片描述

🌵1. 需求

  1. 实现对通讯录数据的 增加, 修改 , 删除, 查找
  2. 个人基本信息中实现可能有多个电话号码的要求
  3. 在查找时可以实现按姓名排序,模糊姓名查询

🌳2. 系统分析

2.1 流程

  1. 进入程序,从文件中读取信息
  2. 用户根据菜单,选择相应功能,实现增删查等
  3. 用户选择退出时,向文件写入信息

2.2 函数

  • 主函数,包含对不同功能(函数)的选择与调用

  • 初始化通讯录

  • 读取文件信息

  • 增加联系人

  • 修改联系人

  • 显示通讯录

  • 查找联系人

  • 对联系人排序

  • 删除联系人信息

  • 向文件写入信息

  • free申请的空间

2.3 其他

  • 使用二进制的文件存储方式,信息安全
  • 考虑到未知且可增加的联系人,我们将空间申请在动态内存里
  • 提供错误选择后,实现大多都有退出的选择,即可以返回上一步

🎯3. 思维导图

​ 增加思维导图,可以帮助编写代码时,有一个清晰是思路

在这里插入图片描述

🌴4. 界面

​ 以下界面是编者程序运行的显示结果,大家可以根据自己的需求来设计不同的界面。

(编者的水平,目前也只能在这黑框框下设计界面)😂

4.1(项目界图)主菜单

在这里插入图片描述

4.2 (项目界图)添加联系人

在这里插入图片描述

4.3 (项目界图)删除信息

在这里插入图片描述

4.3.1 删除电话

在这里插入图片描述

4.4.2 删除所有信息

在这里插入图片描述

4.4(项目界图) 查找联系人

在这里插入图片描述

4.4.1 搜索姓名

在这里插入图片描述

4.4.2 搜索电话

在这里插入图片描述

4.5(项目界图) 修改信息

在这里插入图片描述

4.6(项目界图) 排序

在这里插入图片描述

4.7(项目界图) 显示

在这里插入图片描述

🎖️5. 通讯录-设计

🥇5.1 模拟内存分布图

在这里插入图片描述

​ 整个通讯录中,有两个结构体与一个链表,他们间的调用联系如上图,并且都是通过malloc开辟空间,或者用 realloc来扩大空间。注意:phone所指向的第一个结点中并不存放telep信息.因为我们需要一个头地址来完成后续的增删该操作。

🥈5.2 模拟文件中信息存储分析图

在这里插入图片描述

​ 通过对内存与文件的内存分析,可以发现input(输入)文件信息和output(输出)文件信息的流程,即input时先读取contact.dat中的信息,然后读取telephon中对应的相关信息。而output时相反。

🥉5.3 代码实现分析图

在这里插入图片描述

🎉6. 代码实现

1️⃣6.1 main()

#define _CRT_SECURE_NO_WARNINGS 1

#include "header.h"

int main()
{
	//创建通讯录
	Contact Con;
	//初始化通讯录S
	InitCont(&Con);
	//写入文件数据
	FputInfo(&Con);
    
	int input = -1; //接收选择的主菜单序号

	do
	{
		//确保输入的选择为0~6
		while (1)
		{
			MenuFunction();//显示主函数
			printf("请选择菜单中对应数字:>");
			if (!scanf("%d", &input))//判断输入的内容是否为整型
			{
				//接收错误输入的内容
				getchar();
				char temp[MAX_NAME];
				gets(temp);

			}
			if (input>=0&&input<=6)//正确输入条件
			{
				break;
			}
			else {
				printf("错误输入,请重新选择\n");
			}
		}
		//调用选择的功能(函数)
		switch (input)
		{
		case Add://1
			AddInfo(&Con);//新增信息
			break;
		case Del://2
			DeleInfo(&Con);//删除信息
			break;
		case Search://3
			SreachInfo(&Con);//搜索信息
			break;
		case Modify://4
			MdfInfo(&Con);//修改信息
			break;
		case Sort://5
			SortInfo(&Con);//排序
			break;
		case Print://6
			PrintName(&Con);//显示信息
			break;
		case Exit://0
			//退出
			WriteFile(&Con);//输出信息到文件里
			ExitContact(&Con);//完成动态内存的free
			printf("exit\n");
			break;
		/*default:
			printf("选择错误,请重新输入\n");*/
		}
	} while (input);
	return 0;
}
6.1.1InitCont()
void InitCont(Contact* pf)//初始化通讯录
{
	pf->size = 0;//联系人起始个数为0
	pf->capacity = INITE_SIZE;//通讯录起始大小为3个
	//申请空间
	(pf->data) = (PerInf*)malloc((pf->capacity) * sizeof(PerInf));
	if ((pf->data) == NULL)
	{
		perror("InitCont");//输出错误信息
		return ;
	}
}

2️⃣6.2FputInfo()

void FputInfo(Contact* pf)//读出文件信息
{
	CreatFile();//判断是否需要新建文件

	FILE* fpCon = fopen("contact.dat", "rb");//只读打开contact.dat文件
	if (fpCon == NULL)
	{
		perror("FputInfo");//输出打开错误信息
		return;
	}
	FILE* fpTele = fopen("telephone.dat", "rb");//只读打开telephone.dat文件
	if (fpTele == NULL)
	{
		perror("FputInfo");//输出打开错误信息
		return;
	}

	PerInf information;//开辟一个临时存储空间

	//从contact.dat里读取信息
	while (fread(&information, sizeof(PerInf), 1, fpCon)>0)
	{
		IncreaseCap(pf);//判断是否需要扩容
		*(pf->data + (pf->size)) = information;//得到信息
		(pf->data + (pf->size))->phone = NULL;//初始化phone指针为空
		 
		//从telephone.dat里读取信息
		int i = 1;
		//读取该联系人phoneNum个电话信息
		for (i = 1; i <= (pf->data + (pf->size))->phoneNum; ++i)
		{
			Tele* node = NULL;
			Tele* temp = (pf->data+(pf->size))->phone;//保护头结点
			node = (Tele*)malloc(sizeof(Tele));//新建结点
			if (node == NULL)
			{
				perror("FputInfo");//输出错误信息
				exit(0);
			}

			if ((pf->data + (pf->size))->phone == NULL)//新建链表
			{
				//头结点
				(pf->data + (pf->size))->phone = (Tele*)malloc(sizeof(Tele));
				temp = (pf->data + (pf->size))->phone;
				temp->next = node;
			}
			else//向链表尾增加结点
			{
				while (temp->next != NULL)//找到链表尾 
				{
					temp = temp->next;
				}
				temp->next = node;//进行新增
			}
			//得到电话信息
			fread(node->telep, sizeof(sizeof(char)*MAX_TELE), 1, fpTele);
			node->next = NULL;//将链表尾置为NULL
		}
		(pf->size) += 1;//联系人个数+1
	}
	printf("\t\t文件读取成功\n");
	//关闭文件
	fclose(fpCon);
	fclose(fpTele);
}
6.2.1CreatFile()
void CreatFile()//创建文件
{
	FILE* fpCon = fopen("contact.dat","rb");//尝试只读打开文件
	if (fpCon == NULL)//若无该文件,则打开失败
	{
		fpCon = fopen("contact.dat", "wb");//新建一个空文件
	}
	FILE* fpTele = fopen("telephone.dat", "rb");//尝试只读打开文件
	if (fpTele == NULL)//若无该文件,则打开失败
	{
		fpTele = fopen("telephone.dat", "wb");//新建一个空文件
	}
	//关闭文件
	fclose(fpCon);
	fclose(fpTele);
}
6.2.1IncreaseCap()
void IncreaseCap(Contact* pf)//扩容	
{
	//判断联系人个数是否到底通讯录容量
	if ((pf->size) == (pf->capacity))
	{
		//重新申请一个比原来大5的联系人空间
		PerInf* temp = NULL;
		temp = (PerInf*)realloc((pf->data), sizeof(PerInf) * ((pf->capacity + INCREASE)));
		if (temp == NULL)//申请失败,提示错误信息
		{
			perror("IncreaseCap");
			printf("\t\t\t扩容失败\n");

		}
		else//扩容成功
		{
			(pf->capacity) += INCREASE;//通讯录容量加5
			(pf->data) = temp;//指向从新申请的空间
			printf("\t\t\t扩容成功\n");
		}
	}
}

3️⃣6.3 AddInfo()

void AddInfo(Contact* pf)//增加个人信息
{
	IncreaseCap(pf);//判断是否需要扩容
    
	printf("\n---------------添加联系人---------------\n");
	printf("请输入要添加人的信息\n(输入回车退出添加)\n");
	char one[MAX_NAME] = { 0 };
	printf("请输入姓名:>");
	getchar();
	gets(one);

	//增加的退出条件
	if (strcmp(one, "") == 0)
	{
		printf("\n---------------结束添加联系人---------------\n");	
		return;
	}
	strcpy((*(pf->data + pf->size)).name, one);//新增姓名

	printf("请输入年龄:>");
	scanf("%s", (pf->data + pf->size)->age);//新增年龄

	printf("请输入性别:>");
	scanf("%s", (pf->data + pf->size)->sex);//新增性别

	//新增电话
	(pf->data + pf->size)->phone = NULL;   //开始初始化为空指针
	(pf->data + pf->size)->phoneNum = 0; //初始化电话个数为0
	int judge = -1;//接收下方Judge的选择

	do {
		//确保输入的选择数字在MenuJudge();中:1 或 0
		while (1)
		{
			printf("你是否要添加电话?\n");
			MenuJudge();//选择菜单:1 yes,0 no
			//接收错误输入的内容
			if (!scanf("%d", &judge))//判断输入的内容是否为整型
			{
				getchar();
				char temp[MAX_NAME];
				gets(temp);

			}
			if (judge == 1 || judge == 0)//符合要求的条件
			{
				break;
			}
		}

		if (judge == 1)
		{
			//添加电话
			(pf->data + pf->size)->phone = AddTele((pf->data + pf->size)->phone);
			//电话数目+1
			(pf->data + pf->size)->phoneNum++;
			//显示目前已有的电话
			PrintTele((pf->data + pf->size)->phone);
		}
	} while (judge);
	printf("\t结束添加电话\n");

	printf("请输入地址:>");
	scanf("%s", (pf->data + pf->size)->address);//新增地址
	printf("请输入E_mail:>");
	scanf("%s", (pf->data + pf->size)->email);//新增邮箱

	pf->size += 1;//联系人个数+1

	printf("\n---------------成功添加联系人---------------\n");
}
6.3.1 AddTele()
Tele* AddTele(Tele* pt)// 添加电话
{
	Tele* temp = pt;

	Tele* node = node = (Tele*)malloc(sizeof(Tele));//新建结点
	//申请空间失败
	if (node == NULL)
	{
		perror("AddTele");//输出错误信息
		exit(0);
	}

	if (pt == NULL)//新建链表
	{
		pt = (Tele*)malloc(sizeof(Tele));//头结点
		temp = pt;
		temp->next = node;
	}
	else//向后增加结点
	{
		while (temp->next != NULL)//找到链表尾 
		{
			temp = temp->next;
		}
		temp->next = node;//进行新增
	}

	int judge = 0;//接收FormatTelep对电话格式判断的结果
	char T[MAX_TELE] = { 0 };//接收输入的电话
	do
	{
		printf("请输入该联系人的电话:>");
		scanf("%s", T);
		judge = FormatTelep(T);//判断电话是否符合要求
		if (judge == 1)//符合
		{
			break;
		}

		printf("电话号码格式错误,请重新输入\n");
	} while (1);
	
	strcpy(node->telep, T);//新增电话
	node->next = NULL;//将链表尾置为NULL

	return pt;//返回链表头
}
6.3.1.1FormatTelep()
//返回0: 不符合,1:符合
int FormatTelep(char* telep)//判断电话是否符和格式
{

	if (telep == NULL)//指针不能为空
	{
		return 0;
	}

	int len = strlen(telep);//得到电话长度
	
	if (len == 0)//长度不能为0
	{
		return 0;
	}
	//内容必须都为数字字符
	int i = 0;
	for (; i < len; ++i)
	{
		if (telep[i] < '0' || telep[i]>'9')
		{
			return 0;
		}
	}

	return 1;
}

4️⃣6.4 DeleInfo()

void DeleInfo(Contact* pf)//删除信息
{
	printf("\n---------------删除联系人---------------\n");
	//输入要删除操作的联系人姓名
	printf("请输入要删除人的姓名\n(输入回车退出删除):>");
	char temp[MAX_NAME] = { 0 };
	getchar();
	gets(temp);

	//增加的退出条件
	if (strcmp(temp, "") == 0)
	{
		printf("\n---------------结束删除联系人---------------\n");
		return;
	}

	//处理同名联系人操作
	int personNumber=0;//同名联系人个数
	int* person = Reach(pf, temp,&personNumber);//查找,返回同名联系人的序号数组

	//如果没有该姓名的联系人,退出
	if (personNumber == 0)
	{
		printf("\t\t通讯录没有该人信息\n");
		free(person);
		return;
	}

	//显示出所有姓名相同且符合条件的联系人
	for (int i = 0; i < personNumber; ++i)
	{
		printf("\n联系人序号:>%d\n",person[i]);
		PrintInfo(pf, person[i]);
		printf("\n");
	}

	//对需要操作的联系人的序号进行选择
	int i = -1;//接收联系人的序号
	if (personNumber > 1)
	{
		i = Choose(person, personNumber);//进行选择

	}
	else//只有一人的情况
	{
		i = person[0];
	}

	int input = 0;		//接收下方对MenuDele()菜单选择的输入
	int wt = -1;		//电话序号

	//确保输入的选择数字在MenuDele()中:1/2/3
	while (1)
	{
		printf("请选择对该联系人的删除操作\n");
		MenuDele();			//删除菜单

		//接收错误输入的内容
		if (!scanf("%d", &input))//判断输入的内容是否为整型
		{
			getchar();
			char temp[MAX_NAME];
			gets(temp);

		}
		//符合要求的条件
		if (input >=0&&input<=2)
		{
			break;
		}
	}

	int judge = -1;//接收下方Judge的选择
	
	switch (input)
	{
	case 1://删除该联系人所有信息

		//确保输入的选择数字在MenuJudge();中:1 或 0
		while (1)
		{
			printf("是否要删除该联系人所有信息?\n");
			MenuJudge();//选择菜单:1 yes,0 no

			//接收错误输入的内容
			if (!scanf("%d", &judge))//判断输入的内容是否为整型
			{
				getchar();
				char temp[MAX_NAME];
				gets(temp);

			}
			else if (judge == 1 || judge == 0)//符合要求的条件
			{
				break;
			}
		}
		//进行删除操作
		if (judge == 1)
		{
			//删除电话
			if ((pf->data + i)->phone != NULL)
			{
				DeleTelep((pf->data + i)->phone, 0);//0 表示所有电话
			}

			//删除PerInf的信息
			int j = 0;
			for (j = i + 1; j < (pf->size); ++j)
			{
				*(pf->data + j - 1) = *(pf->data + j);
			}
			(pf->size) -= 1;
			printf("\n---------------删除成功---------------\n");

		}
		else//选择0 取消删除
		{
			printf("\n---------------取消删除---------------\n");

		}
		break;

	case 2://删除删除该联系人某一电话

		if ((pf->data + i)->phoneNum == 0)//无电话,退出
		{
			printf("无电话号码\n");
			printf("\n---------------结束删除---------------\n");
			break;
		}

		//循环实现选择删除的电话号码(0:为全部)
		printf("选择你要删除的电话序号");
		
		while (1)//确保输入的选择数字在有效范围
		{
			//接收错误输入的内容
			if (!scanf("%d", &wt))//判断输入的内容是否为整型
			{
				getchar();
				char temp[MAX_NAME];
				gets(temp);
			}
			else if (wt>0&&wt<= (pf->data + i)->phoneNum)//符合要求的范围
			{
				break;
			}
			else//序号超出范围
			{
				printf("无该电话,请重新选择");
			}
		}
		
		//判断是否要删除
		while (1)
		{
			printf("是否要删除该电话?\n");
			MenuJudge();//确定菜单:1 yes,0 no
			if (!scanf("%d", &judge))
			{
				getchar();
				char temp[MAX_NAME];
				gets(temp);

			}
			else if (judge == 1 || judge == 0)
			{
				break;
			}
		}

		if (judge == 1)//进行电话删除操作
		{			 
			DeleTelep((pf->data + i)->phone, wt);
			printf("\n---------------删除成功---------------\n");
			((pf->data + i)->phoneNum)--;

		}
		if (judge == 0)//取消电话删除操作
		{
			printf("\n---------------取消删除---------------\n");

		}	
	case 0://退出
	default :
		printf("\n---------------结束删除---------------\n");
		break;
	}
	free(person);//对前方接收同名联系人序号数组空间的释放
}
6.4.1Reach()
int* Reach(Contact* pf, char* temp, int * size)//查找 
{
	//先开辟size个int的空间,用于存放pf中联系人的序号
	int* result = (int*)malloc(sizeof(int) * pf->size);
	if (result == NULL)//开辟失败提示信息
	{
		perror("Reach");
		return;
	}

	int num = 0;//联系人个数
	for (int i = 0; i < (pf->size); ++i)
	{
		//如果找到该姓名联系人,则记录下来他的序号
		if (strcmp(temp, (pf->data + i)->name) == 0)
		{
			result[num] = i;
			num++;
		}
	}
	
	*size = num;//将联系人个数返回
	return result;//返回存放联系人序号的数字
}
6.4.2 Choose()
int Choose(int* per, int size)//选择
{
	int res = -1;//存放输入选择联系人的序号
	while (1)
	{
		printf("请选择对哪个联系人进行操作:>");
		//如果输入的不是数字,则接收错误输入的内容
		if(!scanf("%d", &res))
		{
			getchar();
			char temp[MAX_NAME];
			gets(temp);

		}
		//判断输入的序号是否符合要求
		for (int i = 0; i < size; ++i)
		{
			if (res == per[i])
			{
				return res;
			}
		}
	}
}
6.4.3PrintInfo()
void PrintInfo(Contact* pf,int i)//打印个人信息
{

	printf("姓名:\t%s\n", (pf->data + i)->name);
	printf("年龄:\t%s\n", (pf->data + i)->age);
	PrintTele((pf->data + i)->phone);//显示该联系人所有电话
	printf("性别:\t%s\n", (pf->data + i)->sex);
	printf("邮箱:\t%s\n", (pf->data + i)->email);
	printf("地址:\t%s\n", (pf->data + i)->address);
	printf("电话数:\t%d\n", (pf->data + i)->phoneNum);
}
6.4.3.1 PrintTele()
void PrintTele(Tele* pt)//打印电话
{
	if (pt != NULL)
	{
		int i = 1;
		Tele* temp = pt->next;
		//遍历显示
		for (i = 1; temp != NULL; ++i)
		{
			printf("电话%d:\t", i);
			printf("%s\n", temp->telep);
			temp = temp->next;
		}
	}
	else
	{
		printf("无电话信息\n");
	}
}
6.4.4DeleTelep()
//i==0全部删除or删除第i个电话
void DeleTelep(Tele* pt, int i)
{

	Tele* p = pt;//用p来遍历链表
	Tele* pr = NULL;//free pr指向的空间
	
	if (i == 0)//删除所用电话信息
	{
		while (p != NULL)
		{
			pr = p;
			p = p->next;
			free(pr);
		}
		pt = NULL;
	}
	else
	{
		int j = 0;//记录现在p所指向的第几个结点
		//找到第i个结点,或者遍历到NULL
		while (p != NULL && j < i)
		{
			pr = p;
			p = p->next;
			++j;
		}
		//连接删除的上一个与下一个链表
		pr->next = p->next;
		free(p);//删除第i个链表	
	}
}

5️⃣6.5 SreachInfo()

void SreachInfo(Contact* pf)//查找个人信息
{
	int input = 0;//接收根据菜单MenuSearch()的选择
	//确保输入的选择在有效范围
	while (1)
	{
		MenuSearch();//显示查找方式的菜单
		printf("请选择菜单中对应数字:>");
		if (!scanf("%d", &input))//判断输入的内容是否为整型
		{
			//接收错误输入的内容
			getchar();
			char temp[MAX_NAME];
			gets(temp);

		}
		if (input == 1 || input == 2)//正确输入条件
		{
			break;
		}
		else {
			printf("错误输入,请重新选择\n");
		}
	}

	char temp[MAX_NAME] = { 0 };//接收输入的信息
	switch (input)
	{
	case 1://姓名查找
		printf("\n请输入你要查找人的姓名(输入0退出查找):>");
		scanf("%s", temp);

		//增加的退出条件
		if (strcmp(temp, "0") == 0)
		{
			printf("结束查找\n");
			return;
		}
		ReachName(pf, temp);//姓名查找
		break;
	case 2://电话查找
		printf("\n请输入你要查找人的电话号(输入0退出查找):>");
		scanf("%s", temp);

		//增加的退出条件
		if (strcmp(temp, "0") == 0)
		{
			printf("结束查找\n");
			return;
		}

		ReachTele(pf, temp);//电话查找
		break;
	default:
		printf("错误选择,跳出查找\n");
		break;
	}
}
6.5.1 ReachName()
void ReachName(Contact* pf, char* temp)//查找姓名
{
	int i = 0;
	int count = 0;
	for (i = 0; i < (pf->size); ++i)
	{
		//利用strstr进行模糊姓名查询
		/*
		* strstr(char* str1, char* str2)  
		*  比较str2是不是str1的子字符串
		*/
		if (strstr((pf->data + i)->name,temp ) != NULL)
		{
			printf("\n联系人序号:>%d\n", i + 1);
			PrintInfo(pf, i);//显示联系人信息
			printf("\n");
			count++;
		}
	}
	//没有该姓名联系人
	if(count == 0)
	printf("通讯录没有该人信息\n");
}
6.5.2 ReachTele()
void ReachTele(Contact* pf, char* temp)//查找电话
{
	int i = 0;
	int count = 0;
	for (i = 0; i < (pf->size); ++i)
	{
		//判断序号为i的联系人有无该电话
		if(JudgeTelep((pf->data + i)->phone,temp))
		{
			printf("\n联系人序号:>%d\n", i + 1);
			PrintInfo(pf, i);//显示联系人信息
			printf("\n");
			count++;
		}
	}
	//没有该姓名联系人
	if(count == 0)
	printf("通讯录没有该人信息\n");
}
6.5.2.1 JudgeTelep()
//判断是否有电话号码 返回0:no 1:yes
int JudgeTelep(Tele* pt, char *target) 
{
	int res = 0;
	Tele* temp = pt;

	//遍历链表
	while(temp!=NULL)
	{
		//利用strstr进行模糊电话查询
		if ((strstr(temp->telep, target) != NULL))
		{
			res = 1;
			break;
		}
		else
		{
			temp = temp->next;//移向下一个链表结点
		}
	}

	return res;
}

6️⃣6.6 MdfInfo()

void MdfInfo(Contact* pf)//修改信息
{
	//接收要修改的联系人的姓名
	printf("请输入要修改人的姓名\n(输入回车退出修改)\n");
	char temp[MAX_NAME] = { 0 };
	getchar();
	gets(temp);

	//增加的退出条件
	if (strcmp(temp, "") == 0)
	{
		printf("\n---------------结束修改---------------\n");
		return;
	}

	//处理同名联系人操作
	int personNumber = 0;//同名联系人个数
	int* person = Reach(pf, temp, &personNumber);//查找,返回同名联系人的序号数组
	
	//如果没有该姓名的联系人,退出
	if (personNumber == 0)
	{
		printf("\t\t通讯录没有该人信息\n");
		free(person);
		return;
	}

	//打印出所有姓名相同且符合条件的联系人
	for (int i = 0; i < personNumber; ++i)
	{
		printf(" 联系人序号:>%d\n", person[i]);
		PrintInfo(pf, person[i]);
		printf("\n");
	}

	//对需要操作的那个联系人进行选择
	int i = -1;//接收联系人的序号
	if (personNumber > 1)
	{
		i = Choose(person, personNumber);//进行选择

	}
	else//只有一人的情况
	{
		i = person[0];
	}

	int chose = 0;//接收下方对MenuModify();菜单选择的输入
	do
	{
		//确保输入的选择数字有效范围
		while (1)
		{
			MenuModify();//修改菜单
			printf("请选择要修改的部分\n");

			//接收错误输入的内容
			if (!scanf("%d", &chose))//判断输入的内容是否为整型
			{
				getchar();
				char clear[MAX_NAME];
				gets(clear);

			}

			if (chose>=0&&chose<=6)//符合要求的条件
			{
				break;
			}

			printf("选择错误\n");//不符合要求输入的提示
		}

		switch (chose)
		{
		case 1://修改姓名
			ModifyName((*(pf->data + i)).name);
			break;
		case 2:
			ModifyTelep(pf, i);
			break;
		case 3://修改性别
			ModifySex((pf->data + i)->sex);
			break;
		case 4://修改邮箱
			ModifyEmail((pf->data + i)->email);
			break;
		case 5://修改地址
			ModifyAddress((pf->data + i)->address);
			break;
		case 6://修改年龄
			ModifyAge((pf->data + i)->age);
			break;
		case 0://退出 
			printf("结束修改\n");
			printf("\n---------------结束修改---------------\n");
			return;
		default:
			printf("选择错误,请重新输入\n");
		}
	}while (chose);
	free(person);//对前方接收同名联系人序号数组空间的释放
}
6.6.1 ModifyName()
void ModifyName(char* pm)//修改姓名
{
	//输入修改后的姓名
	printf("(输入回车跳出修改)\n\(%s\)请输入修改后的姓名:>",pm);
	char temp[MAX_NAME] = { 0 };
	getchar();
	gets(temp);

	//增加的退出条件
	if (strcmp(temp, "") == 0)
	{
		printf("\n---------------结束修改---------------\n");
		return;
	}

	strcpy(pm, temp);//进行修改
	printf("\t修改成功\n");
}
6.6.2 ModifySex()
void ModifySex(char* pm)//修改性别
{
	//输入修改后的性别
	printf("(输入回车跳出修改)\n\(%s\)请输入修改后的性别:>",pm);
	char temp[MAX_SEX] = { 0 };
	getchar();
	gets(temp);
	//增加的退出条件
	if (strcmp(temp, "") == 0)
	{
		printf("\n---------------结束修改---------------\n");
		return;
	}
	strcpy(pm, temp);//进行修改
	printf("\t修改成功\n");
}
6.6.3ModifyEmail()
void ModifyEmail(char* pm)//修改email
{
	//输入修改后的邮箱
	printf("(输入回车跳出修改)\n\(%s\)请输入修改后的E-mail:>",pm);
	char temp[MAX_Email] = { 0 };
	getchar();
	gets(temp);
	//增加的退出条件
	if (strcmp(temp, "") == 0)
	{
		printf("\n---------------结束修改---------------\n");
		return;
	}
	strcpy(pm, temp);//进行修改
	printf("\t修改成功\n");
}
6.6.3ModifyAddress()
void ModifyAddress(char* pm)// 修改地址
{
	//输入修改后的地址
	printf("(输入回车跳出修改)\n\(%s\)请输入修改后的地址:>",pm);
	char temp[MAX_ADDR] = { 0 };
	getchar();
	gets(temp);
	//增加的退出条件
	if (strcmp(temp, "") == 0)
	{
		printf("\n---------------结束修改---------------\n");
		return;
	}
	strcpy(pm, temp);//进行修改
	printf("\t修改成功\n");
}
6.6.4ModifyAge()
void ModifyAge(char* pm)
{
	//输入修改后的地址
	printf("(输入回车跳出修改)\n\(%s\)请输入修改后的年龄:>",pm);
	char temp[MAX_AGE] = { 0 };
	getchar();
	gets(temp);
	//增加的退出条件
	if (strcmp(temp, "") == 0)
	{
		printf("\n---------------结束修改---------------\n");
		return;
	}
	strcpy(pm, temp);//进行修改
	printf("\t修改成功\n");
}
6.6.5ModifyTelep()
void ModifyTelep(Contact* pf, int i)//修改电话
{
	//如果该联系人无电话,退出
	if ((pf->data+i)->phoneNum == 0)
	{
		printf("无电话号码\n");
		printf("\n---------------结束修改---------------\n");
		return;
	}

	PrintTele((pf->data + i)->phone);//显示该联系人全部电话

	int wt = -1;//接收选择的电话序号
	printf("选择你要修改的电话序号");
	//确保输入的电话序号是有效的
	while (1)
	{
		//接收错误输入的内容
		if (!scanf("%d", &wt))
		{
			getchar();
			char temp[MAX_NAME];
			gets(temp);
		}
		//符合要求的条件
		else if (wt >= 0 && wt <= (pf->data + i)->phoneNum)
		{
			break;
		}
		else
		{
			printf("无该电话序号,请重新选择");
		}
	}

	// 删除wt序号的电话
	Tele* mod = (pf->data + i)->phone->next;//令mod指向有效结点
	int j = 1;//记录目前电话序号
	//变量当找到该序号结点或者到链表尾声退出
	while (mod != NULL && j < wt)
	{
		mod = mod->next;//指向下一个链表
		++j;
	}

	printf("(输入回车跳出修改)\n\(%s\)请输入修改后的电话:>",mod->telep);
	char temp[MAX_TELE] = { 0 };
	getchar();
	gets(temp);
	//增加的退出条件
	if (strcmp(temp, "") == 0)
	{
		printf("\n---------------结束修改---------------\n");
		return;
	}
	strcpy(mod->telep, temp);//进行修改
	printf("\t修改成功\n");
}

7️⃣6.7 SortInfo()

void SortInfo(Contact* pf)		//排序	
{
	//利用库函数qsort实现排序
	/*
	* void qsort (void* base, size_t num, size_t size,
            int (*compar)(const void*,const void*));
	* 对数组的 num 个元素进行排序,每个元素的大小为 size 字节长,使用比较函数确定顺序。
	* 此函数使用的排序算法通过将指定的 compar 函数与指向它们的指针作为参数来比较元素对。
	* 该函数不返回任何值,但修改数组所指向的内容,方法是根据 compar 定义对其元素进行基本重	 新排序。
	*/
	qsort((pf->data), (pf->size), sizeof(PerInf), cmp_PerInf);

	printf("排序成功\n");
	PrintName(pf);//输出排序后的通讯录中每个联系人的姓名
}
6.7.1 cmp_PerInf()
/*函数返回值
* <0	e1 所指向的元素位于 e2 所指向的元素之前
* 0		e1 所指向的元素等效于 e2 所指向的元素
* >0	e1 所指向的元素位于 e2 所指向的元素之后
*/
int cmp_PerInf(const void* e1, const void* e2)//比较两个信息
{
    //返回比较的姓名
	return (strcmp(((PerInf*)e1)->name, ((PerInf*)e2)->name));
}

8️⃣6.8 PrintName()

void PrintName(Contact* pf)//打印姓名
{
	int i = 0;

	//对输出格式的控制
	printf("%-5s %-10s\n", "序号", "姓名");
	for (i = 0; i < (pf->size); ++i)
	{
		printf("%-5d %-10s\n", i, (pf->data + i)->name);
	}
}

9️⃣6.9 WriteFile()

void WriteFile(Contact* pf)//写入文件
{
	FILE* fpCon = fopen("contact.dat", "wb");//打开文件,并将里面内容置空
	if (fpCon == NULL)//打开失败
	{
		perror("WriteFile");//显示错误信息
		return;
	}
	FILE* fpTele = fopen("telephone.dat", "wb");//打开文件,并将里面内容置空
	if (fpTele == NULL)//打开失败
	{
		perror("WriteFile");//显示错误信息
		return;
	}

	//输出信息到文件中
	int i = 0;
	for (i = 0; i < (pf->size); ++i)
	{
		//如果该联系人有电话,则将电话输出到telephone.dat中
		if ((pf->data + i)->phone != NULL)
		{
			Tele* temp = (pf->data + i)->phone->next;
			while (temp != NULL)
			{
				//输出(写入)电话
				fwrite(temp->telep, sizeof(sizeof(char) * MAX_TELE), 1, fpTele);
				temp = temp->next;
			}
		}
		//将联系人信息输出到contact.dat中
		fwrite((pf->data + i), sizeof(PerInf), 1, fpCon);

	}
	//关闭文件
	fclose(fpCon);
	fclose(fpTele);
}

🔟6.10 ExitContact()

void ExitContact(Contact* pf)//退出
{
	int i = 0;
	//free每个联系人的电话
	for (i = 0; i < (pf->size); ++i)
	{
		if ((pf->data + i)->phone != NULL)
		{
			DeleTelep((pf->data + i)->phone, 0);
		}
		(pf->data + i)->phone = NULL;
	}
	//free整个通讯录
	free(pf->data);
	pf->data = NULL;
}

🖐️7. 结束语

这个项目是我大一下学期的一个项目课题,经过了多次改良后所最终呈现的代码。整篇博客确实也写了好久好久,包含我对整个项目的分析与实现,或许无法达到那些大佬们循序渐进的讲述,但我也算是呕心沥血了。

如果你发现有什么不足或错误可以与私信我。

如果你感觉这篇博客对你有些许帮助的话,请点上小小一个赞👍,就是对我莫大的鼓励了。

继续努力 !!!🦀🦀大家

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言课程设计任务书(4) 一、题目:通讯录管理 二、目的与要求 1. 目的: (1)基本掌握面向过程程序设计的基本思路和方法; (2)达到熟练掌握C语言的基本知识和技能; (3)能够利用所学的基本知识和技能,解决简单的程序设计问题 2. 要求 基本要求: 1.         要求利用C语言面向过程的编程思想来完成系统的设计; 2.       突出C语言的函数特征,以多个函数实现每一个子功能; 3.         画出功能模块图; 4.         具有清晰的程序流程图和数据结构的详细定义; 5.       熟练掌握C语言对文件的各种操作。 创新要求: 在基本要求达到后,可进行创新设计,如系统用户功能控制,对管理员级和一般级别的用户系统功能操作不同 三、信息描述 有关该系统基本信息的描述,如:姓名、电话、城市和邮编等。 四、功能描述 1.       名单基本信息(姓名,城市,电话,邮编等)的录入,并存放在文件当中。 2.       基本信息的查询与修改。 3.       记录的添加和删除。 4.       对同一类型记录的查找:如查找同一城市的记录或同一省份的记录。 五、解决方案 1.       分析程序的功能要求,划分程序功能模块。 2.       画出系统流程图。 3.       代码的编写。定义数据结构和各个功能子函数。 4.       程序的功能调试。 5.       完成系统总结报告以及使用说明书 六、进度安排 此次课程设计时间为一周或两周,分四个阶段完成: 1.       分析设计阶段。指导教师应积极引导学生自主学习和钻研问题,明确设计要求,找出实现方法,按照需求分析、总体设计、详细设计这几个步骤进行。 2.       编码调试阶段:根据设计分析方案编写C代码,然后调试该代码,实现课题要求的功能。 3.       总结报告阶段:总结设计工作,写出课程设计说明书,要求学生写出需求分析、总体设计、详细设计、编码、测试的步骤和内容。 4.       考核阶段。 七、撰写课程设计报告或课程设计总结 课程设计报告要求: 总结报告包括需求分析、总体设计、详细设计、编码(详细写出编程步骤)、测试的步骤和内容、课程设计总结、参考资料等,不符合以上要求者,则本次设计以不及格记。 八、参考资料  《C语言程序设计教程》   网上相关资料(....略)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值