前言
今天,我们来尝试利用已经学过的知识,来实现一下通讯录~
基本思路
文件的创建和分工
还是像之前的扫雷、三子棋之类的游戏一样,对于通讯录的实现,我们也分为三个文件:两个源文件(test.c\contract.c)、一个头文件(contact.h)
1.test.c:负责测试功能是否正常
2.contract.c:负责实现通讯录的功能
3.contact.h:声明需要的函数(库函数和自定义函数)
实现的步骤
1.存放用户信息(用户数量自定义)
用户信息:名字+年龄+性别+电话+住址
2.通讯录功能:
增加用户信息
删除用户信息
查找用户信息
修改用户信息
打印用户信息
实现过程
注意:实现过程的讲解并不是一个文件一个文件去讲解的(毕竟真正写代码的时候,也不是写完一个文件再去写下一个文件)
至于各个函数具体创建在哪个文件下面,在目录中都有说明
在文章中有很多“优化”这样的标题:意思是代码有可以优化的地方,对于优化前的代码我不会删掉,而是注释掉他们,保留优化后的代码
并且,为方便理解,我对于代码做了注释,提高可读性
test.c函数
我们将test.c拆分成几部分来分别实现
循环部分我们依然用do while循环
menu函数
这是我们的老朋友了,格式跟之前基本一样,在此就不多介绍了,直接看代码吧
void menu() { printf("**************************************\n"); printf("**********1.add 2.del *******\n"); printf("**********3.search 4.modify *******\n"); printf("**********5.show 6.sort *******\n"); printf("**********0.exit *******\n"); printf("**************************************\n"); printf("**************************************\n"); }
main函数
main的基本框架:
(仍可优化)
int main() { int input = 0; do { menu(); printf("请选择:>"); scanf("%d", &input); switch(input) { case 1: break; case 2: break; case 3: break; case 4: break; case 5: break; case 6: break; case 0: printf("退出通讯录\n"); break; default: printf("输入错误\n"); break; } } while (input); return 0; }
contract.h函数
创建通讯录
通讯录作用;用于存放用户信息
用户信息:名字+电话+性别+住址+年龄
对于复杂对象,肯定是使用结构体了
并且,为了方便,我们使用宏定义,方便我们以后修改
#define MAX 1000 #define MAX_NAME 20 #define MAX_SEX 5 #define MAX_TELE 12 #define MAX_ADDR 30 struct PeoInfo { char name[MAX_NAME]; int age; char sex[MAX_SEX]; char tele[MAX_TELE]; char addr[MAX_ADDR]; };
在main函数中,要创建一个变量来记录通讯录里面已经存储了多少个用户数据
再创建一个变量来记录通讯录最多可以存储多少个用户数据:即MAX
优化1
我们可以注意到,1~6这六种情况一共要创建6个函数,每个函数都要传入两个参数,这时我们想到:不如再单独封装出一个函数(也是在contract.h中创建),来简化传参
struct Contract { struct PeoInfo data[MAX]; int size; };
在main函数中创建通讯录时,就可以写成
struct Contract con;//con就是创建的通讯录,里面有一个元素个数为1000的数组和size变量
在传参时,也可以直接写成con
InitContract函数(在contract.h中声明、在contract.c中实现)
初始化通讯录(传址)
要初始两个元素:data数组和通讯录数据个数size
data的初始化
data是一块很大的空间,所以我们可以使用memset函数
size的初始化
设置通讯录只有零个元素
提示:因为结构体成员无法初始化,所以才需要在InitContract函数中实现初始化
代码如下:
void InitContract(struct Contract* ps) { memset(ps->data, 0, sizeof(ps->data));//data是一块很大的空间,所以我们可以使用memset函数 ps->size = 0;//设置通讯录只有零个元素 }
AddContract函数(在contract.h中声明、在contract.c中实现)
作用:添加用户数据
AddContract(&con)
传入数组首元素地址,从首元素开始存放
传入通讯录大小,传地址是为了判断下一个数据要存在哪里、以及判断通讯录是否填满
代码如下:
判断满没满
输入数据
表明结果
void AddContract(struct Contract* ps) { if ((ps->size) = MAX) { printf("通讯录已满,请停止添加\n");//判断是否填满 } else { printf("请输入名字:>"); scanf("%s", ps->data[ps->size].name); printf("请输入年龄:>"); scanf("%s", &(ps->data[ps->size].age)); //提示:因为age不是数组名,所以需要取地址 printf("请输入性别:>"); scanf("%s", ps->data[ps->size].sex); printf("请输入电话:>"); scanf("%s", ps->data[ps->size].tele); printf("请输入地址:>"); scanf("%s", ps->data[ps->size].addr); (ps->size)++; printf("添加成功\n"); } }
表明结果就需要另一个函数:ShowContract函数了
ShowContract函数(在contract.h中声明、在contract.c中实现)
打印用户信息
为了美观和对齐,在打印用户数据之前,先输出一行用户数据列表
printf("%20s\t%4s\t5s\t%12s\t%20s", "名字", "年龄", "性别", "电话", "地址");
代码如下:
void ShowContract(const struct Contract* ps) { if (ps->size == 0) { printf("通讯录为空\n"); } else { int i = 0; printf("%-20s\t%-4s\t-5s\t%-12s\t%-20s", "名字", "年龄", "性别", "电话", "地址"); for (i = 0; i < (ps->size); i++) { printf("%-20s\t%-4s\t-5s\t%-12s\t%-20s",ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].tele, ps->data[i].addr); } } }