【通讯录项目 (3 / 3)】基于顺序表的通讯录实现——通讯录项目实现
前言
前两章我们已经知道顺序表的功能并完成了功能实现,下面我们将实现通讯录的以下功能:
1 项目预备工作
1.1 多文件处理
首先我们要对所用文件进行分类管理,以便后续操作。
我们将要在顺序表的基础上增加“contact.h”头文件和“contact.c”功能文件
注意头文件的正确引用
如下
请仔细检查,这是完成较大项目的基础。不同文件管理不同内容,方便快捷,效率高。
1.2 联系人数据管理
接下来是联系人的数据管理,我们需要改变原本顺序表的“SLDataType”为一个新类型。*我们可以想到联系人的信息不一,所以我们使用结构体来管理数据。
#define NAME_MAX 100 #define SEX_MAX 4 #define TEL_MAX 20 #define ADDR_MAX 200 //前置声明 typedef struct SeqList contact; //用户数据 typedef struct PersonInfo { char name[NAME_MAX]; char sex[SEX_MAX]; int age; char tel[TEL_MAX]; char addr[ADDR_MAX]; }PeoInfo;
我们用宏定义常量,方便后续查看修改。这里我设置了姓名 性别 年龄 号码 地址五种信息。代码中“前置声明”是为了避免后续引用出现问题。我们通过“typedef”进行重命名,方便后续书写代码。
2 功能实现
上面将我们的准备工作进行完毕,下面开始实现功能。我们基于顺序表在进行操作。如有不理解的地方请参考【通讯录项目 (2 / 3)】,下面不对 顺序表功能 进行详细说明
我们会使用顺序表大多数功能,请理解顺序表的功能在进行阅读。
2.1 初始化通讯录
“初始化”只需要简单的引用顺序表的初始化即可。
void InitContact(contact* con) { SLInit(con); }
void SLInit(SL* ps) { assert(ps);//断言判断是否为空 ps->a = NULL;//将初始地址改为空 ps->size = ps->capacity = 0;//容量与大小定为空 }
这样就实现了初始化,与初始化顺序表一致。
2.2 添加联系人
添加联系人也非常简单,只需要依次输入数据,在进行顺序表的插入即可。
void AddContact(contact* con) { assert(con); PeoInfo info; printf("请输入联系人姓名:\n"); scanf("%s", info.name); printf("请输入联系人的性别:\n"); scanf("%s", info.sex); printf("请输入联系人的年龄:\n"); scanf("%d", &info.age); //这里需要取地址,因为age是int类型,其余为数组 printf("请输入联系人的电话:\n"); scanf("%s", info.tel); printf("请输入联系人的住址:\n"); scanf("%s", info.addr); SLPushBack(con,info); printf("添加成功\n");
void SLPushBack(SL* ps, SLDataType x) { assert(ps); SLCheckCapacity(ps); ps->a[ps->size++] = x;
这样就进行了数据的加入。
2.3 删除联系人
删除联系人依然使用顺序表的删除功能。这里需要一个"查找联系人"的功能。需要通过一个信息来查找联系人是否存在。
2.3.1 查找目标
我们输入一个信息,来进行遍历查找联系人。返回目标的偏移值。
//查找联系人 int findname(contact* con, char name[NAME_MAX]) { assert(con); for (int i = 0; i < con->size; i++) { if (strcmp(con->a[i].name, name) == 0) { return i; } } return -1; }
2.3.2 删除联系人
同样使用顺序表的删除功能来实现,通过“查找联系人”返回的偏移值来进行定位
void DelContact(contact* con) { assert(con); char find[NAME_MAX] = { 0 }; printf("请输入你想删除的联系人姓名:> \n"); scanf("%s",find); int ret = findname(con, find); if (ret < 0) { printf("未找到该联系人\n"); } else SLErase(con, ret); }
void SLErase(SL*ps,int pos) { assert(ps); if (pos >= 0 && pos < ps->size) { for (int i = pos; i < ps->size - 1; i++) { ps->a[i] = ps->a[i + 1];//a[size-2]=a[size-1]模拟最后一次查找 } ps->size--; } else assert(pos); }
这样通过覆盖就完成了删除功能。
2.4 展示通讯录
展示通讯录的功能是对顺序表展示的扩展。
void ShowContact(contact* pcon) { //打印通讯录所有的数据 //先打印表头文字 assert(pcon); printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址"); for (int i = 0; i < pcon->size; i++) { printf("%-4s %-4s %-4d %-11s %-4s\n", pcon->a[i].name, pcon->a[i].sex, pcon->a[i].age, pcon->a[i].tel, pcon->a[i].addr ); } }
只需遍历顺序表,并打印联系人数据即可。
注意换行符,与打印格式让界面更加美观。
2.5 查找与修改
查找与修改操作相似,我们放在一起说明
2.5.1 查找联系人
查找联系人以上面的查找目标功能为基础,通过遍历进行查找。这里需要进行一次打印操作来展示查找结果
void FindContact(contact* con) { assert(con); char find[NAME_MAX] = { 0 }; printf("请输入想要查找的联系人姓名:> \n"); scanf("%s",find); int ret = findname(con, find); if (ret < 0) { printf("未找到该联系人\n"); } else{ printf("找到了\n"); printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "住址"); printf("%-4s %-4s %-4d %-4s %-4s\n", con->a[ret].name, con->a[ret].sex, con->a[ret].age, con->a[ret].tel, con->a[ret].addr ); } }
2.5.2 修改联系人
修改联系人同样基于“查找目标”功能的基础,并进行一次修改操作。
oid ModifyContact(contact* con) { assert(con); int name[NAME_MAX] = { 0 }; printf("请输入想修改的联系人: > \n"); scanf("%s", name); int ret = findname(con, name); //通过偏移量进行修改 printf("请输入联系人姓名:\n"); scanf("%s", con->a[ret].name); printf("请输入联系人的性别:\n"); scanf("%s", con->a[ret].sex); printf("请输入联系人的年龄:\n"); scanf("%d", &con->a[ret].age); printf("请输入联系人的电话:\n"); scanf("%s", con->a[ret].tel); printf("请输入联系人的住址:\n"); scanf("%s", con->a[ret].addr); printf("修改完成\n"); ShowContact(con); }
2.6 销毁通讯录
销毁功能是对储存空间的操作,通过free来实现销毁。
void DestroyContact(contact* con) { assert(con); free(con->a); con->size = con->capacity = 0; con->a = NULL; }
3 界面完成
上面我们已经实现了通讯录的大部分功能,还有一些额外功能没有加入,比如读取文件数据,储存到文件等。
下面我们开始完善界面内容,来把通讯录的功能进行整合。
3.1 打印菜单
这个容易实现,按照喜好设置即可,下面给予参考
void menu() { printf("*************************************\n"); printf("********* 通讯录 **********\n"); printf("**** 1.添加联系人 2.删除联系人 *****\n"); printf("**** 3.修改联系人 4.查找联系人 *****\n"); printf("**** 5.查看通讯录 0.退出通讯录 *****\n"); }
效果如图
3.2 完成功能选择
通过switch语句我们可以方便的完成功能选择
int main() { int op = -1; contact con; InitContact(&con); do { menu(); printf("请选择你的操作:> \n"); scanf("%d",&op); switch (op) { case 1: AddContact(&con); break; case 2: DelContact(&con); break; case 3: ModifyContact(&con); break; case 4: FindContact(&con); break; case 5: ShowContact(&con); break; case 0: printf("goodbye~\n"); break; default: printf("输入格式有误,重新输入:> \n"); break; } } while (op != 0); DestroyContact(&con); return 0; }
这样我们就完成了功能选择,都是有一点点瑕疵。
3.3 界面优化
通过上面的菜单我们在进行几步操作后便会发现
界面非常冗杂混乱,如何解决呢。
我们可以通过
system("pause"); system("cls");
这两行简单的代码便可以大大优化界面
int main() { int op = -1; contact con; InitContact(&con); do { menu(); printf("请选择你的操作:> \n"); scanf("%d",&op); switch (op) { case 1: AddContact(&con); system("pause"); system("cls"); break; case 2: DelContact(&con); system("pause"); system("cls"); break; case 3: ModifyContact(&con); system("pause"); system("cls"); break; case 4: FindContact(&con); system("pause"); system("cls"); break; case 5: ShowContact(&con); system("pause"); system("cls"); break; case 0: printf("goodbye~\n"); system("pause"); system("cls"); break; default: printf("输入格式有误,重新输入:> \n"); system("pause"); system("cls"); break; } } while (op != 0); DestroyContact(&con); return 0; }
让我们看看效果
无论进行多少操作,我们的界面依然清爽。
结语
通讯录项目我们实现了大部分内容,接下来你可以自行探索,丰富功能。
谢谢你的阅读
祝您前程似锦