通讯录的实现

  • 前言
  • 1.通讯录实现的构思
    • 1.1菜单的实现
    • 1.2菜单功能的设计
    • 1.3成员结构体设计
    • 1.4全局变量和相关的头文件
  • 2.通讯录功能的实现
    • 2.1结构体成员初始化
    • 2.2成员的增添
    • 2.3成员的展示
    • 2.4成员的查找
    • 3.5成员的修改
    • 3.6成员的删除
    • 3.7成员的排序(按照年龄排序)
  • 3.整体代码展示

前言

本次通讯录的实现主要涉及的知识点是:结构体,枚举,函数设计等知识点,其中结构体和枚举是本次的主要知识点,可以这么说本章节是对前两期博客的一个知识总结( C语言结构体讲解和 枚举类型的使用),也可以说是将知识运用到实际生活当中,好了长话短说,我们进入今天的主题。

在实现一个通讯录的时候,我们都要先构思出它的框架,它的成员信息有什么,以及这个通讯录要实现的功能是什么,等等。我们知道一个人的基本信息包括:名字,年龄,性别,电话,住址。而这个通讯录的基本功能包括:1.成员的增加,2.成员的展示,3.成员的查找,4.成员的修改,5.成员的删除,6.成员的排序。现在我们来一步一步实现。

1.通讯录实现的构思

1.1菜单的实现

我们要设计出一个通讯录,这个通讯录是给用户使用的,那既然是给用户使用的你总得让用户知道你设计出来的通讯录有什么功能把,所以设计出一个菜单,菜单里面包含了全部的功能是比较关键的一步的。
代码如下:

void menu()
{printf("**************** Menu *****************\n");printf("*****  1.add            2.show    *****\n");printf("*****  3.search         4.modify  *****\n");printf("*****  5.del            6.sort    *****\n");printf("*****  0.exit                     *****\n");printf("***************************************\n");
}

展示效果:

这样我们的一个菜单就设计好了。

1.2菜单功能的设计

我们有了菜单就要实现这些菜单上的功能,而实现这些功能的时候就是输入菜单上功能前面的数子,那我们就会想到用switch语句加上do while语句,来进行功能的选择。但是我们为了增加代码的可读性,我们一般还会用到enum枚举类型来增加代码的可读性。

enum
{exi,//0add,//1show,//2search,//3modify,//4del,//5sort//6
};
int main()
{int input = 0;//创建通讯录struct contact con;//con包含了1000个通信录信息,和size//初始化通讯录Initcontact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case add:Addcontact(&con);//1break;case show:Showcontact(&con);//2break;case search:Searchcontact(&con);//3break;case modify:Modifycontact(&con);//4break;case del:Delcontact(&con);//5break;case sort:Sortcontact(&con);//6break;case 0:printf("退出通讯录\n");break;default:printf("输入错误,重新输入\n");break;}} while (input);return 0;
}

1.3成员结构体设计

我们要输入成员的信息,就要用到结构体,将需要的成员的信息定义在结构体当中,在输出的时候就会很方便,但是我们要知道的的是,我们添加成员肯定不止是添加一个成员的,所以还要用到结构体数组,这要就可以存放多个成员了。
具体看以下代码:

struct peoinfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
};
//定义一个通讯录类型,里面存放通讯录信息和记录有多少个信息
struct contact
{struct peoinfo date[MAX];//定义一个结构体数组,里面可以存放MAX个成员。int size;//记录当前信息个数
};

这里需要解释的就是,我们将一个成员结构体定义在了另一个结构体当中,并且在此结构体当中定义了结构体数组,同时还定义了size变量。这里解释一下,我们设计出这个通讯录是给用户用的,但是我们不知道用户会添加多少个成员,所以我们就得定义一个变量来记录添加了多少个成员,而这个变量就是size。于是当我们传参的时候就得把成员结构体和size传过去Addcontact(&con,sizr);,其他的也是如此,而没个功能都是要传这两个参数的,这就显得有点麻烦了,既然这两个参数是同时传过去的,那我们我们就把他们两个放在一起,到时候传参的时候就只要传一个参数即可,这样就简化了代码。

1.4全局变量和相关的头文件

最后就是我们要用到的全局变量和所用到的头文件:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define MAX 1000 //最多可以放下1000个成员
#define MAX_NAME 20 //名字的最大长度是20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDR 20

至此,一个通讯录的基本框架就算是完成了,接下来就是逐个的实现通讯录的功能了。

2.通讯录功能的实现

2.1结构体成员初始化

我们定义了结构体数组,但是没有进行初始化,此时结构体数组里面存放的就是随机值,这避免不了在后续的程序中会出现一些问题,所以这里我们就将所有的成员初始化为0,size也初始化为0,这里就要用到字符串函数memset内存设置函数的头文件<string.h>。

void Initcontact(struct contact* ps)
{assert(ps!=NULL);memset(ps->date, 0, sizeof(ps->date));ps->size = 0;//设置通讯录最初是0
}

2.2成员的增添

添加成员的时候我们要考虑以下几点:1:成员添加的数量是否超过了给点数组的大小,2:成员添加了多要个。这两点都会影响后续的进行。而成员添加的的多少由size记录,我们知道数组的下标是从0开始的,我们第一个成员添加到下标为0出的数组里面,那如果我们还想添加成员,那接下来就要添加到下标为1出的数组,所以我们在每添加一个成员的时候size都要++。

void Addcontact(struct contact* ps)
{assert(ps!=NULL);if (ps->size == MAX){printf("通讯录已满,无法增加\n");}else{printf("请输入名字;>");scanf("%s", ps->date[ps->size].name);printf("请输入年龄;>");scanf("%d", &(ps->date[ps->size].age));printf("请输入性别;>");scanf("%s", ps->date[ps->size].sex);printf("请输入电话;>");scanf("%s", ps->date[ps->size].tele);printf("请输入地址;>");scanf("%s", ps->date[ps->size].addr);ps->size++;}
}

展示效果:

2.3成员的展示

上面我们知道了用户添加了都少个成员,即size个成员,有了个数我们就可以很好的将其打印出来,即用一个for循环即可:

void Showcontact(const struct contact* ps)//查找成员是不修改参数的,所以这里可以用const修饰
{assert(ps!=NULL);if (ps->size == 0)//没有添加成员的时候或者成员都被删除了{printf("通讯录为空\n");}else{printf("%-20s\t%-4s\t%-4s\t%-12s\t%-10s\n", "名字", "年龄", "性别", "电话", "住址");int i = 0;for (i = 0; i < ps->size; i++){printf(" %-20s\t%-4d\t%-4s\t%-12s\t%-10s\n",ps->date[i].name,ps->date[i].age,ps->date[i].sex,ps->date[i].tele,ps->date[i].addr);}}
}

展示效果:

2.4成员的查找

查找成员的时候我们一般用的方法是直接用一个for循环,然后一一遍历数组,方法如下:

Searchcontact(&con);
{assert(ps!=NULL);char names[MAX_NAME];scanf("%s", names);int i = 0;for (i = 0; i < ps->size; i++){if (strcmp(ps->date[i].name, names) == 0){//查到了此人,再将其打印出来。}else{printf("没有此人");}}
}

但是我们会发现,在后面的成员修改和成员删除,都是要先查找出有这个成员了再进行修改和删除,那如果是上面这样的写法的话,那每个功能函数都要添加这段代码,那代码就重复累赘了,所以我们就想到了用一个函数find将其分装好来,要用的时候就调用这个函数。

int find(const struct contact* ps)
{assert(ps!=NULL);char names[MAX_NAME];scanf("%s", names);int i = 0;//寻找到要查找的人for (i = 0; i < ps->size; i++){if (strcmp(ps->date[i].name, names) == 0){return i;//找到返回下标}}return -1;//没有此人返回-1
}
void Searchcontact(const struct contact* ps)
{assert(ps!=NULL);char names[MAX_NAME];if (ps->size == 0){printf("通讯录为空,无法查询\n");}printf("请输入查询的名字:>");int ret = find(ps);if (ret!=-1){printf("%-20s\t%-4s\t%-4s\t%-12s\t%-10s\n", "名字", "年龄", "性别", "电话", "住址");printf(" %-20s\t%-4d\t%-4s\t%-12s\t%-10s\n",ps->date[ret].name,ps->date[ret].age,ps->date[ret].sex,ps->date[ret].tele,ps->date[ret].addr);}else{printf("没有此人\n");}
}

展示效果:

3.5成员的修改

到这里成员的修改就会比较方便,就是再查找到成员的时候进行修改就可以了。

void Modifycontact(struct contact* ps)
{assert(ps!=NULL);printf("请输入要修改人的名字:>");//查找要修改人的为位置int ret=find(ps);if (ret != -1){printf("修改后的名字;>");scanf("%s", ps->date[ret].name);printf("修改后的年龄;>");scanf("%d", &(ps->date[ret].age));printf("修改后的性别;>");scanf("%s", ps->date[ret].sex);printf("修改后的电话;>");scanf("%s", ps->date[ret].tele);printf("修改后的地址;>");scanf("%s", ps->date[ret].addr);printf("修改后的通讯录\n");//打印修改后的通讯录Showcontact(ps);}else{printf("要修改的人不存在\n"); }
}

展示效果:

3.6成员的删除

删除成员的话第一步也是先查找出有这个人,然后就是进行删除。关键是怎么实现删除这个功能。我们使用数组存放着成员的信息,如果说直接将要删除的人从数组中去掉,那显然是不可能的,因为如果是直接去掉的话那这个存放成员的内容就是空的,那后面要展示成员的时候就会把这个空的数组展示出来,这就不符合我们要的需求。我们既要函数这个成员还好不影响数组的遍历,所以我们就可以使用平移法,就是就是将要删除的那个成员的后面的成员全部向前平移一个单位,同时我们的成员也少了一个,size要–;

void Delcontact(struct contact* ps)
{assert(ps!=NULL);printf("请输入要删除人的名字:>");//查找要删除人的位置int ret = find(ps);//删除if (ret != -1){int i = 0;for (i = ret; i < ps->size-1; i++){ps->date[i] = ps->date[i + 1];}ps->size--;printf("删除成功\n");printf("删除后的通讯录\n");Showcontact(ps);}else{printf("要删除的人不存在\n");}
}

展示效果:

3.7成员的排序(按照年龄排序)

最后就到了排序阶段了,这里我们是按照年龄来进行排序的,这里就是直接使用冒泡排序就行了。

void Sortcontact(struct contact* ps)
{assert(ps!=NULL);int i = 0;//冒泡排序for (i = 0; i < ps->size - 1; i++){int j = 0;for (j = 0; j < ps->size - 1 - i; j++){if (ps->date[j].age > ps->date[j+1].age){struct peoinfo  tmp = ps->date[j];//要创建相同类型的ps->date[j] = ps->date[j + 1];ps->date[j + 1] = tmp;}}}printf("排序成功\n");printf("排序后的通讯录\n");//打印排序后的通讯录Showcontact(ps);
}

展示效果:

这样我们的通讯录功能就全部设计完了。

3.整体代码展示

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDR 20
struct peoinfo
{char name[MAX_NAME];int age;char sex[MAX_SEX];char tele[MAX_TELE];char addr[MAX_ADDR];
};
//定义一个通讯录类型,里面存放通讯录信息和记录多少个信息
struct contact
{struct peoinfo date[MAX];int size;//记录当前信息个数
};
enum
{exi,//0add,//1show,//2search,//3modify,//4del,//5sort//6
};//函数的声明//初始化通讯录
void Initcontact(struct contact* ps);
//增加通讯录
void Addcontact(struct contact* ps);
//展示通讯录
void Showcontact(const struct contact* ps);
//查找通讯录
void Searchcontact(const struct contact* ps);
//修改通讯录
void Modifycontact(struct contact* ps);
//删除通讯录
void Delcontact(struct contact* ps);
//通讯录排序(按照年龄排序)
void Sortcontact(struct contact* ps);//函数的实现
void Initcontact(struct contact* ps)
{assert(ps!=NULL);memset(ps->date, 0, sizeof(ps->date));ps->size = 0;//设置通讯录最初是0
}
void Addcontact(struct contact* ps)
{assert(ps!=NULL);if (ps->size == MAX){printf("通讯录已满,无法增加\n");}else{printf("请输入名字;>");scanf("%s", ps->date[ps->size].name);printf("请输入年龄;>");scanf("%d", &(ps->date[ps->size].age));printf("请输入性别;>");scanf("%s", ps->date[ps->size].sex);printf("请输入电话;>");scanf("%s", ps->date[ps->size].tele);printf("请输入地址;>");scanf("%s", ps->date[ps->size].addr);ps->size++;}
}
void Showcontact(const struct contact* ps)
{assert(ps!=NULL);if (ps->size == 0){printf("通讯录为空\n");}else{printf("%-20s\t%-4s\t%-4s\t%-12s\t%-10s\n", "名字", "年龄", "性别", "电话", "住址");int i = 0;for (i = 0; i < ps->size; i++){printf(" %-20s\t%-4d\t%-4s\t%-12s\t%-10s\n",ps->date[i].name,ps->date[i].age,ps->date[i].sex,ps->date[i].tele,ps->date[i].addr);}}
}
static int find(const struct contact* ps)
{assert(ps!=NULL);char names[MAX_NAME];scanf("%s", names);int i = 0;for (i = 0; i < ps->size; i++){if (strcmp(ps->date[i].name, names) == 0){return i;}}return -1;
}
void Searchcontact(const struct contact* ps)
{assert(ps!=NULL);char names[MAX_NAME];if (ps->size == 0){printf("通讯录为空,无法查询\n");}printf("请输入查询的名字:>");int ret = find(ps);if (ret != -1){printf("%-20s\t%-4s\t%-4s\t%-12s\t%-10s\n", "名字", "年龄", "性别", "电话", "住址");printf(" %-20s\t%-4d\t%-4s\t%-12s\t%-10s\n",ps->date[ret].name,ps->date[ret].age,ps->date[ret].sex,ps->date[ret].tele,ps->date[ret].addr);}else{printf("没有此人\n");}
}
void Modifycontact(struct contact* ps)
{assert(ps!=NULL);printf("请输入要修改人的名字:>");int ret = find(ps);if (ret != -1){printf("修改后的名字;>");scanf("%s", ps->date[ret].name);printf("修改后的年龄;>");scanf("%d", &(ps->date[ret].age));printf("修改后的性别;>");scanf("%s", ps->date[ret].sex);printf("修改后的电话;>");scanf("%s", ps->date[ret].tele);printf("修改后的地址;>");scanf("%s", ps->date[ret].addr);printf("修改后的通讯录\n");//打印修改后的通讯录Showcontact(ps);}else{printf("要修改的人不存在\n");}
}
void Delcontact(struct contact* ps)
{assert(ps!=NULL);printf("请输入要删除人的名字:>");//查找要删除人的位置int ret = find(ps);//删除if (ret != -1){int i = 0;for (i = ret; i < ps->size - 1; i++){ps->date[i] = ps->date[i + 1];}ps->size--;printf("删除成功\n");printf("删除后的通讯录\n");Showcontact(ps);}else{printf("要删除的人不存在\n");}
}
void Sortcontact(struct contact* ps)
{assert(ps!=NULL);int i = 0;//冒泡排序for (i = 0; i < ps->size - 1; i++){int j = 0;for (j = 0; j < ps->size - 1 - i; j++){if (ps->date[j].age > ps->date[j + 1].age){struct peoinfo  tmp = ps->date[j];//要创建相同类型的ps->date[j] = ps->date[j + 1];ps->date[j + 1] = tmp;}}}printf("排序成功\n");printf("排序后的通讯录\n");//打印排序后的通讯录Showcontact(ps);
}
void menu()
{printf("**************** Menu *****************\n");printf("*****  1.add            2.show    *****\n");printf("*****  3.search         4.modify  *****\n");printf("*****  5.del            6.sort    *****\n");printf("*****  0.exit                     *****\n");printf("***************************************\n");
}//主函数部分
int main()
{int input = 0;//创建通讯录struct contact con;//con包含了1000个通信录信息,和size//初始化通讯录Initcontact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case add:Addcontact(&con);//1break;case show:Showcontact(&con);//2break;case search:Searchcontact(&con);//3break;case modify:Modifycontact(&con);//4break;case del:Delcontact(&con);//5break;case sort:Sortcontact(&con);//6break;case 0:printf("退出通讯录\n");break;default:printf("输入错误,重新输入\n");break;}} while (input);return 0;
}

带你一步一步实现通讯录的设计相关推荐

  1. 手挽手带你学React:四档(上)一步一步学会react-redux (自己写个Redux)

    手挽手带你学React入门四档,用人话教你react-redux,理解redux架构,以及运用在react中.学完这一章,你就可以开始自己的react项目了. 之前在思否看到过某个大神的redux搭建 ...

  2. 从零开始带你一步一步使用 YOLOv3 测试自己的数据

    上一篇: 从零开始带你一步一步使用YOLOv3训练自己的数据 我给大家详细介绍了如何使用 YOLOv3 模型来训练自己的数据集.训练部分完成,本文将继续给大家详细介绍如何使用我们训练好的模型来进行图片 ...

  3. 从零开始带你一步一步使用YOLOv3测试自己的数据

    红色石头的个人网站:redstonewill.com 知乎:https://www.zhihu.com/people/red_stone_wl 公众号:AI有道(redstonewill) 上一篇: ...

  4. 从零开始带你一步一步使用YOLOv3训练自己的数据

    红色石头的个人网站:redstonewill.com 知乎:https://www.zhihu.com/people/red_stone_wl 公众号:AI有道(redstonewill) YOLOv ...

  5. a4988 脉宽要求_Allegro MicroSystems 公司发布全新带过流保护的 DMOS 微步电动机驱动器 A4988...

    Allegro MicroSystems 公司发布全新带过流保护的 DMOS 微步电动机驱动器 A4988 热效率高.封装小巧精致 马萨诸塞州伍斯特-2010 年 4 月 29 日 - Allegro ...

  6. 一步一步,手把手带你用最简单的方法,在linux上安装anaconda

    1 前言 本文将会一步一步用最简单的方法,手把手带你在linux上安装anaconda,不改文件,不需要管理员权限,普通用户也可以操作! 当我们想利用服务器进行深度学习/数据分析时,我们通常需要使用P ...

  7. 你还停留在使用Dagger2吗? 带你一步一步走进Dagger2的世界

    Dagger2是一个依赖注入框架 1.什么是依赖注入? 就是目标类中所依赖的其他的类的初始化过程,不是通过手动编码的方式创建 将其他的类初始化好的实例自动注入到我们的目标类当中.它也是面向对象的一种设 ...

  8. React-Native带你一步一步实现侧滑删除

    前言:好久没有写博客了,回想起刚开始写博客的时候对自己的要求,"每周至少一篇!!!"(还有当初说减肥跟写博客同步进行,结果越减越肥.),嗯嗯,说多了都是泪,最近在一直在学习h5,然 ...

  9. 调试JDK源码-一步一步看HashMap怎么Hash和扩容

    调试JDK源码-一步一步看HashMap怎么Hash和扩容 调试JDK源码-ConcurrentHashMap实现原理 调试JDK源码-HashSet实现原理 调试JDK源码-调试JDK源码-Hash ...

最新文章

  1. Oracle表空间文件损坏后的排查及解决
  2. 随机森林——气温预测(2/2)
  3. LintCode-56.两数之和
  4. 每日一皮:当你感觉上升瓶颈的时候,不妨换个环境...
  5. nginx部分实现原理解析
  6. Cocoa touch(十):UIDatePicker
  7. CPU内核配置(一):通用内核配置
  8. android surfaceflinger研究----显示系统
  9. 爱因斯坦:量子物理与抽象数学(广义)
  10. php mysql实现下拉列表查询_php mysql如何实现通过下拉框查询显示数据库中的数据...
  11. NIST 按行政令关于加强软件供应链安全的要求,给出“关键软件”的定义及所含11类软件...
  12. python练手经典100例-Python 的练手项目有哪些值得推荐?
  13. 一些网站后台模板源码分析
  14. 改winpe注册信息及OEM信息
  15. c 语言编程字谜,C语言猜字谜游戏
  16. 理解Spring 容器设计理念
  17. Android技术点滴记录
  18. ATF:Gicv源码解读系列-gicv2_spis_configure_defaults
  19. lol最克制诺手的英雄_LOL诺手怎么打如何克制诺手 什么英雄好打诺手
  20. Android Studio设置http proxy加速下载(亲测有效)

热门文章

  1. 用html+css做出一个地下城游戏网站页面,新人练手推荐,带源码
  2. mkdir命令Linux,mkdir命令在Linux中的应用
  3. word自动生成章节标题
  4. 网页开发:MySQL和Python案例
  5. 帧数达不到144用144hz_科普一下144HZ显示器,可能很多人有误区,帮你们解答!...
  6. 基于快速行进平方法的水面无人船路径规划
  7. (二)最常用的量子计算模型——量子线路
  8. 高并发高可用处理大数据量
  9. 七巧板复原算法——计算机图形学基本算法之一, 点在多边形内部的判断
  10. 视频太大发不出去怎么办?微信视频太大发不出去的解决办法?