简单易上手的通讯录实现,跟着敲,你也能拥有属于你的通讯录!(代码 笔记已经上传至gitee)
通讯录
老规矩笔记和代码欢迎自取~
链接:
- 通讯录笔记
- 通讯录工程文件+源代码
文章目录
一、通讯录的组成
利用最近所学的知识,试着实现一个通讯录
手机里面的通讯录信息
最后我决定给通讯录增加以下信息
二、通讯录文件构成
为什么每一篇小项目都强调一遍文件构成?
1. test.c
按照之前的设计小游戏一样,test.c文件是必要的,用来测试各种功能使用是否可以正常使用或者运行
还包括整个通讯录的框架,比如提供给使用者得选择菜单
2. correspondence.c
用来设计实现通讯录功能的文件,文件包含的基本上都是函数
函数包括实现增加/删除/修改/查找/打印/排序联系人
3. correspondence.h
包含 test.c 和 correspondence.c 中需要用到的库函数的头文件,以及全过程需要使用的变量
三、实现的代码步骤分析
1. 打印菜单
使用者上手即操作,我们需要提供给他们操作的菜单,也是我们功能的目录
菜单明细上面也分析了,主要包含:
void menu()//菜单
{printf("==============通讯录=============n");printf(" 1.添加联系人(add) n");printf(" 2.查找联系人(seek) n");printf(" 3.删除联系人(delete) n");printf(" 4.修改联系人(modify) n");printf(" 5.排序联系人(sort) n");printf(" 6.打印联系人(print) n");printf(" 0.退出通讯录(EXIT) n");}
利用最近所学的枚举类型,我们试着这次的循环内的switch语句,判断不选择数字,而选择判断功能的内容
所以我们定义一个枚举类型,用单词代表各个功能
此过程在 test.c 文件中
enum menu
{EXIT,//0add,//1seek,//2delete,//3modify,//4sort,//5print//6
};
把exit放前面正好代表0,每个枚举常量代表的数字都是对应的功能
到此为止,整个循环的大概模型是这样,代码如下
此过程在 test.c 文件中
int main()
{int input = 0;do{menu();//打印菜单提供使用者选择printf("请选择您要使用的功能(输入选项括号内内容):");scanf("%d", &input);//使用者输入选择switch (input){case add:break;case seek:break;case delete:break;case modify:break;case sort:break;case print:break;case exit:printf("您选择了退出通讯录n");break;default:printf("输入错误信息,请重新输入:n");break;}} while (input != 0);return 0;
}
运行的结果
分别测试了 正确信息 错误信息 退出功能
2. 联系人信息初始化
刚拿到新手机的大家,通讯录里面是没有联系人的信息
但可以通过自己填写联系人信息存储到手机中
我们需要提供给使用者,接收/存储信息的一个数据库
但因为人的信息是复杂的,是多种元素构成
信息包括:姓名 + 性别 + 年龄 + 电话 + 公司地址
使用类型:char char int int char
此过程在 correspondence.h 文件中
#define NAME_MAX 11
#define GENDER_MAX 5
#define TELE_MAX 12
#define EMAIL_MAX 20//通讯录初始化个人信息
struct perinfmt //personal information
{char name[NAME_MAX];//支持5个汉字(2个字节一个汉字)char gender[GENDER_MAX];//男性 or 女性int age;char tele[TELE_MAX];//11位电话号码char email[EMAIL_MAX];//19位邮箱
};
为了不用每次挨个修改个人信息的大小,我们用define定义每个信息的最大值
还没有结束,我们创建好的是每个人的信息填写位置,但还没有创建一个通讯录,有100个人,每个人还需要标记序号(这里序号不放在个人信息里是因为,创建联系人的时候不会去填每个人的信息),这是需要我们系统内部自己去偷偷记录的
此时100个人 + 序号 通讯录仍然是复杂信息 我们再次创建结构体变量
此过程在 correspondence.h 文件中
struct address_book //通讯录内容
{struct perinfmt p[BOOK_MAX];//每个人信息,数组一共100个人int ID;//统计每个人编号
};
创建通讯录的结构体变量时,我们仍然还没有初始化
新建一个函数,专门初始化它
此过程在 correspondence.c 文件中
void Initialize(struct address_book* ap)
{ap->ID = 0;//序号初始值0memset(ap->p, 0, sizeof(ap->p));//初始化整个结构体数组大小为0}
记得在 correspondence.h 中声明
我们才能在 test.c 上使用 (记得在进入循环前就初始化好)
struct address_book alinfmt;//all information
Initialize(&alinfmt);//初始化通讯录
PS:但其实也可以不创建这个 函数初始化
(我们是为了方便,这样每次都可以,直接用函数初始化)
可以在创建变量的时候直接初始化
struct address_book alinfmt = { { 0 }, 0 };//all information
此过程在 test.c 中完成
3. 添加联系人
功能的铺垫已经写好了
我们开始写主要的功能
添加联系人函数
//增加联系人
void add_contact(struct address_book* ap)
{if (ap->ID == BOOK_MAX){printf("通讯录满了,请删除一些联系人再添加!n");}else{printf("请输入联系人姓名:");scanf("%s", ap->p[ap->ID].name);printf("请输入联系人性别:");scanf("%s", ap->p[ap->ID].gender);printf("请输入联系人年龄:");scanf("%d", &(ap->p[ap->ID].age));//这里是因为age是int类型变量需要传地址,其他数组类型变量名就是地址printf("请输入联系人电话:");scanf("%s", ap->p[ap->ID].tele);printf("请输入联系人邮箱地址:");scanf("%s", ap->p[ap->ID].email);printf("-----添加完成-----n");ap->ID++;}
}
scanf里面一大串都是什么?
图解
还有写这段代码时候必须包含等号,不能只写大于号
if (ap->ID == BOOK_MAX){printf("通讯录满了,请删除一些联系人再添加!n");}
不然会警告
最后别忘了填写完一个人的信息的时候,记录的ID需要增加
4. 打印联系人
既然已经完成了添加联系人,那么我们就不按顺序,看看如何打印我们所有联系人的成员吧
打印联系人函数
直接用一个for循环搞定~
//显示所有联系人
void print_book(struct address_book* ap)
{int i = 0;for (i = 0; i < ap->ID; i++){printf("联系人姓名:%sn性别:%sn年龄:%dn电话:%sn邮箱地址:%sn", ap->p[i].name, ap->p[i].gender, ap->p[i].age,ap->p[i].tele,ap->p[i].email);}
}
搭配添加联系人食用~,结果如下图:
5. 删除联系人
我们发现,删除/查找/修改 联系人功能中,都会包含有 查找联系人这个动作
用for循环遍历一遍,查找是否有这个联系人
//查找联系人
int find_contact(const struct address_book* ap, const char* name)
{int i = 0;for (i = 0; i < ap->ID; i++){if (strcmp(ap->p[i].name, name) == 0){return 1;}}return -1;
}
找到了之后图解:
//删除联系人
void del_contact(struct address_book* ap)
{if (ap->ID == 0)//判断通讯录是否为空{printf("无可删除联系人");return;}char name[NAME_MAX] = { 0 };//存放查找的姓名printf("请输入删除的联系人姓名:");scanf("%s", name);int ret = find_contact(ap, name);if (ret == -1){printf("该联系人不存在");}else{//删除联系人int j = 0;for (j = ret; j < ap->ID - 1; j++){ap->p[j] = ap->p[j + 1];}ap->ID--;//少了一个数字printf("删除成功!n");}}
代码运行效果:
我的舍友就这样成功被我删除了哈哈哈哈
6. 查找指定联系人
这个代码有了上面几个代码的铺垫,直接复制粘贴修改一些变量就可以!
看看代码是不是有点熟悉,copy就完事了
//查找指定联系人
void seek_contact(const struct address_book* ap)//我们只是查找不作修改
{char name[NAME_MAX];printf("请输入需要查找的联系人姓名:");scanf("%s", &name);int ret = find_contact(ap, name);if (ret == -1){printf("该联系人不存在");}else{printf("找到了!n联系人姓名:%sn性别:%sn年龄:%dn电话:%sn邮箱地址:%snn",ap->p[ret].name,ap->p[ret].gender,ap->p[ret].age,ap->p[ret].tele,ap->p[ret].email);}
}
运行效果:
7. 修改联系人
同理,也是copy + 稍微修改一下就完事了
//修改联系人
void modify_contact(struct address_book* ap)
{char name[NAME_MAX];printf("请输入需要查找的联系人姓名:");scanf("%s", &name);int ret = find_contact(ap, name);if (ret == -1){printf("该联系人不存在");}else{printf("开始修改联系人信息!n");printf("请重新输入联系人姓名:");scanf("%s", ap->p[ret].name);printf("请重新输入联系人性别:");scanf("%s", ap->p[ret].gender);printf("请重新输入联系人年龄:");scanf("%d", &(ap->p[ret].age));printf("请重新输入联系人电话:");scanf("%s", ap->p[ret].tele);printf("请重新输入联系人邮箱地址:");scanf("%s", ap->p[ret].email);printf("-----修改完成-----n");}}
运行效果:
8. 排序联系人
我们用qsort快排进行联系人的姓名排序
int compare(const void* e1, const void* e2)
{return (strcmp((const char*)e1, (const char*)e2));
}//排序联系人
void sort_contact(struct address_book* ap)
{qsort(ap->p->name, ap->ID, sizeof(ap->p[0]), compare);printf("排序完成,请选择显示所有联系人进行查看!n");}
然后,我将前面的exit改成了大写
因为出现了问题!!!
在stdlib.h文件的存在情况下,exit是已经被使用的
而我再使用,与库函数冲突,会报错!!
在发现了原因的情况下,修改之后
效果如下:
标签:
相关文章
-
无相关信息