目录
一、具体实现步骤
(一)创建工程
编辑
(二)设计存储数据的结构形式
(三)函数功能设计及实现
初始化函数
添加通讯录信息的函数
展示通讯录内容
删除通讯录内容
查找通讯录内容
修改通讯录内容
清空通讯录
排序通讯录 按名字 升序
(四)实现菜单 测试函数功能
二、源码附录
(一)静态版本
1.1.contact.h
1.2.contact.c
1.3.test.c
(二)动态版本
2.1.contact.h
2.2.contact.c
2.3.test.c
(三)文件存储版本
3.1.contact.h
3.2.contact.c
3.3.test.c
环境:Visual Studio2022
实现语言:C语言
一、具体实现步骤
(一)创建工程
step1.首先我们需要创建一个工程,打开编译器,点击创建新项目
step2.选择空项目,点击下一步
step3.为项目起一个合适的名字 ,我这里就叫Contact ,然后点击创建
step4.来到新的页面后 找到解决方案资源管理器 分别右键源文件、头文件 选择添加新建项,分别建好contact.h contact.c test.c 三个文件
解释:
contact.h
统一包含 工程所需要包含的头文件 将未来可能修改大小的值 定义成 标识符常量声明自定义的数据类型通讯录功能 函数的声明contact.c
实现通讯录功能的函数test.c
用来测试通讯录的功能(二)设计存储数据的结构形式
首先设计一下存储数据的结构形式,我们采用的是顺序表,简单点说,就是用数组存储每一个人的信息,再加上一个用来记录当前通讯录中包含多少个人的信息的变量 就构成了一个通讯录,我们将它自定义为一个通讯录类型的数据
//声明并类型重命名 一个通讯录的 结构体类型//该类型包含//一个 Peoinfo类型的 结构体数组 data[] 用来存放每一个人的信息//一个 sz变量 用来记录当前通讯录中包含多少个人的信息typedef struct Contact{Peoinfo data[DATA_MAX];int sz;}Contact;
然后我们发现,每个人的信息包括:姓名、性别、年龄、电话、住址 这些条目,所以我们将每个人的信息打包。
//声明 一个 可以包含一条人信息的 结构体类型//并进行类型重命名 重命名为Peoinfotypedef struct Peoinfo{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];}Peoinfo;
(三)函数功能设计及实现
添加联系人信息删除指定联系人信息查找指定联系人信息修改指定联系人信息显示所有联系人信息清空所有联系人以名字排序所有联系人设计函数的形参实现,在头文件中声明函数
//初始化通讯录void InitContact(Contact* con);//向通讯录中添加信息void AddContact(Contact* con);//展示通讯录内容void ShowContact(Contact* con);//删除通讯录内容void DelContact(Contact* con);//查找通讯录内容void SearchContact(Contact* con);//修改通讯录内容void ModifyContact(Contact* con);//清空通讯录void EmptyContact(Contact* con);//排序通讯录 按名字 升序void SortContact(Contact* con);
在Contact.c中具体实现这些函数
1.初始化函数
初始化时,传的是结构体Con的地址,用结构体指针pc来接收,里面并用aasert断言一下,以便知道是哪行出了问题,它属于一种暴力检查。再用memset函数,把通讯录里面的信息条数置为0,即把sz记录当前数量置为0。
void InitContact(Contact* pc){assert(pc);pc->sz = 0;memset(pc->data,0,sizeof(pc->data));}
2.添加通讯录信息的函数
用结构体指针变量pc接收,直接用标准输入输出函数,去录入信息,如名字,用结构体指针pc访问数组,并用pc访问成员变量sz找到数组下标,再.name找到名字。里面要注意再用scanf的时候 成员变量如果是数组,数组名就是首元素地址,不用再加&取地址运算符,而成员变量如果是整型变量要加取地址符号。最后用sz++,记录已录人数,并打印成功添加。void AddContact(Contact* pc){assert(pc);//增加联系人之前 应先判断通讯录是否满了if (pc->sz == DATA_MAX){printf("通讯录已满,不能执行添加操作!\n");return;}//增加信息printf("联系人姓名:");scanf("%s", pc->data[pc->sz].name);printf("联系人性别:");scanf("%s", pc->data[pc->sz].sex);printf("联系人年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("联系人电话:");scanf("%s", pc->data[pc->sz].tel);printf("联系人住址:");scanf("%s", pc->data[pc->sz].addr);//增加成功pc->sz++;printf("增加成功!\n");}
3.展示通讯录内容
还是要实现对齐保持上下一致,用for循环直接打印全部信息。void ShowContact(Contact* pc){assert(pc);//打印之前判断通讯录中是否存在联系人if (pc->sz == 0){printf("通讯录为空,无需打印!\n");}int i = 0;printf("%-20s %-20s %-20s %-20s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");for (i = 0; i < pc->sz; i++){printf("%-20s %-20s %-20d %-20s %-20s\n",pc->data[i].name, pc->data[i].sex,pc->data[i].age, pc->data[i].tel,pc->data[i].addr);}}
4.删除通讯录内容
在里面要先创建name数组,来存放要删除的名字,之后需要判断要删除的人是否存在还需创建Find_name()函数来判断,并用ret接收。找到之后用for循环把后面的元素左移。最后人数减一。此函数如下:void DelContact(Contact* pc){assert(pc);char name[20];printf("请输入你要删除的联系人姓名:");scanf("%s", name);//查找联系人是否存在 //封装FindPeoInfo_ByName()函数 如果存在返回下标 如果不存在返回-1int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{int i = 0;//为什么是pc->sz-1?//1000个元素 下标0~999 //i < pc->sz-1 意味着只能访问到 i(max)=998 //pc->data[998] = pc->data[999];才不会发生下标越界for (i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}//若删除最后一个元素 最后一个元素不用被覆盖 pc->sz--即可pc->sz--;printf("删除成功!\n");}}
解析里面用到的FindPeoInfo_ByName():
除了用pc接收,还要接收删除name的地址,在里面用for循环,遍历查找,里面再用if判断语句来判断,用strcmp比较函数来比较所输入名字和通讯录名字是否一样。
如果一样返回下标。没有找到返回-1。
//遍历data数组 寻找姓名字符串一样的数组下标//如果存在返回下标 如果不存在返回-1static int FindPeoInfo_ByName(char* name, Contact* pc){int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(name, pc->data[i].name) == 0){return i;}}return -1;}
查找通讯录内容
前面的步骤和删除步骤一样,需要判断搜索的人是否存在,如果存在打印。为了让信息显示的更美观和直观,用对齐方式来实现且上下两个打印函数保持一致,负号表示右对齐。void SearchContact(Contact* pc){assert(pc);char name[20];printf("请输入你要查找的联系人姓名:");scanf("%s", name);int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{printf("该联系人存在:\n");printf("%-20s %-20s %-20s %-20s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%-20s %-20s %-20d %-20s %-20s\n",pc->data[ret].name, pc->data[ret].sex,pc->data[ret].age, pc->data[ret].tel,pc->data[ret].addr);}}
5.修改通讯录内容
void modify_meun(){printf("************************************************\n");printf("***1.姓名 2.性别 3.年龄 4.电话 5.住址 0.退出****\n");printf("************************************************\n");}enum modify_option{modify_exit,NAME,SEX,AGE,TEL,ADDR};void ModifyContact(Contact* pc){assert(pc);char name[20];printf("请输入你要修改的联系人姓名:");scanf("%s", name);int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{int modify_option = 0;printf("该联系人存在!\n");modify_meun();printf("请选择你要修改的信息:");scanf("%d", &modify_option);switch (modify_option){case NAME:printf("修改联系人姓名:");scanf("%s", pc->data[ret].name);break;case SEX:printf("修改联系人性别:");scanf("%s", pc->data[ret].sex);break;case AGE:printf("修改联系人年龄:");scanf("%d", &(pc->data[ret].age));break;case TEL:printf("修改联系人电话:");scanf("%s", pc->data[ret].tel);break;case ADDR:printf("修改联系人住址:");scanf("%s", pc->data[ret].addr);break;case modify_exit:printf("退出修改!\n");break;default:printf("不存在该选项,请重新选择!\n");break;}}}
6.清空通讯录
void EmptyContact(Contact* pc){assert(pc);if (pc->sz != 0){InitContact(pc);}}
7.排序通讯录 按名字 升序
void SortContact(Contact* pc){assert(pc);int i = 0;for (i = 0; i < pc->sz - 1; i++){int j = 0;for (j = 0; j < pc->sz - 1 - i; j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){Peoinfo temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("排序完成!\n");}
(四)实现菜单 测试函数功能
二、源码附录
(一)静态版本
1.1.contact.h
//工程所需要包含的头文件#include<stdio.h>#include<assert.h>#include<string.h>#include<stdlib.h>//将未来可能修改大小的值 定义成 标识符常量#define NAME_MAX 20#define SEX_MAX 5#define TEL_MAX 20#define ADDR_MAX 20#define DATA_MAX 1000//声明 一个 可以包含一条人信息的 结构体类型//并进行类型重命名 重命名为Peoinfotypedef struct Peoinfo{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];}Peoinfo;//声明并类型重命名 一个通讯录的 结构体类型//该类型包含//一个 Peoinfo类型的 结构体数组 data[] 用来存放每一个人的信息//一个 sz变量 用来记录当前通讯录中包含多少个人的信息typedef struct Contact{Peoinfo data[DATA_MAX];int sz;}Contact;//包含通讯录功能函数的声明//初始化通讯录void InitContact(Contact* con);//向通讯录中添加信息void AddContact(Contact* con);//展示通讯录内容void ShowContact(Contact* con);//删除通讯录内容void DelContact(Contact* con);//查找通讯录内容void SearchContact(Contact* con);//修改通讯录内容void ModifyContact(Contact* con);//清空通讯录void EmptyContact(Contact* con);//排序通讯录 按名字 升序void SortContact(Contact* con);
1.2.contact.c
//实现通讯录功能的函数#include"contact.h"void InitContact(Contact* pc){assert(pc);pc->sz = 0;memset(pc->data,0,sizeof(pc->data));}void AddContact(Contact* pc){assert(pc);//增加联系人之前 应先判断通讯录是否满了if (pc->sz == DATA_MAX){printf("通讯录已满,不能执行添加操作!\n");return;}//增加信息printf("联系人姓名:");scanf("%s", pc->data[pc->sz].name);printf("联系人性别:");scanf("%s", pc->data[pc->sz].sex);printf("联系人年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("联系人电话:");scanf("%s", pc->data[pc->sz].tel);printf("联系人住址:");scanf("%s", pc->data[pc->sz].addr);//增加成功pc->sz++;printf("增加成功!\n");}void ShowContact(Contact* pc){assert(pc);//打印之前判断通讯录中是否存在联系人if (pc->sz == 0){printf("通讯录为空,无需打印!\n");}int i = 0;printf("%-20s %-20s %-20s %-20s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");for (i = 0; i < pc->sz; i++){printf("%-20s %-20s %-20d %-20s %-20s\n",pc->data[i].name, pc->data[i].sex,pc->data[i].age, pc->data[i].tel,pc->data[i].addr);}}//遍历data数组 寻找姓名字符串一样的数组下标//如果存在返回下标 如果不存在返回-1static int FindPeoInfo_ByName(char* name, Contact* pc){int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(name, pc->data[i].name) == 0){return i;}}return -1;}void DelContact(Contact* pc){assert(pc);char name[20];printf("请输入你要删除的联系人姓名:");scanf("%s", name);//查找联系人是否存在 //封装FindPeoInfo_ByName()函数 如果存在返回下标 如果不存在返回-1int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{int i = 0;//为什么是pc->sz-1?//1000个元素 下标0~999 //i < pc->sz-1 意味着只能访问到 i(max)=998 //pc->data[998] = pc->data[999];才不会发生下标越界for (i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}//若删除最后一个元素 最后一个元素不用被覆盖 pc->sz--即可pc->sz--;printf("删除成功!\n");}}void SearchContact(Contact* pc){assert(pc);char name[20];printf("请输入你要查找的联系人姓名:");scanf("%s", name);int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{printf("该联系人存在:\n");printf("%-20s %-20s %-20s %-20s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%-20s %-20s %-20d %-20s %-20s\n",pc->data[ret].name, pc->data[ret].sex,pc->data[ret].age, pc->data[ret].tel,pc->data[ret].addr);}}void modify_meun(){printf("************************************************\n");printf("***1.姓名 2.性别 3.年龄 4.电话 5.住址 0.退出****\n");printf("************************************************\n");}enum modify_option{modify_exit,NAME,SEX,AGE,TEL,ADDR};void ModifyContact(Contact* pc){assert(pc);char name[20];printf("请输入你要修改的联系人姓名:");scanf("%s", name);int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{int modify_option = 0;printf("该联系人存在!\n");modify_meun();printf("请选择你要修改的信息:");scanf("%d", &modify_option);switch (modify_option){case NAME:printf("修改联系人姓名:");scanf("%s", pc->data[ret].name);break;case SEX:printf("修改联系人性别:");scanf("%s", pc->data[ret].sex);break;case AGE:printf("修改联系人年龄:");scanf("%d", &(pc->data[ret].age));break;case TEL:printf("修改联系人电话:");scanf("%s", pc->data[ret].tel);break;case ADDR:printf("修改联系人住址:");scanf("%s", pc->data[ret].addr);break;case modify_exit:printf("退出修改!\n");break;default:printf("不存在该选项,请重新选择!\n");break;}}}void EmptyContact(Contact* pc){assert(pc);if (pc->sz != 0){InitContact(pc);}}void SortContact(Contact* pc){assert(pc);int i = 0;for (i = 0; i < pc->sz - 1; i++){int j = 0;for (j = 0; j < pc->sz - 1 - i; j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){Peoinfo temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("排序完成!\n");}
1.3.test.c
用来测试通讯录的功能#include"contact.h"void meun(){printf("***************************\n");printf("*****1.ADD 2.DEL *****\n");printf("*****3.SEARCH 4.MODIFY*****\n");printf("*****5.SHOW 6.EMPTY *****\n");printf("*****7.SORT 0.EXIT *****\n");printf("***************************\n");}enum Option{EXIT,//0ADD,//1DEL,SEARCH,MODIFY,SHOW,EMPTY,SORT};int main(){int input = 0;//创建通讯录Contact con;//初始化通讯录InitContact(&con);do{meun();printf("请输入你的选择:");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case EMPTY:EmptyContact(&con);break;case SORT:SortContact(&con);break;case EXIT:printf("退出通讯录!\n");break;default:printf("没有可执行的操作,请重新选择!\n");break;}} while (input);return 0;}
(二)动态版本
2.1.contact.h
//工程所需要包含的头文件#include<stdio.h>#include<assert.h>#include<string.h>#include<stdlib.h>//将未来可能修改大小的值 定义成 标识符常量#define NAME_MAX 20#define SEX_MAX 5#define TEL_MAX 20#define ADDR_MAX 20#define DATA_MAX 1000//Dynamic版本#define DEFAULT_CAPACITY 3 #define DEFAULT_INC 2 //声明 一个 可以包含一条人信息的 结构体类型//并进行类型重命名 重命名为Peoinfotypedef struct Peoinfo{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];}Peoinfo;//Dynamic版本//声明并类型重命名 一个通讯录的 结构体类型//该类型包含//一个 Peoinfo类型的 data指针,用来接收calloc开辟的空间 (用来存放人的信息)//一个 sz变量 用来记录当前通讯录中包含多少个人的信息//一个 capacity变量 了用来记录当前通讯录的容量typedef struct Contact{Peoinfo *data;int sz;int capacity;}Contact;//通讯录功能函数的声明//初始化通讯录void InitContact(Contact* con);//向通讯录中添加信息void AddContact(Contact* con);//展示通讯录内容void ShowContact(Contact* con);//删除通讯录内容void DelContact(Contact* con);//查找通讯录内容void SearchContact(Contact* con);//修改联系人内容void ModifyContact(Contact* con);//清空通讯录void EmptyContact(Contact* con);//排序通讯录 按名字 升序void SortContact(Contact* con);//检查容量void CheckCapacity(Contact* con);//销毁通讯录void DestroyContact(Contact* con);
2.2.contact.c
//实现通讯录功能的函数#include"contact.h"//Dynamic版本void InitContact(Contact* pc){assert(pc);pc->sz = 0;//一开始默认通讯录的容量可以存 DEFAULT_CAPACITY 个人的信息pc->capacity = DEFAULT_CAPACITY;//所以开辟 pc->capacity个 大小为sizeof(Peoinfo)个字节的空间pc->data = (Peoinfo*)calloc(pc->capacity,sizeof(Peoinfo));//需要判断是否开辟成功if (pc->data == NULL){perror("InitContact->calloc");return;}}//检查通讯录容量void CheckCapacity(Contact* pc){//如果容量满了,调用realloc函数对动态开辟内存大小做调整if (pc->sz == pc->capacity){Peoinfo* ptr = realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(Peoinfo));//判断realloc是否开辟成功 若开辟成功再赋给pc->dataif (ptr != NULL){pc->data = ptr;pc->capacity += DEFAULT_INC;printf("增容成功!\n");}//若不成功 报错else{perror("AddContact->realloc:");return;}}}//用来释放动态开辟的内存空间 void DestroyContact(Contact* pc){free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;}//Dynamic 版本void AddContact(Contact* pc){assert(pc);//增加联系人之前 应先判断通讯录是否还有容量CheckCapacity(pc);//增加信息printf("联系人姓名:");scanf("%s", pc->data[pc->sz].name);printf("联系人性别:");scanf("%s", pc->data[pc->sz].sex);printf("联系人年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("联系人电话:");scanf("%s", pc->data[pc->sz].tel);printf("联系人住址:");scanf("%s", pc->data[pc->sz].addr);//增加成功pc->sz++;printf("增加成功!\n");}void ShowContact(Contact* pc){assert(pc);//打印之前判断通讯录中是否存在联系人if (pc->sz == 0){printf("通讯录为空,无需打印!\n");return;}int i = 0;printf("%-20s %-20s %-20s %-20s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");for (i = 0; i < pc->sz; i++){printf("%-20s %-20s %-20d %-20s %-20s\n",pc->data[i].name, pc->data[i].sex,pc->data[i].age, pc->data[i].tel,pc->data[i].addr);}}//遍历data数组 寻找姓名字符串一样的数组下标//如果存在返回下标 如果不存在返回-1static int FindPeoInfo_ByName(char* name, Contact* pc){assert(pc);int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(name, pc->data[i].name) == 0){return i;}}return -1;}void DelContact(Contact* pc){assert(pc);//首先判断通讯录是否有信息可以删除if (pc->sz = 0){printf("通讯录为空,无法删除!\n");return;}char name[NAME_MAX];printf("请输入你要删除的联系人姓名:");scanf("%s", name);//查找联系人是否存在 //封装FindPeoInfo_ByName()函数 如果存在返回下标 如果不存在返回-1int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");return;}//删除联系人else{int i = 0;//为什么是pc->sz-1?//1000个元素 下标0~999 //i < pc->sz-1 意味着只能访问到 i(max)=998 //pc->data[998] = pc->data[999];才不会发生下标越界for (i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}//若删除最后一个元素 最后一个元素不用被覆盖 pc->sz--即可pc->sz--;printf("删除成功!\n");}}void SearchContact(Contact* pc){assert(pc);char name[NAME_MAX];printf("请输入你要查找的联系人姓名:");scanf("%s", name);int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{printf("该联系人存在:\n");printf("%-20s %-20s %-20s %-20s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%-20s %-20s %-20d %-20s %-20s\n",pc->data[ret].name, pc->data[ret].sex,pc->data[ret].age, pc->data[ret].tel,pc->data[ret].addr);}}void modify_meun(){printf("************************************************\n");printf("***1.姓名 2.性别 3.年龄 4.电话 5.住址 0.退出****\n");printf("************************************************\n");}enum modify_option{modify_exit,NAME,SEX,AGE,TEL,ADDR};void ModifyContact(Contact* pc){assert(pc);char name[20];printf("请输入你要修改的联系人姓名:");scanf("%s", name);int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{int modify_option = 0;printf("该联系人存在!\n");modify_meun();printf("请选择你要修改的信息:");scanf("%d", &modify_option);switch (modify_option){case NAME:printf("修改联系人姓名:");scanf("%s", pc->data[ret].name);break;case SEX:printf("修改联系人性别:");scanf("%s", pc->data[ret].sex);break;case AGE:printf("修改联系人年龄:");scanf("%d", &(pc->data[ret].age));break;case TEL:printf("修改联系人电话:");scanf("%s", pc->data[ret].tel);break;case ADDR:printf("修改联系人住址:");scanf("%s", pc->data[ret].addr);break;case modify_exit:printf("退出修改!\n");break;default:printf("不存在该选项,请重新选择!\n");break;}}}void EmptyContact(Contact* pc){assert(pc);if (pc->sz != 0){InitContact(pc);return;}}void SortContact(Contact* pc){assert(pc);int i = 0;for (i = 0; i < pc->sz - 1; i++){int j = 0;for (j = 0; j < pc->sz - 1 - i; j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){Peoinfo temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("排序完成!\n");}
2.3.test.c
#include"contact.h"void meun(){printf("***************************\n");printf("*****1.ADD 2.DEL *****\n");printf("*****3.SEARCH 4.MODIFY*****\n");printf("*****5.SHOW 6.EMPTY *****\n");printf("*****7.SORT 0.EXIT *****\n");printf("***************************\n");}enum Option{EXIT,//0ADD,//1DEL,SEARCH,MODIFY,SHOW,EMPTY,SORT};int main(){int input = 0;//创建通讯录Contact con;//初始化通讯录InitContact(&con);do{meun();printf("请输入你的选择:");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case EMPTY:EmptyContact(&con);break;case SORT:SortContact(&con);break;case EXIT:DestroyContact(&con);printf("退出通讯录!\n");break;default:printf("没有可执行的操作,请重新选择!\n");break;}} while (input);return 0;}
(三)文件存储版本
3.1.contact.h
//工程所需要包含的头文件#include<stdio.h>#include<assert.h>#include<string.h>#include<stdlib.h>//将未来可能修改大小的值 定义成 标识符常量#define NAME_MAX 20#define SEX_MAX 5#define TEL_MAX 20#define ADDR_MAX 20#define DATA_MAX 1000//Dynamic版本新增#define DEFAULT_CAPACITY 3 #define DEFAULT_INC 2 //声明 一个 可以包含一条人信息的 结构体类型//并进行类型重命名 重命名为Peoinfotypedef struct Peoinfo{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];}Peoinfo;//Dynamic版本//声明并类型重命名 一个通讯录的 结构体类型//该类型包含//一个 Peoinfo类型的 data指针,用来接收calloc开辟的空间 (用来存放人的信息)//一个 sz变量 用来记录当前通讯录中包含多少个人的信息//一个 capacity变量 用来记录当前通讯录的容量typedef struct Contact{Peoinfo *data;int sz;int capacity;}Contact;//通讯录功能函数的声明//初始化通讯录void InitContact(Contact* con);//向通讯录中添加信息void AddContact(Contact* con);//展示通讯录内容void ShowContact(Contact* con);//删除通讯录内容void DelContact(Contact* con);//查找通讯录内容void SearchContact(Contact* con);//修改联系人内容void ModifyContact(Contact* con);//清空通讯录void EmptyContact(Contact* con);//排序通讯录 按名字 升序void SortContact(Contact* con);//检查容量void CheckCapacity(Contact* con);//销毁通讯录void DestroyContact(Contact* con);//保存通讯录内容到文件void SaveContact(Contact* con);//加载文件中的通讯录信息void LoadContact(Contact* con);
3.2.contact.c
#define _CRT_SECURE_NO_WARNINGS 1//实现通讯录功能的函数#include"contact.h"void CheckCapacity(Contact* pc);void LoadContact(Contact* pc){//打开文件FILE* pf = fopen("Contact.txt", "rb");if (pf == NULL){perror("LoadContact");return;}//读取文件//创建Peoinfo类型的临时变量,读取的数据暂放在Peoinfo中Peoinfo tmp = { 0 };//成功读取数据返回1 进入循环 ,返回0 没有读到 循环停止//读取一个放入一个while (fread(&tmp, sizeof(Peoinfo), 1, pf)){//放入数据前,先检测通讯录中的容量大小capacityCheckCapacity(pc);//放入数据pc->data[pc->sz] = tmp;//放入数据后 记录包含多少个人信息的变量+1pc->sz++;}//关闭文件fclose(pf);pf = NULL;}//File版本的初始化函数void InitContact(Contact* pc){assert(pc);pc->sz = 0;//一开始默认通讯录的容量可以存 DEFAULT_CAPACITY 个人的信息pc->capacity = DEFAULT_CAPACITY;//所以开辟 pc->capacity个 大小为sizeof(Peoinfo)个字节的空间pc->data = (Peoinfo*)calloc(pc->capacity, sizeof(Peoinfo));//需要判断是否开辟成功if (pc->data == NULL){perror("InitContact->calloc");return;}//加载文件中的信息//加载pc所指向的通讯录中信息LoadContact(pc);}void CheckCapacity(Contact* pc){//如果容量满了,调用realloc函数对动态开辟内存大小做调整if (pc->sz == pc->capacity){Peoinfo* ptr = realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(Peoinfo));//判断realloc是否开辟成功 若开辟成功再赋给pc->dataif (ptr != NULL){pc->data = ptr;pc->capacity += DEFAULT_INC;printf("增容成功!\n");}//若不成功 报错else{perror("AddContact->realloc:");return;}}}//用来释放动态开辟的内存空间 void DestroyContact(Contact* pc){free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;}//Dynamic 版本void AddContact(Contact* pc){assert(pc);//增加联系人之前 应先判断通讯录是否还有容量CheckCapacity(pc);//增加信息printf("联系人姓名:");scanf("%s", pc->data[pc->sz].name);printf("联系人性别:");scanf("%s", pc->data[pc->sz].sex);printf("联系人年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("联系人电话:");scanf("%s", pc->data[pc->sz].tel);printf("联系人住址:");scanf("%s", pc->data[pc->sz].addr);//增加成功pc->sz++;printf("增加成功!\n");}void ShowContact(Contact* pc){assert(pc);//打印之前判断通讯录中是否存在联系人if (pc->sz == 0){printf("通讯录为空,无需打印!\n");return;}int i = 0;printf("%-20s %-20s %-20s %-20s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");for (i = 0; i < pc->sz; i++){printf("%-20s %-20s %-20d %-20s %-20s\n",pc->data[i].name, pc->data[i].sex,pc->data[i].age, pc->data[i].tel,pc->data[i].addr);}}//遍历data数组 寻找姓名字符串一样的数组下标//如果存在返回下标 如果不存在返回-1static int FindPeoInfo_ByName(char* name, Contact* pc){assert(pc);int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(name, pc->data[i].name) == 0){return i;}}return -1;}void DelContact(Contact* pc){assert(pc);//首先判断通讯录是否有信息可以删除if (pc->sz = 0){printf("通讯录为空,无法删除!\n");return;}char name[NAME_MAX];printf("请输入你要删除的联系人姓名:");scanf("%s", name);//查找联系人是否存在 //封装FindPeoInfo_ByName()函数 如果存在返回下标 如果不存在返回-1int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");return;}//删除联系人else{int i = 0;//为什么是pc->sz-1?//1000个元素 下标0~999 //i < pc->sz-1 意味着只能访问到 i(max)=998 //pc->data[998] = pc->data[999];才不会发生下标越界for (i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}//若删除最后一个元素 最后一个元素不用被覆盖 pc->sz--即可pc->sz--;printf("删除成功!\n");}}void SearchContact(Contact* pc){assert(pc);char name[NAME_MAX];printf("请输入你要查找的联系人姓名:");scanf("%s", name);int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{printf("该联系人存在:\n");printf("%-20s %-20s %-20s %-20s %-20s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%-20s %-20s %-20d %-20s %-20s\n",pc->data[ret].name, pc->data[ret].sex,pc->data[ret].age, pc->data[ret].tel,pc->data[ret].addr);}}void modify_meun(){printf("************************************************\n");printf("***1.姓名 2.性别 3.年龄 4.电话 5.住址 0.退出******\n");printf("************************************************\n");}enum modify_option{modify_exit,NAME,SEX,AGE,TEL,ADDR};void ModifyContact(Contact* pc){assert(pc);char name[20];printf("请输入你要修改的联系人姓名:");scanf("%s", name);int ret = FindPeoInfo_ByName(name, pc);if (ret == -1){printf("该联系人不存在!\n");}else{int modify_option = 0;printf("该联系人存在!\n");modify_meun();printf("请选择你要修改的信息:");scanf("%d", &modify_option);switch (modify_option){case NAME:printf("修改联系人姓名:");scanf("%s", pc->data[ret].name);break;case SEX:printf("修改联系人性别:");scanf("%s", pc->data[ret].sex);break;case AGE:printf("修改联系人年龄:");scanf("%d", &(pc->data[ret].age));break;case TEL:printf("修改联系人电话:");scanf("%s", pc->data[ret].tel);break;case ADDR:printf("修改联系人住址:");scanf("%s", pc->data[ret].addr);break;case modify_exit:printf("退出修改!\n");break;default:printf("不存在该选项,请重新选择!\n");break;}}}void EmptyContact(Contact* pc){assert(pc);if (pc->sz != 0){InitContact(pc);return;}}void SortContact(Contact* pc){assert(pc);int i = 0;for (i = 0; i < pc->sz - 1; i++){int j = 0;for (j = 0; j < pc->sz - 1 - i; j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){Peoinfo temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("排序完成!\n");}void SaveContact(Contact* pc){//打开文件FILE* pf = fopen("Contact.txt", "wb");//判断文件是否打开成功,若打开失败报错if (pf == NULL){perror("SaveContact");return;}//写文件:将通讯录的内容写入文件int i = 0;for (i = 0; i < pc->sz; i++){//一种写法//fwrite(&(pc->data[i]), sizeof(Peoinfo), 1, pf);//另一种写法fwrite(pc->data+i, sizeof(Peoinfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;}
3.3.test.c
#include"contact.h"void meun(){printf("***************************\n");printf("*****1.ADD 2.DEL *****\n");printf("*****3.SEARCH 4.MODIFY*****\n");printf("*****5.SHOW 6.EMPTY *****\n");printf("*****7.SORT 0.EXIT *****\n");printf("***************************\n");}enum Option{EXIT,//0ADD,//1DEL,SEARCH,MODIFY,SHOW,EMPTY,SORT};int main(){int input = 0;//创建通讯录Contact con;//初始化通讯录InitContact(&con);do{meun();printf("请输入你的选择:");scanf("%d", &input);switch (input){//添加联系人case ADD:AddContact(&con);break;//删除联系人case DEL:DelContact(&con);break;//查找联系人case SEARCH:SearchContact(&con);break;//修改联系人case MODIFY:ModifyContact(&con);break;//展示通讯录case SHOW:ShowContact(&con);break;//清空通讯录case EMPTY:EmptyContact(&con);break;//排序case SORT:SortContact(&con);break;case EXIT://保存信息到文件SaveContact(&con);DestroyContact(&con);printf("退出通讯录!\n");break;default:printf("没有可执行的操作,请重新选择!\n");break;}} while (input);return 0;}