(c语言)通讯录管理系统
🌟开头的话
这是一篇干货满满的c语言程序,既然来都来了,要不就往下看看吧
目录
🌵1. 需求
- 实现对通讯录数据的 增加, 修改 , 删除, 查找
- 个人基本信息中实现可能有多个电话号码的要求
- 在查找时可以实现按姓名排序,模糊姓名查询
🌳2. 系统分析
2.1 流程
- 进入程序,从文件中读取信息
- 用户根据菜单,选择相应功能,实现增删查等
- 用户选择退出时,向文件写入信息
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. 结束语
这个项目是我大一下学期的一个项目课题,经过了多次改良后所最终呈现的代码。整篇博客确实也写了好久好久,包含我对整个项目的分析与实现,或许无法达到那些大佬们循序渐进的讲述,但我也算是呕心沥血了。
如果你发现有什么不足或错误可以与私信我。
如果你感觉这篇博客对你有些许帮助的话,请点上小小一个赞👍,就是对我莫大的鼓励了。
继续努力 !!!🦀🦀大家