目录

简介:

基本要求:

代码的实现:

1、Contact.h

2、test.c

3、Cantact.c

运行效果图:

部分复杂函数流程图


前两周是本人的实验周,抽到的课题是“手机通信录的实现”,课题大致如下:

简介:

(1)用C/C++设计出模拟手机通信录系统,实现对手机中的通信录进行管理。

(2)将通讯录用文件存储,人员信息包括:姓名、手机号码、家庭电话号码、办公电话、电子邮件、分组。

(3)其中:手机号码、家庭电话号码、办公电话不能同时为空;分组说明:未知、同事、亲戚、朋友、家人、同学等还可以自己创建分组

(4)文件类型可以是文本文件或二进制文件。

基本要求:

(1)首先向客户展示一个欢迎界面,并提醒客户输入任意键进入主菜单,在菜单中客户进行操作选择,而且客户操作完后还可以根据需求进行返回主菜单进行其他操作。

(2)增加功能:

能录入新人员记录。

(3)查看功能:
选择此功能时,当选中某类时,显示出此类所有数据中的姓名和电话号码。

(4)拔号功能:
能显示出通信录中所有人的姓名,当选中某个姓名时,屏幕上模拟打字机的效果依次显示出此人的电话号码中的各个数字。

(5)修改功能: .
选中某个人的姓名时,可对此人的相应数据进行修改。

我一看,嚯哟!这个课题好简单啊!除了“分类查找”和“拨号”是我没写过的,剩下的功能不都是最基础的吗?主要涉及到的知识点不就是些:数组应用、指针和结构体嘛!

可是转念一想,不行,写的那么简单,和别的组没有区分度,不方便老师打分呢~(bushi)

再说了,这个程序一天就可以写完,再算上写实验报告和画函数图解也最多不过一周的事,不是对不起这两周的实验周吗?(对不起,后来博主被狠狠打脸了。老师要求很严格,不仅被要求补充了一些代码,最后写实验报告的时候简直被折磨的不行,流程图重画了好几遍……实验报告一共也就写了那么整整15个小时吧)

于是我决定,要写就写个详细的通信录程序。不仅补充上了“分类查找”和“模拟拨号(类似打印机)”这两个功能,我还增加了一些别的小功能:

1、“模糊查询”(即你要找“Jackson”这个联系人的信息,输入“Jack”,通信录会跳出所以名字含这个字符串的联系人信息。对于中文名也是可以的,比如你想找“如花”,输入“如”字按回车,它会跳出一堆“如花”、“如玉”......);

2、qsort函数实现排序:可以选择按照姓名、年龄和电话号码排序。

3、防误触:听上去好像很厉害,其实很简单,只有三行代码就搞定了。(不过是让用户再次确认自己的选择避免造成不可挽回的损失罢了)。

总之,断断续续地,花了三天时间,我终于把这个小程序写完了。它现在一共有11个功能,博主暂时想不到别的了,大家如果有好的想法可以提出来。

其实它还不是特别完备,只是一个静态的版本,我打算有时间的话把它改造成一个动态的版本,这就要涉及到我们的malloc、calloc 、free 和 realloc 函数了。

扯远了,现在让我们来看看这个通信录吧:

代码的实现:

1、Contact.h

宏定义的设置可以方便我们以后的修改。

#pragma once
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<windows.h>
#define MAX_NAME 10
#define MAX_SEX 5
#define MAX_HOME_NUM 12
#define MAX_NUM 12
#define MAX_OFFICE 15
#define MAX_DATA 100
#define MAX_E_MAIL 20
#define MAX_CLASSIFICATION 10
//创建联系人结构体
struct Peoinfo
{char name[MAX_NAME];   char sex[MAX_SEX];char home_num[MAX_HOME_NUM];char cell_num[MAX_NUM];int age;char office_number[MAX_OFFICE];char e_mail[MAX_E_MAIL];char classification[MAX_CLASSIFICATION];
};//创建通讯录结构体
struct Contact
{struct Peoinfo data[MAX_DATA];//存放数据int sz;//记录通讯录中的有效信息个数//int capcity;
};//把上次存在文件中的信息加载过来
void LoadContact(struct Contact* pc);
//初始化通讯录
void init_contact(struct Contact* con);
//添加联系人
void addContact(struct Contact* con);
//删除联系人
void deleteContact(struct Contact* con);
//修改联系人
void modifyContact(struct Contact* con);
//寻找联系人
static int find(const struct Contact* con, char* name);
//查找联系人
void searchContact(struct Contact* con);
//显示联系人信息
void showContact(struct Contact* con);
//排序联系人(按照年龄、名字)
void sortContact(struct Contact con);
//清空联系人
void clearContact(struct Contact* con);
//查看某一类联系人
void checkContact(struct Contact* con);
//保存联系人
void saveContact(struct Contact* con);
//拨号
void dialContact(struct Contact* con);
//把上次存在文件中的信息加载过来
//void LoadContact(struct Contact* pc);
//模糊查询联系人信息
void fuzzy_search(struct Contact* contact);

2、test.c

这里想要解释一下为什么要加一个枚举常量。(后面的Contact.c也添加了一个枚举,目的是一样的。)

枚举的使用增加了我们代码的可读性和维护性:

有时候在写一些代码时,比如写这个菜单,我们用了1来代表add,0代表exit,但是在后续代码中,1和0的真实含义有时难以被区分。所以如果用枚举的话,后续在case 后面加常量的时候就可以直接写add,这样,代码的可读性就增强了不少)。

注意!我们的防误触操作就设置在此处,因为它实在是太简单了,没有单独为它写一个函数的必要呢。

(和大家讲个笑话,活跃一下气氛。在界面设计这里呢,本来博主有一点自己的小私心,想要提醒老师我有模糊查询这个功能,让她夸夸我来着,但是她好像并不care,反而对我层层嵌套调用函数的addContact子功能青睐有加。)

#define _CRT_SECURE_NO_WARNINGS#include "contact.h"
void Meue()
{printf("***亲爱的用户,欢迎您使用通信录!***\n");printf("***温馨提示,本通信录支持模糊查询的功能哦!***\n");printf("************************************\n");printf("*****   1.add       2.delete   *****\n");printf("*****   3.modify    4.search   *****\n");printf("*****   5.show      6.sort     *****\n");printf("*****   7.clear     8.check    *****\n");printf("*****   9.save      10.dial    *****\n");printf("*****   11.fuzzy_search        *****\n"); printf("*****   0.exit                 *****\n");printf("************************************\n");
}
int main()
{int input = 0;enum number{EXIT,//0ADD,//1DELE,//2MODIFY,SEARCH,SHOW,SORT,CLEAR,CHECK,SAVE,DIAL,FUZZY_SEARCH,};struct Contact con;//通信录init_contact(&con);//初始化通信录LoadContact(&con);//把上次存在文件中的信息加载过来do{Meue();printf("请选择:");scanf_s("%d", &input);switch (input){case EXIT://这里设置一个防误触的功能,提醒用户再次确认是否要保存一下联系人信息再退出printf("请问需要保存一下通讯录的信息再退出吗?\n");printf("**********   1.保存一下   0.直接退出  **********\n");int q = 0;scanf("%d", &q);if (q==0){printf("退出通信录!\n");break;} saveContact(&con);printf("退出通信录!\n");break;case ADD:addContact(&con);break;case DELE:deleteContact(&con);break;case MODIFY:modifyContact(&con);break;case SEARCH:searchContact(&con);break;case SHOW:showContact(&con);break;case SORT:sortContact(con);break;case CLEAR://这里设置一个防误触的功能,提醒用户再次确认是否要清空联系人信息printf("请问您确定要清空联系人信息吗?一旦清空,无法找回!\n");printf("*************   1.确定清空   0.取消  *************\n");int x = 0;scanf("%d",&x);if (x==1) {clearContact(&con);}break;case CHECK:checkContact(&con);break;case SAVE:saveContact(&con);break;case DIAL:dialContact(&con);break;case FUZZY_SEARCH:fuzzy_search(&con);break;default:printf("输入错误!\n");break;}} while (input);return 0;
}

3、Cantact.c

这个源文件定义了每一个子函数的实现,还添加了两个小的 find 函数帮助个别子函数的实现。

注解都写了,大家可以好好看一下:

#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
//把上次存在文件中的信息加载过来
void LoadContact(struct Contact* pc)
{//打开文件FILE* pf = fopen("D:\\C语言2\\手机通信录实现\\contact.dat", "rb");if (pf == NULL){perror("LoadContact::fopen");return;}//读文件struct Peoinfo tmp = { 0 };while (fread(&tmp, sizeof(struct Peoinfo), 1, pf)){pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;
}
//初始化通讯录
void init_contact(struct Contact* pc)
{assert(pc);pc->sz = 0;memset(pc->data, 0, MAX_DATA * sizeof(struct Peoinfo));
}
//add中判断是否存在相同姓名联系人
int repetition_name(struct Contact * con, char* len)
{int ret = find(con, len);int i = 0;if (ret == -1)return 3;else{int repe;printf("已存在同名联系人,请选择:>\n");printf("*** 0.重新输入 1.覆盖  2.新建 ***\n");scanf("%d", &repe);switch (repe){case 0:return 0;case 1:i = 0;for (i = 0; i < con->sz - ret; i++){con->data[ret + i] = con->data[ret + i + 1];}con->sz--;printf("覆盖联系人成功!\n");return 1;case 2:return 2;}}
}
//add中判断是否存在相同号码联系人
int repetition_num(struct Contact* con, char* len)
{int ret = findnum(con, len);int i = 0;if (ret == -1)return 2;else{int repe;printf("已存在相同号码的联系人,请选择:>\n");printf("*** 0.重新输入 1.覆盖  ***\n");//号码是无法相同的,所以不要新建scanf("%d", &repe);switch (repe){case 0:return 0;case 1:i = 0;for (i = 0; i < con->sz - ret; i++){con->data[ret + i] = con->data[ret + i + 1];}con->sz--;printf("覆盖联系人成功!\n");return 1;}}
}
//add中用于判断电话号码中是否存在非数字字符
int isnumber(const char* ps)
{while (*ps != '\0'){if (*ps < '0' || *ps > '9'){return 0;}ps++;}if (*ps == '\0'){return 1;}
}
//新建联系人
void new(struct Contact* con, char* len)
{char new[MAX_NAME] = {0};strcpy(new, con->data[con->sz].name);
}
//添加联系人
void addContact(struct Contact* con)
{assert(con);int ret;int k ;char new[MAX_NAME] = {0};if ((con->sz) == MAX_DATA){printf("通讯录已满!无法增加\n");return;}printf("请输入名字:>");    do{scanf("%s", con->data[con->sz].name);//数组名本身就是首元素地址k = repetition_name(con, con->data[con->sz].name);if(k==0)printf("请重新输入!\n");if (k == 2){printf("请输入新的备注:>");scanf("%s",new );strcat(con->data[con->sz].name,new);//在名字后添加备注}} while (!k);printf("请输入性别:>");scanf("%s", con->data[con->sz].sex);printf("请输入家庭电话:>");//判断是否有非数字字符do{ret = 1;scanf("%s", con->data[con->sz].home_num);if (!isnumber(con->data[con->sz].home_num))printf("提示!输入的号码中存在非数字字符,请重新输入!\n");elseret = 0;} while (ret);//因为是家庭号码,所以此处不需要判断是否已有相同号码联系人存在printf("请输入个人电话:>");do{ret = 1;scanf("%s", con->data[con->sz].cell_num);if (!isnumber(con->data[con->sz].cell_num))printf("提示!输入的号码中存在非数字字符,请重新输入!\n");elseret = 0;} while (ret);//判断是否已有相同号码联系人存在do{k = 1;k = repetition_num(con, con->data[con->sz].cell_num);if (!k){ printf("请重新输入!\n");scanf("%s", con->data[con->sz].cell_num);k = 1;}elsek = 0;} while (k);printf("请输入年龄:>");scanf("%d", &(con->data[con->sz].age));//这里需要取地址printf("请输入办公电话:>");do{ret = 1;scanf("%s", con->data[con->sz].office_number);if (!isnumber(con->data[con->sz].office_number))printf("提示!输入的号码中存在非数字字符,请重新输入!\n");elseret = 0;} while (ret);//因为是办公号码,所以此处不需要判断是否已有相同号码联系人存在 printf("请输入邮箱:>");scanf("%s", con->data[con->sz].e_mail);printf("请输入分类:>\n");printf("您可以在以下选项中进行选择并输入:>\n");printf("同事  亲戚  朋友  家人  同学  老师  其他\n");scanf("%s", con->data[con->sz].classification);con->sz++;printf("添加联系人成功!\n");
}
//删除联系人
void deleteContact(struct Contact* con)
{if (con->sz == 0){printf("通讯录为空,无法删除!\n");return;}char name[MAX_NAME];printf("请输入要删除的联系人:");scanf("%s", name);int ret = find(con, name);if (ret == -1)printf("未找到该联系人!\n");else{int i = 0;for (i = 0; i < con->sz - ret; i++){con->data[ret + i] = con->data[ret + i + 1];}con->sz--;printf("删除联系人成功!\n");}
}
//修改联系人
void modifyContact(struct Contact* con)
{char name[MAX_NAME];printf("请输入要修改的联系人:");scanf("%s", name);int ret = find(con, name);if (ret == -1)printf("未找到该联系人!\n");else{int n = 0;do{int ret;int k;printf("请选择你想要修改的信息:\n");printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5s\t%-15s\t%-20s\t%-10s\n","0.退出修改","1.姓名", "2.性别", "3.家庭电话", "4.个人电话", "5.年龄", "6.办公电话", "7.邮箱", "8.分类");scanf("%d", &n);switch (n){case NAME:printf("请输入你想修改的姓名:");do{scanf("%s", con->data[con->sz].name);//数组名本身就是首元素地址k = repetition_name(con, con->data[con->sz].name);if (k == 0)printf("请重新输入!\n");if (k == 2){printf("请输入新的备注:>");scanf("%s", new);strcat(con->data[con->sz].name, new);//在名字后添加备注}} while (!k);printf("修改成功!\n");break;case SEX:printf("请输入你想修改的性别:");scanf("%s", con->data[ret].sex);break;case HOME_NUM:printf("请输入你想修改的家庭电话:");//判断是否有非数字字符do{ret = 1;scanf("%s", con->data[con->sz].home_num);if (!isnumber(con->data[con->sz].home_num))printf("提示!输入的号码中存在非数字字符,请重新输入!\n");elseret = 0;} while (ret);//因为是家庭号码,所以此处不需要判断是否已有相同号码联系人存在break;case CELL_NUM:printf("请输入你想修改的手机号码:");do{ret = 1;scanf("%s", con->data[con->sz].cell_num);if (!isnumber(con->data[con->sz].cell_num))printf("提示!输入的号码中存在非数字字符,请重新输入!\n");elseret = 0;} while (ret);//判断是否已有相同号码联系人存在do{k = 1;k = repetition_num(con, con->data[con->sz].cell_num);if (!k){printf("请重新输入!\n");scanf("%s", con->data[con->sz].cell_num);k = 1;}elsek = 0;} while (k);break;case AGE:printf("请输入你想修改的年龄:");scanf("%d", &con->data[ret].age);//不是数组,需要写地址符break;case OFFICE_NUMBER:printf("请输入你想修改的办公电话:");do{ret = 1;scanf("%s", con->data[con->sz].office_number);if (!isnumber(con->data[con->sz].office_number))printf("提示!输入的号码中存在非数字字符,请重新输入!\n");elseret = 0;} while (ret);//因为是办公号码,所以此处不需要判断是否已有相同号码联系人存在 break;case E_MAIL:printf("请输入你想修改的电子邮箱:");scanf("%s", con->data[ret].e_mail);break;case CLASSFICATION:printf("请输入你想修改的分组:");scanf("%s", con->data[ret].classification);break;case LEAVE:printf("不修改退回页面\n");break;default:printf("无效操作数!\n");}} while (n);}
}//下面这些代码是表示每次修改都要重新输入该联系人的所有信息的,//因为不太方便,所以改造了一下,//改成上面那样,只用修改自己想要修改的信息//else//{// printf("请输入姓名:");//    scanf("%s", con->data[ret].name);//    printf("请输入性别:");//    scanf("%s", con->data[ret].sex);// printf("请输入电话:");//    scanf("%s", con->data[ret].home_num);//    printf("请输入电话:");//    scanf("%s", con->data[ret].cell_num);//    printf("请输入年龄:");//    scanf("%d", &(con->data[ret].age));//  printf("请输入办公电话:");//  scanf("%s", con->data[ret].office_number);//   printf("请输入邮箱:");//    scanf("%s", con->data[ret].e_mail);//  printf("请输入分类:");//    scanf("%s", con->data[ret].classification);//  printf("修改联系人成功!\n");//}//寻找联系人是否存在——因为有多个功能都需要我们先去确认是否存在联系人,
//所以干脆把这个功能作为一个函数独立出去
static int find(const struct Contact* con, char* name)
//加上static之后就不会被别人看到,只能在该源文件使用
{int i = 0;for (i = 0; i < con->sz; i++){if (0 == strcmp(con->data[i].name, name))return i;}return -1;//i==con->sz
}
static int findnum(const struct Contact* con, char* number)
//同样的,查找联系人电话我们也把它独立出来
{int i = 0;for (i = 0; i < con->sz; i++){if (0 == strcmp(con->data[i].cell_num, number))return i;}return -1;//i==con->sz
}
//查找联系人
void searchContact(struct Contact* con)
{assert(con);char name[20] = { 0 };char number[12] = {0};int n;printf("请问您想要通过那种方式查找联系人:\n");printf("***    1.姓名    2.电话号码    ***\n");int ret=0;scanf("%d",&n);switch (n){case 1:printf("请输入要查找的联系人姓名:");scanf("%s", &name);ret = find(con, name);if (ret == -1)printf("未找到该联系人!\n");else{printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5s\t%-15s\t%-20s\t%-10s\n","姓名", "性别","家庭电话", "个人电话", "年龄", "办公电话", "邮箱", "分类");printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5d\t%-15s\t%-20s\t%-10s\n",con->data[ret].name, con->data[ret].sex, con->data[ret].home_num,con->data[ret].cell_num, con->data[ret].age, con->data[ret].office_number,con->data[ret].e_mail, con->data[ret].classification);}break;case 2:printf("请输入要查找的联系人的电话号码:");scanf("%s", &number);ret = findnum(con, number);if (ret == -1)printf("未找到该联系人!\n");else{printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5s\t%-15s\t%-20s\t%-10s\n","姓名","性别", "家庭电话", "个人电话", "年龄", "办公电话", "邮箱", "分类");printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5d\t%-15s\t%-20s\t%-10s\n",con->data[ret].name, con->data[ret].sex, con->data[ret].home_num,con->data[ret].cell_num, con->data[ret].age, con->data[ret].office_number,con->data[ret].e_mail, con->data[ret].classification);}break;}}
//显示联系人
void showContact(struct Contact* con)
{assert(con);int i = 0;//姓名      性别   家庭电话      个人电话           年龄          办公电话      邮箱                  分类//zhangsan  男     1245676789    13245123123        20            12538912332   67125677121@136.com   家人printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5s\t%-15s\t%-20s\t%-10s\n","姓名", "性别","家庭电话", "个人电话", "年龄", "办公电话", "邮箱", "分类");for (i = 0; i < con->sz; i++){printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5d\t%-15s\t%-20s\t%-10s\n",con->data[i].name, con->data[i].sex, con->data[i].home_num,con->data[i].cell_num, con->data[i].age, con->data[i].office_number,con->data[i].e_mail, con->data[i].classification);}}
//按姓名排序
int name_cmp(const void* e1, const void* e2)
{return strcmp(((struct Peoinfo*)e1)->name, ((struct Peoinfo*)e2)->name);
}
//按办公电话排序
int office_number_cmp(const void* e1, const void* e2)
{return strcmp(((struct Peoinfo*)e1)->office_number,((struct Peoinfo*)e2)->office_number);
}
//按年龄排序
int age_cmp(const void* e1, const void* e2)
{return ((struct Peoinfo*)e1)->age - ((struct Peoinfo*)e2)->age;
}
//排序通讯录
void sortContact(struct Contact con)
{printf("********* 请选择排序方式:**********\n");printf("********* 1.姓名         ***********\n");printf("********* 2.办公电话     ***********\n");printf("********* 3.年龄         ***********\n");printf("************************************\n");int a = 0;scanf("%d", &a);switch (a){case 1:qsort(con.data, con.sz, sizeof(con.data[0]), name_cmp);break;case 2:qsort(con.data, con.sz, sizeof(con.data[0]), office_number_cmp);break;case 3:qsort(con.data, con.sz, sizeof(con.data[0]), age_cmp);break;default:printf("输入错误\n");break;}int i = 0;printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5s\t%-15s\t%-20s\t%-10s\n","姓名","性别", "家庭电话", "个人电话", "年龄", "办公电话", "邮箱", "分类");for (i = 0; i < con.sz; i++){printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5d\t%-15s\t%-20s\t%-10s\n",con.data[i].name, con.data[i].sex, con.data[i].home_num,con.data[i].cell_num, con.data[i].age, con.data[i].office_number,con.data[i].e_mail, con.data[i].classification);}
}
//清空联系人
void clearContact(struct Contact* con)
{con->sz = 0;printf("清空联系人成功!\n");
}//查看某一类联系人
void checkContact(struct Contact* con)
{char classification[10];int jude = 0;do {printf("人员信息如下:\n");printf("同事  亲戚  朋友  家人  同学  老师  其他\n");printf("请输入查看人员的类别:\n");scanf("%s", classification);//用来判断输入字符串是否符合分类名称char* judgeclass[7] = { "同事",  "亲戚", "朋友","家人","同学","老师","其他" };for (jude = 0; jude < 7; jude++){if ((strcmp(judgeclass[jude], classification) == 0))break;}if (jude == 7){printf("您输入的分类名错误,请重新输入!>\n");}} while (jude==7);for(int ssz= con->sz - 1;ssz>=0;ssz--){if (strcmp((con->data[ssz].classification), classification) == 0){printf("%-10s\t%-12s\t%-12s\t%-15s\n", "姓名", "家庭电话", "个人电话", "办公电话");printf("%-10s\t%-12s\t%-12s\t%-15s\n",con->data[ssz].name, con->data[ssz].home_num,con->data[ssz].cell_num, con->data[ssz].office_number);}}printf("查找结束!\n");
}
//保存联系人
void saveContact(struct Contact* con)
{FILE* pf = fopen("D:\\C语言2\\手机通信录实现\\contact.dat", "wb");if (pf == NULL){//显示错误信息,表示是在saveContact函数内的这个地方出错了!perror("SaveContact::fopen");return;}//写数据int i = 0;for (i = 0; i < con->sz; i++){//&(con->data[i])可以写成con->data+i,更简单fwrite(con->data + i, sizeof(struct Peoinfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;//简单提示一下printf("保存成功!\n");
}//拨号功能
void dialContact(struct Contact* con)
{if (con->sz == 0){printf("通信录中没有联系人信息!\n");return;}printf("通讯录中所有联系人如下:\n");for (int i = 0; i < con->sz; i++){printf("%d . 姓名:%s\n", i + 1, con->data[i].name);}int choice = 0;printf("请选择您要拨打电话的联系人编号(输入0返回主菜单):");scanf("%d", &choice);if (choice < 0 || choice > con->sz){printf("输入的编号有误,请重新选择!\n");dialContact(con);//返回拨号函数选择处return;}if (choice == 0){return;}printf("您选择的联系人是:%s\n", con->data[choice - 1].name);printf("个人电话:");// 模拟打字机效果逐个显示电话号码中的数字for (int i = 0; i < strlen(con->data[choice - 1].cell_num); i++){printf("%c", con->data[choice - 1].cell_num[i]);Sleep(300);  // 每个数字之间停顿一段时间}printf("\n");printf("家庭电话:");// 模拟打字机效果逐个显示电话号码中的数字for (int i = 0; i < strlen(con->data[choice - 1].home_num); i++){printf("%c", con->data[choice - 1].home_num[i]);Sleep(300);  // 每个数字之间停顿一段时间}printf("\n");printf("办公电话:");// 模拟打字机效果逐个显示电话号码中的数字for (int i = 0; i < strlen(con->data[choice - 1].office_number); i++){printf("%c", con->data[choice - 1].office_number[i]);Sleep(300);  // 每个数字之间停顿一段时间}printf("\n");
}// 子函数,实现模糊查找功能
void fuzzy_search(struct Contact* contact)
{assert(contact);char fuzzy_name[10] = {0};printf("请输入想要查询的联系人的姓名:\n");scanf("%s",fuzzy_name);char* key = fuzzy_name;// 检查通讯录中是否有联系人信息,如果没有,无法进行模糊查询if (contact->sz == 0){printf("通讯录中没有联系人信息!\n");return;}int index[MAX_DATA];int count = 0;// 遍历通讯录中的每个联系人for (int i = 0; i < contact->sz; i++){struct Peoinfo* person = &contact->data[i];// 在联系人的各个字段中查找是否包含要查找的字符串keyif (strstr(person->name, key)){printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5s\t%-15s\t%-20s\t%-10s\n","姓名", "性别", "家庭电话", "个人电话", "年龄", "办公电话", "邮箱", "分类");printf("%-10s\t%-5s\t%-12s\t%-12s\t%-5d\t%-15s\t%-20s\t%-10s\n",person->name, person->sex, person->home_num, person->cell_num, person->age, person->office_number,person->e_mail, person->classification);index[count++] = i;}}// 如果没有找到匹配的联系人,则输出提示信息if (count == 0){printf("未找到匹配的联系人!\n");}else{printf("共找到 %d 个匹配的联系人,分别为:", count);for (int i = 0; i < count; i++){printf("第%d个联系人 ", index[i]+1);//让联系人看起来是从第1个开始排序的,即下标0处跳过}printf("\n");}
}

运行效果图:

1、增加联系人

总的显示给大家看一下:

现在假设我们重新输入,来看看如果出现名字相同的联系人,程序会有什么反应吧:

来看看新建同名联系人后的小米和小米(1)吧: 

那电话号码相同的呢?可以新建吗?当然不行,和姓名相同时的代码略有不同:

如果选择覆盖呢?

小米不见了呢!(对不起,小米):

当然,我们迷人的addContact函数还有一个功能,就是会判断你输入的三个电话号码中是否存在非数字字符,来看一下吧:

2、删除联系人

总的显示给大家看一下:

3、修改联系人信息:

总的显示给大家看一下:

4、寻找单个联系人 

5、显示整个通讯录(刚刚已经展示过了)

6、排序

7、清除所有联系人

8、按分类查找某一类的联系人

9、保存到文件里

已经保存到当前目录下了:

10、模拟拨号(它是像打印机一样慢慢一个数字一个数字打印的,这里演示不了)

11、模糊查询 

12、把上次已经存好在文件中的信息加载过来:

当初次使用时:

如果已有信息(这里博主为了演示,把刚刚上面举的例子都删除了,所以现在的数据是博主又重新输入的,和上面的联系人信息存在不同,请见谅):

现在已经保存好了:

我们重启程序看看: 成功读取了呢!

好了!以上就是我的手机通信录的整个代码实现。

如果你认真看到这里,说明你应该对它的实现很感兴趣吧。

心动不如行动!实践是很重要的!现在,打开电脑,开始码代码吧。

博主建议,各位兄台先自己实现一下,如果遇到逻辑不通的地方,可以画一个图解帮助自己理解,

实在是遇到不理解的地方可以再回来看看。自己写一遍真的不一样!!!

部分复杂函数流程图

最后,因为两个结构体的关系有一点不好理解,所以博主画了一个总的说明图(图1):

图1

下面是一些稍微复杂的函数的流程图(实验报告要求要画,我觉得比代码难搞1000倍!超累的!!!)

添加联系人函数:用于将新的联系人信息添加到通讯录中。该功能包括输入联系人的各项信息,然后将这些信息保存到通讯录中。在保存之前,可能需要进行一些验证和处理,例如检查通讯录是否已满、检查是否存在重复的姓名或电话号码等。

该函数用于将新的联系人信息添加到通讯录中。该功能包括输入联系人的各项信息,然后将这些信息保存到通讯录中。在保存之前,可能需要进行一些验证和处理,例如检查通讯录是否已满、检查是否存在重复的姓名、存入电话号码前先判断输入的是否为数字、是否存在重复的电话号码等,如图2-1-1所示。其中,添加联系人函数用到了5个小的功能函数,它们在“修改联系人函数”时也会再次被调用。find函数流程图,用来寻找整个通信录中是否有该名字的字符串,如图2-1-2所示;findnum函数流程图,用来寻找整个通信录中是否已有相同号码的字符串,如图2-1-3所示;isnumber函数流程图,用来判断输入号码中是否含有非数字字符,如图2-1-4所示;repetition_name函数流程图,用于判断是否有相同姓名的联系人,如图2-1-5所示;repetition_num函数,用于判断是否有相同号码的联系人,如图2-1-6所示。

图2-1-1 添加联系人功能(第1种实现)

图2-1-2 fun函数(查找同名联系人)

图2-1-3 funnum函数(查找相同号码联系人)

图2-1-4 isnumber函数(判断是否有非数字字符)

图2-1-5 repetition_name函数

图2-1-6 repetition_num函数

修改联系人信息函数:在已有的通讯录中修改联系人的相关信息的函数。要求用户输入要修改的联系人姓名作为唯一标识信息,然后遍历整个通讯录,查找是否存在该联系人。如果存在该联系人,用户可以根据需要选择需要修改的信息并进行修改,修改后的信息会被更新到通讯录中,如果没有找到该联系人,则会给出相应的提示信息。

在已有的通信录中修改联系人的相关信息的函数,先判断通信录是否为空,若为空则提醒用户并退出,不为空则要求用户输入要修改的联系人姓名,作为唯一标识信息,然后遍历整个通信录,查找是否存在该联系人。若存在该联系人,用户可以根据需要选择需要修改的信息并进行修改,修改后的信息会被更新到通信录中,若没有找到该联系人,则会给出相应的提示信息。流程图如图3所示。

 查找特定联系人函数:根据姓名或号码查找特定联络人信息。这个功能允许用户通过输入联系人的姓名或号码来查找该联系人的信息,如果找到,则返回该联系人的详细信息,否则返回查找失败的信息。

查找特定联系人信息流程图如图5所示。

如图5  查找特定联系人信息

模糊查询函数:在通讯录中根据关键字模糊搜索联系人信息的功能。该功能可以让用户快速查找到包含特定关键字的联系人信息。根据输入的关键字,遍历通讯录中的所有联系人信息,查找包含关键字的联系人信息并输出。

模糊查询函数如图6所示

图6  模糊查询函数

本次内容到这里就结束啦!谢谢认真看到这里的你呀!

实验课题——最全手机通信录实现版本(【含注释】848行代码)!!!(包括模糊查询、分类查找、模拟拨号、qsort函数实现排序、文件存储、防误触等功能)相关推荐

  1. 微信是如何飞起来的(延伸阅读:性,微信下的机会?一个超级用户的自白:移动社交那点事类kik手机通信录互动应用前景探讨)

    与腾讯的发展史一样,微信在骂声中飞快成长--虽然既非原创,又不具备首发优势,但仅仅一年,微信竟远远超越对手们,拥有了5000万用户. 它的风行,既依托于腾讯源源不断的弹药支援,又源自其持续改进的细节拿 ...

  2. 【并发编程七】C++进程通信——套接字(socket)_80行代码实现一个聊天软件

    [并发编程七]进程通信--套接字(socket)_80行代码实现一个聊天软件 一.简介 二.相关知识介绍 1.winsock1.h.winsock2.h 2.如何使用ws2_32.dll 3.WSAS ...

  3. JS+XML打造QQ个性通信录

    JS+XML打造QQ个性通信录 本文大概介绍用JS操纵XML实现具有查询功能的通信录.而且可以把它嵌入到QQ面板. 主要有 Communication.htm,Communication.xml ,C ...

  4. android 备份 通信录,如何简单备份手机通讯录?

    现在,很多小伙伴更换手机的速度很快,备份手机通讯录就变成经常性的工作了.备份通信录的办法有很多种.今天,小编就给大家介绍几种备份方法~ SIM卡备份 采用SIM卡备份和还原是最原始,也是最通用的备份方 ...

  5. 换手机 之导入通信录

    是这样的,用了很久的手机突然没法接听电话了,于是就去捣鼓了个新的. 一般买来新手机,最重要的就是导入通信录之类的事情.于是问题就来了,古董手机的系统是Android 1.5的,折腾了半天愣是没找到导出 ...

  6. iOS:通信录(完成)(18-01-18更)

    1.读取通信录 1).9.0以前:AddressBook 2).9.0以后:Contacts 2.调用通信录UI(不弄) 1).9.0以前:AddressBookUI 2).9.0以后:Contact ...

  7. 微课|中学生可以这样学Python(例11.3):tkinter通信录管理系统4

    适用教材: 董付国,应根球.<中学生可以这样学Python>.清华大学出版社,2017. 第11章  综合案例设计与分析 例11.3  tkinter版通信录管理系统 京东购买链接:htt ...

  8. 微课|中学生可以这样学Python(例11.3):tkinter通信录管理系统1

    适用教材: 董付国,应根球.<中学生可以这样学Python>.清华大学出版社,2017. 第11章  综合案例设计与分析 例11.3  tkinter版通信录管理系统 京东购买链接:htt ...

  9. 微课|中学生可以这样学Python(例11.3):tkinter通信录管理系统2

    适用教材: 董付国,应根球.<中学生可以这样学Python>.清华大学出版社,2017. 第11章  综合案例设计与分析 例11.3  tkinter版通信录管理系统 京东购买链接:htt ...

最新文章

  1. C# winform combobox默认选中项方法
  2. python编程基础课后答案-中国大学慕课moocPython编程基础课后答案
  3. 20万人仍然每天活跃在“死”掉的ofo APP上:这已变成一个返利应用
  4. STM32手册中的CAN过滤器16位标识符屏蔽配置错误说明
  5. 如何使用浏览器控制台通过JavaScript抓取并将数据保存在文件中
  6. java 导出excel 例子_java导出Excel例子
  7. 产品设计思维工具(2019年做产品的一点总结)
  8. BizTalk Server 2010新功能介绍(四):基于安全连接的FTP适配器
  9. 董洁经纪人挑拨离间,潘粤明称董洁经纪人插手婚姻
  10. 垃圾收集器分类与GC性能指标
  11. 我国跨境电子商务的发展概念以及发展概况
  12. vlan的理解以及华为access、trunk、hybrid三种链路对比
  13. 前端基础知识学习总结--百分比布局、Flex布局
  14. 【Python】在Anaconda中设置清华镜像站并解决“http error“问题
  15. 实现微博自动化脚本-方案对比分析
  16. angular12简单搭建项目的过程记录
  17. 数字图像处理(绪言)
  18. Python——列表与元组
  19. 数字电路中的基础电路结构
  20. 核心交换机链路聚合、冗余、堆叠、热备份

热门文章

  1. 天降神器——Synergy
  2. 仿淘宝京东商品规格属性选择的最简单实现
  3. 如何对Docker容器进行健康检查
  4. 【VirtualAPP 双开系列07】第三方 APP Service、Provider 加载分析
  5. 西门子828D 840Dsl数控程序PLC西门子数控程序中文注释,详细解释介绍
  6. 安卓下Kindle导入本地电子书的方法
  7. 一周开发一个轻量级客服系统(代码开源)
  8. 强化学习用于金融时序问题(Q,DQN,AC)
  9. 贵州大学计算机专业男女比例,全国高校男女比例排行榜出炉! 妈, 我大学估计真找不到对象了...
  10. 为了弄清起点小说如何算字扣钱,我特意注册了作家账号