C语言实现简易小游戏|C语言----实现动态通讯录


文章目录

  • 前言
  • 一、建立文件
  • 二、编写函数
  • 三、调试运行
  • 四、成果展示
  • 五、代码汇总
  • 总结

前言 通讯录是我们日常手机中常见的功能之一,综合C语言中结构体,循环,条件语句,动态内存分配等等知识点,我们对手机通讯录进行一个简单的实现,下面我们开始讲解!!!
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

准备工作:(利用C语言实现动态通讯录) 所需知识:
①.函数调用,函数宏的定义及使用,库函数对应的头文件,函数声明
②.循环语句,选择语句( switch 和 if 语句 )的使用
③.指针,自定义类型的使用(结构体和枚举类型)
④.qsort函数的使用
⑤.动态内存分配函数(malloc函数和realloc函数)的使用
总结:该程序所需的知识比较全面,可以借助本程序对所学C语言的知识进行一个较为全面的复习
在这里我们采用的是多文件的编写方式,各个文件分工明确,代码简约可读性高

一、创建文件 1.创建一个头文件用来编写函数声明,库函数的头文件,定义define宏,定义结构体的基本信息,我们把这些代码都放在头文件里面方便我们另外两个文件调用,头文件里面的代码我们其他两个 .c 文件中都要用到,这样的编写方式使我们的代码更加简约,增加可读性。
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

2.在contact.c文件中我们主要编写的是通讯录的功能函数
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

3.在test.c文件中我们编写的通讯录的基本样式,以及通过test.c这个文件去串起来其他两个文件,实现通讯录的功能
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片


提示:为了方便解析代码博主将代码进行了拆分,在文章的最后会给大家放上最终三个文件的完整代码
二、需求分析+实际编写 1.首先在我们的程序中先创建一个通讯录,再利用它去实现功能
①.分析:我们知道通讯录里面会存储一个人的多个信息,比如:年龄,性别,电话等等,这些都是一个人的多个属性,所以我们就可以把一个人的基本信息封装到一个结构体里
具体代码如下:
struct PeoInfo//定义一个联系人基本信息 { char name[namemax]; int age; char sex[sexmax]; char tel[telemax]; char addr[addrmax]; };

我们看到在结构体里面存储一个人的五项基本信息,由于两个 .c 文件都会用到此结构体的成员信息,所以我们把这个结构体放在文件中。我们注意到字符串数组括号里面没有写具体的数字,而是用宏进行了代替,这样的目的是方便以后对数据的修改,仅仅对宏修改即可,省去对程序的每一个涉及到该字符串的数据进行修改。
该代码块涉及到的宏:
#define namemax 20 #define sexmax 5 #define telemax 12 #define addrmax 30

我们看到如果需要修改字符串数组的容量,仅需要对宏后面的数据进行修改即可。
②.分析:我们已经定义了一个基本联系人的信息,我们想一下,一个通讯录是由多个联系人的基本信息组成的,所以我们又可以把多个联系人的信息(即结构体数组),封装到一个结构体中,此结构体代表的就是我们的所需要的通讯录
具体代码如下:
struct contact { struct PeoInfo* data; int sz ; //目前通讯录有几个 int capacity; //通讯录的总容量 };

我们在这里定义了一个结构体用来存放多个联系人的信息,在 contact 结构体里我们存放了一个结构体指针运来存放 PeoInfo 结构体数组的首地址,这里结构体指针代表的就是多个通讯录成员的信息,sz变量用来记录通讯录的人数,capacity变量代表的是通讯录的总容量。
2.通讯录已经创建完成,接下来我们先编写主函数,再对通讯录进行初始化等一系列操作
我们先编写一个菜单函数,方便程序运行后根据菜单选择序号进行功能的实现
具体代码如下:
void menu() { printf("**************************************\n"); printf("*1.添加联系人2.删除联系人*\n"); printf("*3.查找联系人4.修改联系人*\n"); printf("*5.展示通讯录6.按名字排序*\n"); printf("*0.退出*\n"); printf("**************************************\n"); }

菜单栏的样式随意设计即可。
接着我们定义一个枚举类型,把我们功能的名称都写入枚举类型中,注意这里写入时要注意顺序,和我们规定的菜单的功能编号一致,这样可以保证输入对应的序号实现对应的功能
enum Option { EXIT, ADD, DEL, SERCH, MODIFY, SHOW, SORT };

这里的枚举类型从头开始默认的初值是 0 每向下走一个类型递增 1 ,数值顺序对应我们的功能序号即可
最后我们编写我们的主函数作为调用通讯录功能的函数
具体代码如下:
#pragma warning(disable : 4996) #include "contact.h" void menu() { printf("**************************************\n"); printf("*1.添加联系人2.删除联系人*\n"); printf("*3.查找联系人4.修改联系人*\n"); printf("*5.展示通讯录6.按名字排序*\n"); printf("*0.退出*\n"); printf("**************************************\n"); } enum OPTION { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; int main() { int input = 0; struct contact con; //创建一个通讯录con变量 initcontact(&con); //初始化通讯录 do { menu(); printf("请选择通讯录功能>"); scanf("%d", &input); switch (input) { case ADD: addcontact(&con); break; case DEL: delcontact(&con); break; case SEARCH: searchcontact(&con); break; case MODIFY: modifycontact(&con); break; case SHOW: showcontact(&con); break; case SORT: sortcontact(&con); break; case EXIT: destorycontact(&con); printf("退出通讯录\n"); break; } } while (input); return 0; }

我们在这里定义了一个 input 输入变量,根据用户的输入去实现不同的功能。创建了一个结构体变量con,变量 con 代表的就是我们的刚刚设置好的通讯录。定义一个 initcontact 函数对我们的通讯录进行初始化(开辟空间)。进入循环,用户输入不同的数据实现不同的功能,case后面的枚举类型代表的就是对应的功能序号,在每一个功能下面都有一个功能函数去实现不同的功能,最后循环以输入的input数值最后循环终止的条件,如果输入的是 0 退出通讯录,结束循环。
3.下面我们对通讯录进行初始化以及功能函数的编写
①.我们先对通讯录进行初始化(即给通讯录分配空间)
具体代码如下:
void initcontact(struct contact* pc) { pc->data = https://www.it610.com/article/(struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo)); //动态分配给data一块内存 pc->sz = 0; //初始化时通讯录没人 pc->capacity = size; //假设一开始的通讯录容量为3后面不够用随时增容 }

#define size 3

我们看到这里的参数传进来的是我们通讯录变量的地址,这里定义了一个 pc 指针去接收。我们首先给结构体中的date数据(date代表多组联系人)进行空间的开辟,我们假设通讯录的通讯的总容量为 3 先开辟 3 个空间,这三个空间的类型都是结构体类型(struct PeoInfo类型),所以开辟空间的总大小,就是个数 x 封装成员基本信息的结构体大小。然后利用malloc函数进行空间 的开辟,因为malloc函数的返回值是void*类型(开辟空间的首地址),我们需要把开辟的这上空间强制转换为我们所需要的结构体指针类型,再赋值给我们 pc 指针指向的 data 空间,这样就完成了空间的开辟。又因为开始没有添加联系人的时候,通讯录是空的,所以这里的 pc 指向的 sz 先把它赋值成 0 ,这里 pc 指向的 capacity 代表通讯录的总容量,我们先把它赋值成 3 之后空间不够,再进行补充。
②.初始化完成后,我们开始实现我们的通讯录的代号为 1 的功能即add(添加联系人)函数的编写
具体代码如下:
void addcontact(struct contact* pc) { //如果通讯录满了 if (pc->sz == pc->capacity) { //增容 struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo)); if (ptr != NULL) { pc->data = https://www.it610.com/article/ptr; pc->capacity += 2; printf("通讯录增容成功\n"); } else { return; } } printf("请输入新增联系人的姓名>"); scanf("%s", pc->data[pc->sz].name); printf("请输入新增联系人的年龄>"); scanf("%d", &pc->data[pc->sz].age); printf("请输入新增联系人的性别>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入新增联系人的电话>"); scanf("%s", pc->data[pc->sz].tel); printf("请输入新增联系人的地址>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; }

代码解析:我们看到这里的参数传进来的是我们通讯录变量的地址,这里定义了一个 pc 指针去接收。进入函数先行判断通讯录满没满,如果没满直接进入到下面的 scanf 和 printf 语句中进行成员基本信息的录入,最后成员数sz+1。如果满了判断的条件就是目前通讯录的 sz 个数等于我们的通讯录的总容量数,这样我们的通讯录就已经存满了。进入到 if 语句中对空间重新分配,这里用到了realloc函数,在realloc函数中传入两个参数,一个是需要进行重新分配的空间,另一个是重新开辟的空间大小,这里的空间我们两个两个的给通讯录增加(避免一次开辟过多对空间造成浪费),我们看到这里的空间在原本的通讯录容量上capacity+2就是给我们的通讯录总容量再开辟两个空间,有了需要开辟的空间个数,我们用个数 x 封装成员基本信息的结构体大小得到的就是我们需要重新开辟的空间大小,.realloc函数开辟空间后返回的是void*(开辟空间的首地址),我们在这里把它强转为我们需要的结构体指针类型,赋值给我们的定义的结构体指针,这里新创建一个指针,不直接赋值给 pc 就是为了防止开辟空间失败,把pc指针置空了,导致pc指针中的数据就清空了,为了防止这样的情况发生,我们先定义一个中间变量存放开辟的空间,然后进入判断如果这里返回的是空指针(NULL),证明空间开辟失败了,直接返回空就可以了。如果开辟的不是空指针(NULL),就把这块开辟的空间赋值给存储多组成员信息的结构体指针,然后对应通讯录的总容量 + 2,并打印一下告知空间开辟成功。
③.功能2:通讯录的删除操作(这里用到了strcmp函数)--->C语言相关字符串库函数用法
具体代码如下:
void delcontact(struct contact* pc) { if (pc->sz == 0) { printf("通讯录为空无法删除\n"); return; } char name[namemax] = { 0 }; printf("请您输入想要删除的联系人姓名>"); scanf("%s", name); int pos = Findname(name, pc); if (pos == -1) { printf("没找到此联系人\n"); } else { int j = 0; for (j = pos; j < pc->sz; j++) { pc->data[j] = pc->data[j + 1]; //所有消息都进行交换 } pc->sz--; printf("该联系人删除成功\n"); } }

因为我们需要查找到对应的成员名字再进行删除
所以我们在这里还需要再编写一个查找名字的函数(该函数在后面的查找联系人,更改联系人中都有用到,因为他们都是通过名字去查找,再进行操作)
int Findname(char* name, struct contact* pc) { int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(name, pc->data[i].name) == 0) { return i; } } return -1; }

我们先看删除函数,我们先进行判断通讯录是不是为空,如果sz为0的情况下,这时候通讯是无法进行删除操作(因为通讯录中没有联系人信息),如果为空就直接返回空。如果通讯录有联系人的信息,我们就定义一个由用户输入的名字,我们用这个名字去进行查找,查找到了就进行删除操作,没有这个名字就直接返回空(即删除操作失败了)。在查找的过程中我们就用到我们的查找函数,我们看到查找函数中的参数一个是用户输入的名字,一个是通讯录现有的成员信息,我们进行循环判断,这里用到了strcmp函数进行字符串比较,如果相等就返回对应这个名字在结构体中的下标位置,如果没有查找到就返回-1。返回到删除函数我们定义一个pos变量对返回值进行接收,然后再进行一次判断,如果是-1代表没有查找到函数返回空,如果不是 -1 证明查找到了该联系人,即可以进行删除操作,从pos(需要进行删除操作的名字位置)位置开始依次把后面的结构体成员信息向前一个赋值,把需要删除的那个成员信息被后面的成员信息覆盖掉即可,最后赋值操作完成后,目前得通讯录人数 -1即完成了我们的删除操作。
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

④.功能三:通讯录的查找操作
具体代码如下:
void searchcontact(struct contact* pc) { char name[namemax] = { 0 }; printf("请您输入想要查找的联系人姓名>"); scanf("%s", name); int pos = Findname(name, pc); if (pos == -1) { printf("没找到此联系人\n"); } else { printf("%-15s\t%5s\t%8s\t%15s\t%30s\t\n\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-15s\t%5d\t%8s\t%15s\t%30s\t\n" , pc->data[pos].name , pc->data[pos].age , pc->data[pos].sex , pc->data[pos].tel , pc->data[pos].addr); }}

查找函数依旧用到了我们的按名字查找函数,在结构体查找到用户输入的名字时,返回对应名字的成员下标,没查找到就返回 -1,返回到查找函数中,进行判断 -1 就是没找到,不是 -1,就证明查找到了该联系人,打印出来对应下标pos的结构体成员变量信息即可。
⑤.功能四:修改指定联系人
具体代码如下:
void modifycontact(struct contact* pc) { char name[namemax] = { 0 }; printf("请您输入想要修改的联系人姓名>"); scanf("%s", name); int pos = Findname(name, pc); if (pos == -1) { printf("没找到此联系人\n"); } else { printf("请输入修改联系人的姓名>"); scanf("%s", pc->data[pos].name); printf("请输入修改联系人的年龄>"); scanf("%d", &pc->data[pos].age); printf("请输入修改联系人的性别>"); scanf("%s", pc->data[pos].sex); printf("请输入修改联系人的电话>"); scanf("%s", pc->data[pos].tel); printf("请输入修改联系人的地址>"); scanf("%s", pc->data[pos].addr); printf("该联系人信息修改成功!!!\n"); } }

在修改指定联系人的代码中我们可以看到,依旧使用到了查找函数,我们使用查找名字函数进行查找用户输入想要更改的联系人是不是在通讯录中,如果不在返回 -1 ,如果在通讯录里面,返回该联系人对应的下标。返回到更改函数中,进行条件判断,如果是 -1 返回空程序结束证明修改功能没能实现。如果返回的不是 -1 就证明该联系人在通讯录里,将他对应的下标结构体信息进行重新的录入即可。
⑤.功能五:展示联系人
具体代码如下:
void showcontact(struct contact* pc) { printf("%-15s\t%5s\t%8s\t%15s\t%30s\t\n\n", "姓名", "年龄", "性别", "电话", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-15s\t%5d\t%8s\t%15s\t%30s\t\n" , pc->data[i].name , pc->data[i].age , pc->data[i].sex , pc->data[i].tel , pc->data[i].addr); }}

在打印信息的上面先定义一行标题,再利用循环,循环条件是小于目前通讯录的人数(pc所指向的sz个数),循环打印出来所有的信息即可
⑥.功能六:按照名字对通讯录进行排序(这里用到了qsort函数)--> qsort函数的用法
具体代码如下:
int cmp_byname(const void* e1, const void* e2) { return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name); } void sortcontact(struct contact* pc) { qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_byname); printf("%-15s\t%5s\t%8s\t%15s\t%30s\t\n\n", "姓名", "年龄", "性别", "电话", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-15s\t%5d\t%8s\t%15s\t%30s\t\n" , pc->data[i].name , pc->data[i].age , pc->data[i].sex , pc->data[i].tel , pc->data[i].addr); } }

看到这里的 qsort 函数第一个参数是需要进行排序的数组名,第二个参数是数组的容量,即我们数组中的人数,第三个参数是数组元素的大小,pc->data代表整个数组,pc->data[0]代表的就是数组的第一个元素,利用 sizeof 即可计算出来数组元素的大小(单位:字节),最后一个参数是我们自定义比较函数的函数名。比较函数中,由于qsort函数对任意类型的元素都可以进行排序,所以里面参数的类型采用的都是 void* 类型(void*类型可以接收任意类型的指针),在比较的时候强制转换我们需要比较的数据类型即可,由于这里需要通过名字进行比较,所以这里用到 strcmp 函数进行比较,如果相等返回 0 ,相异返回 -1/1。排序后循环打印出来排序后的通讯录即可。
⑦.功能零:退出通讯录并销毁通讯录
void destorycontact(struct contact* pc) { free(pc->data); pc->data = https://www.it610.com/article/NULL; pc->sz = 0; pc->capacity = 0; }

这里把刚刚给 pc 所指向的data开辟的空间释放掉这里用到了 free 函数即释放我们刚刚动态开辟的空间,然后把 pc->data 指针置空,最后清空通讯录的人数和总容量即可,综上就完成通讯录的退出与销毁。
四、成果展示 ①.信息录入 + 通讯录增容
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

②.删除联系人 + 展示
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

③.查找指定联系人
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

④.修改指定联系人 + 展示
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

⑤.按名字排序(按照字符的assic码值进行比较的)
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

⑥.退出通讯录
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片



五、代码汇总 ①.contact.h(所需头文件,函数声明,宏的定义)
#pragma once #include #include #include #define namemax 20 #define sexmax 5 #define telemax 12 #define addrmax 30 #define size 3 struct PeoInfo//定义一个联系人基本信息 { char name[namemax]; int age; char sex[sexmax]; char tel[telemax]; char addr[addrmax]; }; //这三个信息组成我们的通讯录 struct contact { struct PeoInfo* data; int sz ; //目前通讯录有几个 int capacity; //通讯录的总容量 }; //函数声明 //初始化通讯录 void initcontact(struct contact* pc); //增加联系人 void addcontact(struct contact* pc); //展示通讯录 void showcontact(struct contact* pc); //删除指定联系人 void delcontact(struct contact* pc); //查找指定联系人 void searchcontact(struct contact* pc); //修改指定联系人 void modifycontact(struct contact* pc); //按名字进行排序 void sortcontact(struct contact* pc); //销毁通讯录 void destorycontact(struct contact* pc);

这里的是函数声明:
C语言实现简易小游戏|C语言----实现动态通讯录
文章图片

②.test.c(测试函数)
#pragma warning(disable : 4996) #include "contact.h" void menu() { printf("**************************************\n"); printf("*1.添加联系人2.删除联系人*\n"); printf("*3.查找联系人4.修改联系人*\n"); printf("*5.展示通讯录6.按名字排序*\n"); printf("*0.退出*\n"); printf("**************************************\n"); } enum OPTION { EXIT, ADD, DEL, SEARCH, MODIFY, SHOW, SORT }; int main() { int input = 0; struct contact con; //创建一个通讯录con变量 initcontact(&con); //初始化通讯录 do { menu(); printf("请选择通讯录功能>"); scanf("%d", &input); switch (input) { case ADD: addcontact(&con); break; case DEL: delcontact(&con); break; case SEARCH: searchcontact(&con); break; case MODIFY: modifycontact(&con); break; case SHOW: showcontact(&con); break; case SORT: sortcontact(&con); break; case EXIT: destorycontact(&con); printf("退出通讯录\n"); break; } } while (input); return 0; }

③.contact.c(功能函数的编写)
#pragma warning(disable : 4996) #include "contact.h" void initcontact(struct contact* pc) { pc->data = https://www.it610.com/article/(struct PeoInfo*)malloc(3 * sizeof(struct PeoInfo)); //动态分配给data一块内存 pc->sz = 0; //初始化时通讯录没人 pc->capacity = size; //假设一开始的通讯录容量为3后面不够用随时增容 } void addcontact(struct contact* pc) { //如果通讯录满了 if (pc->sz == pc->capacity) { //增容 struct PeoInfo* ptr = (struct PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(struct PeoInfo)); if (ptr != NULL) { pc->data = https://www.it610.com/article/ptr; pc->capacity += 2; printf("通讯录增容成功\n"); } else { return; } } printf("请输入新增联系人的姓名>"); scanf("%s", pc->data[pc->sz].name); printf("请输入新增联系人的年龄>"); scanf("%d", &pc->data[pc->sz].age); printf("请输入新增联系人的性别>"); scanf("%s", pc->data[pc->sz].sex); printf("请输入新增联系人的电话>"); scanf("%s", pc->data[pc->sz].tel); printf("请输入新增联系人的地址>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; } void showcontact(struct contact* pc) { printf("%-15s\t%5s\t%8s\t%15s\t%30s\t\n\n", "姓名", "年龄", "性别", "电话", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-15s\t%5d\t%8s\t%15s\t%30s\t\n" , pc->data[i].name , pc->data[i].age , pc->data[i].sex , pc->data[i].tel , pc->data[i].addr); }} int Findname(char* name, struct contact* pc) { int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(name, pc->data[i].name) == 0) { return i; } } return -1; } void delcontact(struct contact* pc) { if (pc->sz == 0) { printf("通讯录为空无法删除\n"); return; } char name[namemax] = { 0 }; printf("请您输入想要删除的联系人姓名>"); scanf("%s", name); int pos = Findname(name, pc); if (pos == -1) { printf("没找到此联系人\n"); } else { int j = 0; for (j = pos; j < pc->sz; j++) { pc->data[j] = pc->data[j + 1]; //所有消息都进行交换 } pc->sz--; printf("该联系人删除成功\n"); } } void searchcontact(struct contact* pc) { char name[namemax] = { 0 }; printf("请您输入想要查找的联系人姓名>"); scanf("%s", name); int pos = Findname(name, pc); if (pos == -1) { printf("没找到此联系人\n"); } else { printf("%-15s\t%5s\t%8s\t%15s\t%30s\t\n\n", "姓名", "年龄", "性别", "电话", "地址"); printf("%-15s\t%5d\t%8s\t%15s\t%30s\t\n" , pc->data[pos].name , pc->data[pos].age , pc->data[pos].sex , pc->data[pos].tel , pc->data[pos].addr); }} void modifycontact(struct contact* pc) { char name[namemax] = { 0 }; printf("请您输入想要修改的联系人姓名>"); scanf("%s", name); int pos = Findname(name, pc); if (pos == -1) { printf("没找到此联系人\n"); } else { printf("请输入修改联系人的姓名>"); scanf("%s", pc->data[pos].name); printf("请输入修改联系人的年龄>"); scanf("%d", &pc->data[pos].age); printf("请输入修改联系人的性别>"); scanf("%s", pc->data[pos].sex); printf("请输入修改联系人的电话>"); scanf("%s", pc->data[pos].tel); printf("请输入修改联系人的地址>"); scanf("%s", pc->data[pos].addr); printf("该联系人信息修改成功!!!\n"); } } int cmp_byname(const void* e1, const void* e2) { return strcmp(((struct PeoInfo*)e1)->name, ((struct PeoInfo*)e2)->name); } void sortcontact(struct contact* pc) { qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_byname); printf("%-15s\t%5s\t%8s\t%15s\t%30s\t\n\n", "姓名", "年龄", "性别", "电话", "地址"); int i = 0; for (i = 0; i < pc->sz; i++) { printf("%-15s\t%5d\t%8s\t%15s\t%30s\t\n" , pc->data[i].name , pc->data[i].age , pc->data[i].sex , pc->data[i].tel , pc->data[i].addr); } } void destorycontact(struct contact* pc) { free(pc->data); pc->data = https://www.it610.com/article/NULL; pc->sz = 0; pc->capacity = 0; }

总结 【C语言实现简易小游戏|C语言----实现动态通讯录】这就是简单通讯录的实现,对C语言很多的知识进行了全面的应用,后面还会对通讯录实现文件的版本,还请持续关注,如果本篇文章存在问题请及时联系博主,或者评论区下方留言,谢谢大家的支持!!

    推荐阅读