=========================================================================

相关代码gitee自取:C语言学习日记: 加油努力 (gitee.com)

=========================================================================

接上期

学C的第三十天【自定义类型:结构体、枚举、联合】_高高的胖子的博客-CSDN博客

=========================================================================

通讯录需求:

实现一个通讯录

通讯录中存放保存人的信息

名字年龄性别

电话地址

通讯录相关功能

  • 通讯录中可以存放100个人的信息
  • 增加联系人
  • 删除指定联系人
  • 修改指定联系人
  • 查找指定联系人
  • 显示所有联系人的信息
  • 排序功能

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

多文件实现通讯录

(1). contact.h文件 — 相关函数和结构体类型的声明:

1 . 结构体 struct PeoInfo — 存放通讯录联系人的信息:

使用 typedef 重命名结构体

struct PeoInfo 重命名PeoInfo

方便后续使用

图示:

2 .结构体 struct contact — 通讯录类型:

使用 typedef 重命名结构体

创建通讯录信息结构体变量数组

创建一个变量来记录当前通讯录data的人数

图示:

3 . 函数 InitContact() 的声明 — 初始化通讯录类型变量

参数接收 通讯录类型变量地址

返回类型 void

图示:

4 .函数 AddContact() 的声明 — 增加通讯录成员:

参数接收 通讯录类型变量地址

返回类型 void

图示:

5 . 对常量使用进行优化 — 设置 全局变量 和 枚举

(一).

设置 全局变量

contact.h 中,

定义全局变量 MAX 100设置通讯录最多人数,

其它通讯录信息也是同理

图示:

(二).

设置 枚举

对测试中,用户输入的选项进行枚举

用对应的功能名字代表对应的选项

在 contact.h 文件中设置好后,

在 test.c 文件中进行修改

图示:

6 .函数 ShowContact() 的声明 — 打印通讯录所有成员信息:

参数接收 const Contact* pc

只是打印,不用修改所以设置为常量

返回类型 void

图示:

7 .函数 FindByName() 的声明 — 删除指定通讯录成员信息:

参数接收 通讯录类型变量地址 要查找的名字字符串

返回类型 — int,返回找到的元素下标 或 未找到情况的-1

注:

该函数只在 contact.c文件 中支持其它函数,
为了保密可以不在该文件声明

图示:

8 .函数 DelContact() 的声明 — 删除指定通讯录成员信息:

参数接收 通讯录类型变量地址

返回类型 void

图示:

9 .函数 SearchContact() 的声明 — 查找指定通讯录成员信息:

参数接收 const Contact* pc

只是打印,不用修改所以设置为常量

返回类型 void

图示:

10 .函数 ModifyContact() 的声明 — 查找指定通讯录成员信息:

参数接收 通讯录类型变量地址

返回类型 void

图示:

该文件对应代码:

#define _CRT_SECURE_NO_WARNINGS 1//contact.h文件 -- 相关函数和类型的声明://包含头文件:#include #include #include //定义全局变量 MAX 100 -- 设置通讯录最多人数#define MAX 100//通讯录信息也是同理:#define MAX_NAME 20#define MAX_SEX 5#define MAX_TELE 12#define MAX_ADDR 30//对测试中,用户输入的选项进行枚举,//用对应的功能名字代表对应的选项:enum OPTION{//枚举中的内容默认0开始往后排:EXIT,// 0 对应 退出ADD,// 1 对应 增加DEL,// 2 对应 删除SEARCH, // 3 对应 搜索MODIFY, // 4 对应 修改SHOW,// 5 对应 显示所有SORT// 6 对应 排序};//1.结构体 struct PeoInfo -- 存放保存人的信息://使用 typedef 重命名结构体,typedef struct PeoInfo{char name[MAX_NAME]; //名字int age; //年龄char sex[MAX_SEX]; //性别char tele[MAX_TELE]; //电话char addr[MAX_ADDR]; //地址}PeoInfo;//2.结构体 struct contact -- 通讯录类型://使用 typedef 重命名结构体,typedef struct contact{//创建通讯信息录结构体变量数组:PeoInfo data[MAX];//创建一个变量来记录当前通讯录data的人数:int sz;}Contact;//3.函数 InitContact() 的声明 -- 初始化通讯录类型变量void InitContact(Contact* pc);//4.函数 AddContact() 的声明 -- 增加通讯录成员:void AddContact(Contact* pc);//6.函数 ShowContact() 的声明 -- 打印通讯录所有成员信息:void ShowContact(const Contact* pc);//7.函数 FindByName() 的声明-- 删除指定通讯录成员信息://该函数只在 contact.c文件 中支持其它函数,//为了保密可以不在该文件声明int FindByName(Contact* pc, char name[]);//8.函数 DelContact() 的声明 -- 删除指定通讯录成员信息:void DelContact(Contact* pc);//9.函数 SearchContact() 的声明 -- 查找指定通讯录成员信息:void SearchContact(const Contact* pc);//10 .函数 ModifyContact() 的声明 -- 查找指定通讯录成员信息:void ModifyContact(Contact* pc);

————————————————————————————————————————

(2). contact.c文件 — 自定义函数的实现:

1 .函数 InitContact()– 初始化通讯录类型变量

contact.h文件包含 头文件

再在 contact.c文件包含通讯录函数声明头文件:

使用 memset系统函数初始化data数组

参数1被设置的空间data

参数2要设置的值0 (全部初始化为0)

参数3要设置的空间大小sizeof(pc->data) ,直接计算出大小

联系人个数 sz 初始化为0

图示:

2 .函数 AddContact()– 增加通讯录成员:

增加的前提还没放满

判断通讯录是否人数已满

如果未满则开始添加信息

sz data数组 的下标对应的,
所以可以通过 sz 找到 data 的对应元素
通过对应元素找到对应元素的相应信息

如果对应的信息是数组,可以不加 取地址符&

使用 scanf()函数 将信息放进去

添加完一个联系人后,将指针移向下一个联系人位置

打印添加成功信息

图示:

3 .函数 ShowContact()– 打印通讯录所有成员信息:

打印列标题

再使用 for循环 循环打印信息

注意巧用 printf()函数

图示:

4 .函数 FindByName()– 删除指定通讯录成员信息:

使用 for循环 循环在通讯录中查找该人坐标

使用 strcmp函数 进行判断名字是否存在

如果找到了则返回下标未找到则返回-1

图示:

5 .函数 DelContact()– 删除指定通讯录成员信息:

判断通讯录是否为空为空没法删除则直接返回

不为空

输入接收删除的联系人名字

调用 FindByName()函数 在通讯录中查找该人下标

未找到打印相应信息并返回

找到了删除该下标的联系人

删除后,将指针向前移一位

最后打印删除成功

图示:

6 .函数 SearchContact()– 查找指定通讯录成员信息:

输入接收查找的联系人名字

调用 FindByName()函数 在通讯录中查找该人下标

未找到打印相应信息并返回

找到了打印该下标的联系人信息

图示:

7 .函数 ModifyContact()– 查找指定通讯录成员信息:

输入接收修改的联系人名字

调用 FindByName()函数 在通讯录中查找该人下标

未找到打印相应信息并返回

找到了修改该下标联系人信息


图示:

该文件对应代码:

#define _CRT_SECURE_NO_WARNINGS 1//contact.c文件 -- 自定义函数的实现://包含头文件:#include "contact.h"//1.函数 InitContact()--初始化通讯录类型变量void InitContact(Contact* pc){//断言:assert(pc);memset(pc->data, 0, sizeof(pc->data));/*使用 memset系统函数,初始化data数组。参数1:被设置的空间 -- data参数2:要设置的指-- 0 (全部初始化为0)参数3:要设置的空间大小-- sizeof(pc->data) , 直接计算出大小*///联系人个数初始化为0:pc->sz = 0;}//2.函数 AddContact() 的声明 -- 增加通讯录成员:void AddContact(Contact* pc){//断言:assert(pc);//增加的前提是还没放满:if (pc->sz == MAX){printf("通讯录已满,无法添加\n");//无法添加直接返回:return;}//没满则开始增加信息:// sz 和 data数组 的下标是对应的,// 所以可以通过 sz 找到 data 的对应元素,// 再通过对应元素找到对应元素的相应信息// 如果对应的信息是数组。可以不加&//名字:printf("请输入名字:>");//使用 scanf()函数 将信息放进去scanf("%s", pc->data[pc->sz].name);//年龄:printf("请输入年龄:>");//使用 scanf()函数 将信息放进去scanf("%d", &pc->data[pc->sz].age);//性别:printf("请输入性别:>");//使用 scanf()函数 将信息放进去scanf("%s", pc->data[pc->sz].sex);//电话:printf("请输入电话:>");//使用 scanf()函数 将信息放进去scanf("%s", pc->data[pc->sz].tele);//地址:printf("请输入地址:>");//使用 scanf()函数 将信息放进去scanf("%s", pc->data[pc->sz].addr);//添加完一个联系人后,将指针移向下一个联系人位置:pc->sz++;//打印添加成功信息:printf("成功添加联系人\n");}//3 .函数 ShowContact()-- 打印通讯录所有成员信息:void ShowContact(const Contact* pc){//断言:assert(pc);printf("\n");//打印列标题:printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n","名字", "年龄", "性别", "电话", "地址");//使用 for循环 循环打印信息:int i = 0;for (i = 0; i sz; i++){printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);// %20S:打印20个字符,这里名字是20个字符// \t: 使用制表符进行对齐// %4d:打印4个整型,这里是年龄// “-”号 :左对齐}printf("\n");}//4 .函数 FindByName()-- 删除指定通讯录成员信息:int FindByName(const Contact* pc, char name[]){//遍历查找该人坐标:int i = 0;for (i = 0; i sz; i++){if (strcmp(pc->data[i].name, name) == 0)//如果 找到了一个下标元素的name 和 要找的name 一样{return i; //返回此时找到的下标}}return -1; //未找到则返回-1}//5 . 函数 DelContact()--删除指定通讯录成员信息:void DelContact(Contact* pc){//断言:assert(pc);//先判断通讯录是否为空:if (pc->sz == 0){//为空就没法删除了,直接返回printf("通讯录为空,无法删除\n");return;}//创建存放要删除联系人名字的字符数组:char name[MAX_NAME] = { 0 };//输入并接收删除联系人名字:printf("请输入要删除的人名字:>");scanf("%s", name);//因为在通讯录中查找某人是多个功能所需要的,//所以可以将其封装成函数,再调用:int del = FindByName(pc, name);//如果del为-1,说明未找到:if (del == -1){printf("要删除的人不存在\n");return; //直接返回}//如果找到了则删除坐标为del的联系人:int i = 0;for (i = del; i sz-1; i++)//从del下标开始,到倒数第二个元素{pc->data[i] = pc->data[i + 1];//把del后1个元素赋给del,循环覆盖掉del的元素//倒数第二个元素+1 为最后一个元素为止}//删除一个后,将pc指针向前移一位:pc->sz--;//打印提示:printf("成功删除该联系人\n");}//6 .函数 SearchContact()-- 查找指定通讯录成员信息:void SearchContact(const Contact* pc){//断言:assert(pc);//创建存放要查找的联系人名字的字符数组:char name[MAX_NAME] = { 0 };//输入并接收要查找联系人名字:printf("请输入要查找的联系人名字:>");scanf("%s", name);//使用 FindByName() 函数查找该人在通讯录中的下标:int pos = FindByName(pc, name);//如果del为-1,说明未找到:if (pos == -1){printf("要查找的人不存在\n");return; //直接返回}else //找到了则打印该人信息: {//打印列标题:printf("%-10s\t%-4s\t%-5s\t%-12s\t%-30s\n","名字", "年龄", "性别", "电话", "地址");//打印对应信息:printf("%-10s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].name,pc->data[pos].age,pc->data[pos].sex,pc->data[pos].tele,pc->data[pos].addr);}}//7 .函数 ModifyContact()-- 查找指定通讯录成员信息:void ModifyContact(Contact* pc){//断言:assert(pc);//创建存放要修改的联系人名字的字符数组:char name[MAX_NAME] = { 0 };//输入并接收要修改联系人名字:printf("请输入要修改的联系人名字:>");scanf("%s", name);//使用 FindByName() 函数查找该人在通讯录中的下标:int pos = FindByName(pc, name);//如果del为-1,说明未找到:if (pos == -1){printf("要修改的人不存在\n");return; //直接返回}else //找到了则修改该人信息: {//名字:printf("请输入名字:>");//使用 scanf()函数 将信息放进去scanf("%s", pc->data[pos].name);//年龄:printf("请输入年龄:>");//使用 scanf()函数 将信息放进去scanf("%d", &pc->data[pos].age);//性别:printf("请输入性别:>");//使用 scanf()函数 将信息放进去scanf("%s", pc->data[pos].sex);//电话:printf("请输入电话:>");//使用 scanf()函数 将信息放进去scanf("%s", pc->data[pos].tele);//地址:printf("请输入地址:>");//使用 scanf()函数 将信息放进去scanf("%s", pc->data[pos].addr);printf("修改成功\n");}}

————————————————————————————————————————

(3). test.c文件 — 测试通讯录:

1 . 函数 void menu() — 打印通讯录菜单:

告知使用者输入对应数字实现对应功能

图示:

2 .函数 void test() — 完成通讯录测试:

(一).

使用 do while 循环

打印菜单

根据输入的选项判断是否需要再进行服务

可以使用 switch 语句进行筛选判断

图示:

(二).

包含头文件

通过结构体 struct contact(Contact),

创建通讯录类型变量con

包含data数组,存放有效的通讯录数据

sz,记录存放数据的个数

创建后还需要初始化

调用 函数InitContact() 进行初始化

参数接收通讯录类型变量的地址 &con

图示:

(三).

如果用户输入 1

则调用 函数AddContact()

增加联系人,

参数接收 &con 对通讯录进行对应操作

如果用户输入 2

则调用 函数DelContact()

删除指定通讯录成员,

参数接收 &con 对通讯录进行对应操作

如果用户输入 3

则调用 函数SearchContact()

查找指定联系人信息,

参数接收 &con 对通讯录进行对应操作

如果用户输入 4

则调用 函数ModifyContact()

修改指定联系人信息,

参数接收 &con 对通讯录进行对应操作

如果用户输入 5

则调用 函数ShowContact()

打印所有联系人信息,

参数接收 &con 对通讯录进行对应操作

如果用户输入 0

打印对应信息退出程序

如果用户 输入非法

打印对应信息重新输入

图示:

3 . 主函数

直接调用 test()测试函数即可

图示:

该文件对应代码:

#define _CRT_SECURE_NO_WARNINGS 1//test.c文件 -- 测试通讯录://包含头文件:#include "contact.h"//1 . 函数 void menu() -- 打印通讯录菜单:void menu(){// 选1:增加联系人选2:删除联系人// 选3:搜索联系人选4:修改联系人信息// 选5:显示所有联系人选6:对联系人进行排序//选0:退出通讯录printf("*****************************************************\n");printf("*****1. add2. del*****\n");printf("*****3. search4. modify*****\n");printf("*****5. show6. sort*****\n");printf("*****0. exit*****\n");printf("*****************************************************\n");}//函数 void test() -- 完成通讯录测试:void test(){//创建通讯录类型变量:Contact con;//调用函数初始化通讯录类型变量:InitContact(&con);int input = 0;//接收输入的数据do{//调用菜单函数打印菜单:menu();//接收输入数据:printf("请选择:>");scanf("%d", &input);//使用switch语句进行筛选判断:switch (input){case ADD://如果用户输入1,//则调用AddContact()函数//添加联系人:AddContact(&con);//参数接收 &con ,对通讯录进行对应操作break;case DEL://如果用户输入2,//则调用DelContact()函数//删除指定联系人:DelContact(&con);//参数接收 &con ,对通讯录进行对应操作break;case SEARCH://如果用户输入3,//则调用SearchContact()函数//查找指定联系人:SearchContact(&con);//参数接收 &con ,对通讯录进行对应操作break;case MODIFY://如果用户输入 4,//则调用ModifyContact()函数//修改指定联系人信息ModifyContact(&con);//参数接收 &con ,对通讯录进行对应操作break;case SHOW://如果用户输入5,//则调用ShowContact()函数//打印所有联系人信息:ShowContact(&con);//参数接收 &con ,对通讯录进行对应操作break;case SORT://待定break;case EXIT://如果用户输入0,//打印对应信息并退出程序:printf("退出通讯录\n");break;default://如果用户 输入非法,//打印对应信息并程序输入:printf("选择错误,重新选择\n");break;}} while (input);//只要输入数据不为0就继续进行}//主函数:int main(){//调用测试函数进行测试:test();return;}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

最终实现效果: