目录
一.前言
二.准备工作
三.ContactTest.c测试区
1.菜单
2.选择功能
四.Contact.h头文件引用区
1.通讯录成员结构体函数的创建
2.实现功能函数的创建
五.ContactRealize.c功能实现区
1.初始化成员信息
2.查找目标成员位置
3.增加联系人
4.删除指定联系人
5.查找指定联系人
6.修改指定联系人
7.浏览所有联系人
8.清空所有联系人
9.排序所有联系人
六.源码
1.ContactTest.c源码
2.Contact.h源码
3.ContactRealize.c源码
一.前言
本文讲通过c语言实现通讯录的功能,具体功能为1.添加、2.删除、3.查找、4.修改、5.浏览、6.清空、7.排序以及最后的0.退出通讯录功能。
二.准备工作
区域化编辑:
实现简单的通讯录可以分配为三大块,第一块为测试区,第二块为头文件引用区,第三块最重要,为调用实现通讯录功能函数的实现区块,我们将其分别命名为ContactTest.c,Contact.h和ContactRealize.c。
三.ContactTest.c测试区
1.菜单
以使用者的角度来看,需要了解到有哪些功能,那么我们就需要提供一个简洁明了的菜单功能,以便使用者使用相应的功能,参考菜单可如下:
void menu(){printf("*******************************\n");printf("****** 通讯录******\n");printf("******1.添加 2.删除******\n");printf("******3.查找 4.修改******\n");printf("******5.阅览 6.清空******\n");printf("******7.排序 0.退出******\n");printf("*******************************\n");}
效果如下:
2.选择功能
这里我们使用switch函数来实现功能的选择,又因为会有重复的使用,因此可以使用do_while函数来实现循环,主函数我们可以这样设计:
int main(){int s;Contact con;InitContact(&con);do{menu();scanf("%d", &s);switch (s){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:SearchContact(&con);break;case 4:ModifyContact(&con);break;case 5:ReadContact(&con);break;case 6:EmptyContact(&con);break;case 7:SortContact(&con);break;case 0:printf("已成功退出!\n");break;default:printf("请输入正确的选项!\n");}} while (s);return 0;}
此时我们就已经将退出的功能完成啦!而这里各个函数的调用以及结构体的创建还没有实现,我们将在后文详细说明。
四.Contact.h头文件引用区
1.通讯录成员结构体函数的创建
每个通讯录成员都有着一定的信息,又相互关联,使用结构体保存这一系列数据相对要方便很多;而通讯录成员并不是一个,所以我们需要一个结构体数组,同时还要了解到当前通讯录成员的数量,以此来实现通讯录的各项功能,具体结构体实现如下:
#define MAX 1000#define NAME_MAX 20#define SEX_MAX 5#define ADDR_MAX 30#define TELE_MAX 12//个体成员信息typedef struct ContactMember{char Name[NAME_MAX];char Sex[SEX_MAX];int Age;char Number[TELE_MAX];char Address[ADDR_MAX];}ContactMember;//所有成员信息typedef struct Contact{ContactMember ContactMembers[MAX];int sz;}Contact;
这里定义各个成员信息具体内容的大小是为了方便修改,以达到简洁方便的目的。
2.实现功能函数的创建
因为要用到具体通讯录成员的信息和当前成员数量的信息,我们可以把Contact*类型的函数传递进功能函数,具体函数如下:
//初始化通讯录void InitContact(Contact* con);//增加联系人void AddContact(Contact* con);//删除指定联系人void DelContact(Contact* con);//查找指定联系人void SearchContact(Contact* con);//修改指定联系人void ModifyContact(Contact* con);//查看所有联系人void ReadContact(Contact* con);//清空所有联系人void EmptyContact(Contact* con);//排序所有联系人void SortContact(Contact* con);
设置返回值为空,因为不需要返回值,只要实现相应功能就行了;同时,传递结构体指针是为了提高内存的性能,如果使用的Contact类型的函数,那么将又要为结构体数组开辟出一大块空间来实现函数,大量挤占内存,不是明智之举。
五.ContactRealize.c功能实现区
1.初始化成员信息
因为创建的Contact函数并没有初始化,因此先将其初始化将是一份安全保险,养成良好习惯,从你我做起。
//初始化成员信息void InitContact(Contact* con){con->sz = 0;//初始化下标memset(con, 0, sizeof(con));//初始化所有成员}
这里成员数量还是好初始化的,而成员结构体数组可以用memset函数来帮助我们实现初始化。
2.查找目标成员位置
具体功能中虽然没有该函数的使用,但该函数频繁出现在部分功能函数实现的内容中,在此单独写出来可以防止码重复代码,节约时间成本。
//查找目标成员位置int FindName(Contact* con, char* name){for (int i = 0; i sz; i++){if (strcmp(con->ContactMembers[i].Name, name) == 0){return i;}}return -1;}
这里我们使用姓名来查找目标成员,将目标成员的姓名通过遍历和strcmp函数与各个成员信息比对从来找到目标成员的下标(位置)。
3.增加联系人
增加成员,需要将姓名、性别等信息录入相应位置的结构体,同时sz可以充当当前位置和数量的值,添加成功后联系人成员+1,但要防止超出存储上限的情况,可以在添加联系人之前做出判断来防止此类情况的发生。
//增加联系人void AddContact(Contact* con){assert(con);if (con->sz == MAX){printf("通讯录已满!\n");return;}//增加printf("请输入姓名:");scanf("%s", con->ContactMembers[con->sz].Name);printf("请输入性别:");scanf("%s", con->ContactMembers[con->sz].Sex);printf("请输入年龄:");scanf("%d", &con->ContactMembers[con->sz].Age);printf("请输入住址:");scanf("%s", con->ContactMembers[con->sz].Address);printf("请输入号码:");scanf("%s", con->ContactMembers[con->sz].Number);printf("输入完毕!\n");con->sz++;}
效果如下:
4.删除指定联系人
删除目标成员,首先就要先找到目标成员,此时先前写到的查找目标函数就可以直接调用啦!我们可以调用memmove来实现函数的删除,将删除目标的后面的成员全都向前移动一位,将目标成员的信息覆盖掉,便可以达到删除的效果啦!同时,还要小心没有可以删除目标的情况,在删除前先判断排除该情况。
//删除指定联系人void DelContact(Contact* con){assert(con);if (con->sz == 0){printf("没有可以删除的目标!\n");return;}//查找printf("请输入目标删除人:");char name[NAME_MAX];scanf("%s", name);int ret = FindName(con, name);if (ret == -1){printf("目标人物不存在!\n");return;}//删除memmove(con->ContactMembers + ret, con->ContactMembers + ret + 1, sizeof(con->ContactMembers[0]) * (con->sz - ret - 1));printf("删除成功!\n");con->sz--;}
5.查找指定联系人
此处又用到了查找目标联系人的函数,直接调用后打印即可。
//查找指定联系人void SearchContact(Contact* con) {assert(con);//查找char name[NAME_MAX];printf("请输入要查询的人:");scanf("%s", name);int ret = FindName(con, name);if (ret == -1){printf("查询目标不存在!\n");return;}//显示printf("%-20s\t%-5s\t%s\t%-30s\t%-12s\n", "姓名", "性别", "年龄", "地址", "号码");printf("%-20s\t%-5s\t%d\t%-30s\t%-12s\n", con->ContactMembers[ret].Name,con->ContactMembers[ret].Sex,con->ContactMembers[ret].Age,con->ContactMembers[ret].Address,con->ContactMembers[ret].Number);}
值得注意的是直接打印出来未免太过生硬,所以这里添加了姓名等标签在上一行来标志清楚,同时采用左对齐的方式,清晰美观。模拟实现如下:
6.修改指定联系人
这个函数于查找函数有着异曲同工之妙,只需要将打印目标成员信息的步骤改为输入即可。
//修改指定联系人void ModifyContact(Contact* con){assert(con);//查找char name[NAME_MAX];printf("请输入要修改目标的姓名:");scanf("%s", name);int ret = FindName(con, name);if (ret == -1){printf("修改目标不存在!\n");return;}//修改printf("请输入要修改的姓名:");scanf("%s", con->ContactMembers[ret].Name);printf("请输入要修改的性别:");scanf("%s", con->ContactMembers[ret].Sex);printf("请输入要修改的年龄:");scanf("%d", &con->ContactMembers[ret].Age);printf("请输入要修改的地址:");scanf("%s", con->ContactMembers[ret].Address);printf("请输入要修改的号码:");scanf("%s", con->ContactMembers[ret].Number);printf("修改完毕!\n");}
效果如下:
7.浏览所有联系人
该函数也类似于查找函数,不过不需要输入,直接遍历每个成员的每个信息并打印出来就达成目的啦。
//浏览所有联系人void ReadContact(Contact* con){assert(con);//浏览printf("%-20s\t%-5s\t%s\t%-30s\t%-12s\n", "姓名", "性别", "年龄", "地址", "号码");for (int i = 0; i sz; i++){printf("%-20s\t%-5s\t%d\t%-30s\t%-12s\n", con->ContactMembers[i].Name,con->ContactMembers[i].Sex,con->ContactMembers[i].Age,con->ContactMembers[i].Address,con->ContactMembers[i].Number);}}
效果如下:
8.清空所有联系人
这里我们可以悄悄偷个懒…其实并不是,我们可以使用先前写好了的初始化通讯录的函数,直接调用就可以啦!
//清空所有联系人void EmptyContact(Contact* con){assert(con);InitContact(con);printf("重置成功!\n");}
效果如下:
9.排序所有联系人
排序我们可以通过qsort函数来实现,将所有成员的数组名传递过去,即第一个成员结构体的地址,排序con->sz(成员数)次,每个元素大小为一个成员结构体的大小,而排序函数我们则通过比较两个结构体成员内容的大小即可,使用memcmp函数来实现对相同结构体内容的比较。
//排序函数int Sort(const void* a, const void* b){ContactMember* A = (ContactMember*)a;ContactMember* B = (ContactMember*)b;return memcmp(B, A, sizeof(ContactMember));}//排序所有联系人void SortContact(Contact* con){assert(con);//排序qsort(con->ContactMembers, con->sz, sizeof(con->ContactMembers[0]), Sort);printf("排序完毕!\n");}
具体效果如下:
六.源码
最后把源码分享出来,方便各位学习与交流。
1.ContactTest.c源码
#include "Contact.h"void menu(){printf("*******************************\n");printf("****** 通讯录******\n");printf("******1.添加 2.删除******\n");printf("******3.查找 4.修改******\n");printf("******5.阅览 6.清空******\n");printf("******7.排序 0.退出******\n");printf("*******************************\n");}int main(){int s;Contact con;InitContact(&con);do{menu();scanf("%d", &s);switch (s){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:SearchContact(&con);break;case 4:ModifyContact(&con);break;case 5:ReadContact(&con);break;case 6:EmptyContact(&con);break;case 7:SortContact(&con);break;case 0:printf("已成功退出!\n");break;default:printf("请输入正确的选项!\n");}} while (s);return 0;}
2.Contact.h源码
#pragma once#include #include #include #include #define MAX 1000#define NAME_MAX 20#define SEX_MAX 5#define ADDR_MAX 30#define TELE_MAX 12//成员信息typedef struct ContactMember{char Name[NAME_MAX];char Sex[SEX_MAX];int Age;char Number[TELE_MAX];char Address[ADDR_MAX];}ContactMember;typedef struct Contact{ContactMember ContactMembers[MAX];int sz;}Contact;//初始化通讯录void InitContact(Contact* con);//增加联系人void AddContact(Contact* con);//删除指定联系人void DelContact(Contact* con);//查找指定联系人void SearchContact(Contact* con);//修改指定联系人void ModifyContact(Contact* con);//查看所有联系人void ReadContact(Contact* con);//清空所有联系人void EmptyContact(Contact* con);//排序所有联系人void SortContact(Contact* con);
3.ContactRealize.c源码
#include "Contact.h"//初始化成员信息void InitContact(Contact* con){con->sz = 0;memset(con, 0, sizeof(con));}//查找目标成员位置int FindName(Contact* con, char* name){for (int i = 0; i sz; i++){if (strcmp(con->ContactMembers[i].Name, name) == 0){return i;}}return -1;}//大小排序(qsort实现)int Sort(const void* a, const void* b){ContactMember* A = (ContactMember*)a;ContactMember* B = (ContactMember*)b;return memcmp(B, A, sizeof(ContactMember));}void AddContact(Contact* con){assert(con);if (con->sz == MAX){printf("通讯录已满!\n");return;}printf("请输入姓名:");scanf("%s", con->ContactMembers[con->sz].Name);printf("请输入性别:");scanf("%s", con->ContactMembers[con->sz].Sex);printf("请输入年龄:");scanf("%d", &con->ContactMembers[con->sz].Age);printf("请输入住址:");scanf("%s", con->ContactMembers[con->sz].Address);printf("请输入号码:");scanf("%s", con->ContactMembers[con->sz].Number);printf("输入完毕!\n");con->sz++;}void DelContact(Contact* con){assert(con);if (con->sz == 0){printf("没有可以删除的目标!\n");return;}printf("请输入目标删除人:");char name[NAME_MAX];scanf("%s", name);int ret = FindName(con, name);if (ret == -1){printf("目标人物不存在!\n");return;}memmove(con->ContactMembers + ret, con->ContactMembers + ret + 1, sizeof(con->ContactMembers[0]) * (con->sz - ret - 1));printf("删除成功!\n");con->sz--;}void SearchContact(Contact* con) {assert(con);char name[NAME_MAX];printf("请输入要查询的人:");scanf("%s", name);int ret = FindName(con, name);if (ret == -1){printf("查询目标不存在!\n");return;}printf("%-20s\t%-5s\t%s\t%-30s\t%-12s\n", "姓名", "性别", "年龄", "地址", "号码");printf("%-20s\t%-5s\t%d\t%-30s\t%-12s\n", con->ContactMembers[ret].Name,con->ContactMembers[ret].Sex,con->ContactMembers[ret].Age,con->ContactMembers[ret].Address,con->ContactMembers[ret].Number);}void ModifyContact(Contact* con){assert(con);char name[NAME_MAX];printf("请输入要修改目标的姓名:");scanf("%s", name);int ret = FindName(con, name);if (ret == -1){printf("修改目标不存在!\n");return;}printf("请输入要修改的姓名:");scanf("%s", con->ContactMembers[ret].Name);printf("请输入要修改的性别:");scanf("%s", con->ContactMembers[ret].Sex);printf("请输入要修改的年龄:");scanf("%d", &con->ContactMembers[ret].Age);printf("请输入要修改的地址:");scanf("%s", con->ContactMembers[ret].Address);printf("请输入要修改的号码:");scanf("%s", con->ContactMembers[ret].Number);printf("修改完毕!\n");}void ReadContact(Contact* con){assert(con);printf("%-20s\t%-5s\t%s\t%-30s\t%-12s\n", "姓名", "性别", "年龄", "地址", "号码");for (int i = 0; i sz; i++){printf("%-20s\t%-5s\t%d\t%-30s\t%-12s\n", con->ContactMembers[i].Name,con->ContactMembers[i].Sex,con->ContactMembers[i].Age,con->ContactMembers[i].Address,con->ContactMembers[i].Number);}}void EmptyContact(Contact* con){assert(con);InitContact(con);printf("重置成功!\n");}void SortContact(Contact* con){assert(con);qsort(con->ContactMembers, con->sz, sizeof(con->ContactMembers[0]), Sort);printf("排序完毕!\n");}