目录
相信大家对通讯录很熟悉,通讯录在我们日常生活中经常被用到,比如我们手机联系人通讯录,微信通讯录等,那通讯录可以用C语言来实现吗?答案是肯定的!在实现通讯录时,我们主要用到的知识有结构体、指针、动态内存开辟,文件操作等方面的知识。经过通讯录这样一个小实战项目的练习,相信大家一定会对C语言的知识理解地更加深刻,那么接下来,让我们对如何用C语言实现通讯录一探究竟吧~
- void menu()
- {
- printf("*************************\n");
- printf("**** 1.add 2.del *****\n");
- printf("**** 3.src 4.mod *****\n");
- printf("**** 5.sort 6.show *****\n");
- printf("**** 0.exit *****\n");
- printf("*************************\n");
- }
这是通讯录的选择菜单,提示用户输入数字来选择不同的功能。
在写主函数之前,我们考虑到待会用switch case语句来实现分支选择,通过输入0-6来不同操作,那么我们不妨把0-6这七个数字写成一个枚举常量,以便我们对这7个数字的含义一眼就能看出来。
我们另外创建contact.h这个头文件,用以存放函数声明、结构体和常量声明、枚举等,我们在contact.h这个文件里创建我们刚才所说的枚举类型。
- enum OPTION
- {
- EXIT,//0
- ADD,//1
- DELETE,//2
- SEARCH,//3
- MODIFY,//4
- SORT,//5
- SHOW//6
- };
创建好枚举类型之后,需要才test.c文件中包含contact.h头文件才可以使用枚举常量。我们的main函数就可以写成这个样子:
- int main()
- {
- int input = 0;
- Contact con = { 0 };
- InitContact(&con);
- do
- {
- menu();
- printf("请输入你的选择:>");
- scanf("%d",&input);
- switch (input)
- {
- case ADD:
- AddContact(&con);
- break;
- case DELETE:
- DelContact(&con);
- break;
- case SEARCH:
- FindContact(&con);
- break;
- case MODIFY:
- ModifyContact(&con);
- break;
- case SORT:
- SortContact(&con);
- break;
- case SHOW:
- ShowContact(&con);
- break;
- case EXIT:
- SaveContact(&con);
- DestoryContact(&con);
- printf("退出通讯录\n");
- break;
- default:
- printf("输入错误,请重新选择\n");
- break;
- }
- } while (input);
-
- return 0;
- }
看到这里,大家只需要先明白大体框架就可以,关于其中一些函数的细节我之后会说。
到这里我们可能会想到,我待会要存放的联系人的信息存放到哪里呢?联系人的信息一般有姓名、年龄、性别、电话、地址等,那么我们自然而然想到结构体类型,因此,在contact.h这个头文件中,我们需要先创建PeoInfo这样一个结构体类型:
- typedef struct PeoInfo
- {
- char name[NAME_MAX];
- int age;
- char sex[SEX_MAX];
- char tele[TELE_MAX];
- char addr[ADDR_MAX];
- }PeoInfo;
对于结构体成员的大小,之后可能会多出用到,同时为了方便修改,我们将其用#define定义:
- #define NAME_MAX 20
- #define SEX_MAX 5
- #define TELE_MAX 15
- #define ADDR_MAX 20
到这里,我们再想一想,我们应该创建一个PeoInfo这个结构体类型的数组吧,yes,以此来存放多个联系人的信息。那么我们也应该有一个变量来记录当前结构体已经存放联系人的数量,以及这个结构体类型数组中最多能存放多少个联系人的信息,因此创建了这样一个结构体Contact:
- typedef struct Contact
- {
- PeoInfo* data;
- int sz;//记录当前结构体成员个数
- int capacity;//容量
- }Contact;
其中的PeoInfo* data这个结构体类型指针用于待会的动态内存开辟,待会会说到这个。
在主程序中,我们首先创建了一个结构体类型的变量con并初始化为0:
Contact con = { 0 };
接下来要用InitContact函数来初始化通讯录:
InitContact(&con);
InitContact这个函数这样实现:
- void InitContact(Contact* pc)
- {
- assert(pc);
- pc->data = (PeoInfo*)calloc(MAX, sizeof(PeoInfo));
- if (pc->data == NULL)
- {
- perror("calloc");
- return;
- }
- pc->sz = 0;
- pc->capacity = MAX;
- LoadContact(pc);
- }
在这个初始化函数中,用到了calloc函数动态开辟内存:
其中,MAX为初始通讯录最大容量:
#define MAX 3
InitContact这个函数中最后这个函数LoadContact是用来加载之前存放在内存中的数据:
- void LoadContact(Contact* pc)
- {
- FILE* pf = fopen("contact.dat", "rb");
- if (pf == NULL)
- {
- perror("LoadContact");
- return;
- }
- PeoInfo tmp = { 0 };
- while (fread(&tmp, sizeof(PeoInfo), 1, pf))
- {
- CheckCapacity(pc);
- pc->data[pc->sz] = tmp;
- pc->sz++;
- }
- fclose(pf);
- pf = NULL;
- }
CheckCapacity这个函数是用来检查通讯录容量是否够,不够则增加:
- int CheckCapacity(Contact* pc)
- {
- if (pc->sz == pc->capacity)
- {
- PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_NUM) * sizeof(PeoInfo));
- if (ptr == NULL)
- {
- perror("CheckCapacity");
- return 0;
- }
- else
- {
- pc->data = ptr;
- pc->capacity += INC_NUM;
- printf("扩容成功\n");
- }
-
- }
- return 1;
- }
接下来就是AddContact这个函数的实现:
- void AddContact(Contact* pc)
- {
- assert(pc);
- if (0 == CheckCapacity(pc))
- {
- printf("增容失败\n");
- 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].tele));
- printf("请输入联系人的地址:>");
- scanf("%s", &((pc->data)[pc->sz].addr));
-
- pc->sz++;
- printf("成功添加联系人\n");
-
- }
再增加完联系人后,我们想要打印出来通讯录看看效果:
- void ShowContact(Contact* pc)
- {
- assert(pc);
- if (pc->sz == 0)
- {
- printf("通讯录为空,无需展示\n");
- return;
- }
- printf("%-10s%-10s%-5s%-15s%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
- int i = 0;
- for (i = 0; i < pc->sz; i++)
- {
- printf("%-10s%-10d%-5s%-15s%-10s\n",
- (pc->data[i]).name,
- (pc->data[i].age),
- (pc->data[i]).sex,
- (pc->data[i]).tele,
- (pc->data[i]).addr);
- }
-
- }
那么我们如何删除联系人呢?首先要找到要删除联系人的位置,然后将其之后的成员全部前移,这样要删除的成员就会被覆盖:
- //查找联系人
- static int SearchContact(Contact* pc,char* name)
- {
- int i = 0;
- for (i = 0; i < pc->sz; i++)
- {
- if (strcmp(pc->data[i].name, name) == 0)
- {
- return i;
- }
- }
- return -1;//没找到返回-1
- }
- //删除联系人
- void DelContact(Contact* pc)
- {
- assert(pc);
- if (pc->sz == 0)
- {
- printf("通讯录为空,无需删除\n");
- return;
- }
- char name[NAME_MAX];
- printf("请输入要删除联系人的名字:>");
- scanf("%s",name);
- //查找联系人
- int ret = SearchContact(pc, name);
- if (ret == -1)
- {
- printf("要删除的联系人不存在\n");
- return;
- }
- //删除
- int i = 0;
- for (i = ret; i < (pc->sz)-1; i++)
- {
- pc->data[i] = pc->data[i + 1];
- }
-
- pc->sz--;
- printf("成功删除联系人\n");
-
- }
那么我么想要查找某个联系人怎么办呢?其实在删除联系人也用到了查找联系人:
-
- //查找联系人
- void FindContact(Contact* pc)
- {
- assert(pc);
- char name[NAME_MAX];
- printf("请输入要删除联系人的名字:>");
- scanf("%s", name);
- //查找联系人
- int ret = SearchContact(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- return;
- }
- printf("%-10s%-10s%-5s%-15s%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
- printf("%-10s%-10d%-5s%-15s%-10s\n",
- (pc->data[ret]).name,
- (pc->data[ret].age),
- (pc->data[ret]).sex,
- (pc->data[ret]).tele,
- (pc->data[ret]).addr);
-
- }
那么我们怎么修改联系人的信息呢
- //修改联系人
- void ModifyContact(Contact* pc)
- {
- assert(pc);
- if (pc->sz == 0)
- {
- printf("通讯录为空,无需修改\n");
- return;
- }
- char name[NAME_MAX];
- printf("请输入要修改联系人的姓名:>");
- scanf("%s", name);
- //查找联系人
- int ret = SearchContact(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- return;
- }
-
- printf("请输入联系人的姓名:>");
- scanf("%s", (pc->data)[ret].name);
- printf("请输入联系人的年龄:>");
- scanf("%d", &((pc->data[ret]).age));
- printf("请输入联系人的性别:>");
- scanf("%s", &((pc->data)[ret].sex));
- printf("请输入联系人的电话:>");
- scanf("%s", &((pc->data)[ret].tele));
- printf("请输入联系人的地址:>");
- scanf("%s", &((pc->data)[ret].addr));
-
- printf("成功修改联系人\n");
- }
我们也想对通讯录进行排序:
- //排序联系人
- int cmp_by_name(const void* p1, const void* p2)
- {
- return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
- }
- int cmp_by_age(const void* p1, const void* p2)
- {
- return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age;
- }
- void SortContact(Contact* pc)
- {
- assert(pc);
- if (pc->sz == 0)
- {
- printf("通讯录为空,无需排序\n");
- return;
- }
- int opt = 0;
- printf("您希望按什么排序(1.按姓名 2.按年龄):>");
- scanf("%d", &opt);
- if (opt == 1)
- {
- qsort(pc->data,pc->sz,sizeof(PeoInfo),cmp_by_name);
- printf("已为您按姓名升序排好\n");
- }
- else
- {
- qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_age);
- printf("已为您按年龄序排好\n");
- }
- }
在退出通讯录时,我们需要销毁通讯录:
- //销毁通讯录
- void DestoryContact(Contact* pc)
- {
- assert(pc);
- free(pc->data);
- pc->data = 0;
- pc->capacity = 0;
-
- }
在退出通讯录时,我们也需要保存通讯录:
- //保存通讯录
- void SaveContact(Contact* pc)
- {
- FILE* pf = fopen("contact.dat", "wb");
- if (pf == NULL)
- {
- perror("SaveContact");
- return;
- }
- Contact tmp = { 0 };
- int i = 0;
- for (i = 0; i < pc->sz; i++)
- {
- fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
- }
-
- //关闭文件
- fclose(pf);
- pf = NULL;
- }
这就是通讯录实现的整个流程了,希望对大家有帮助哦
test.c
- #define _CRT_SECURE_NO_WARNINGS 1
- #include "contact.h"
-
- void menu()
- {
- printf("*************************\n");
- printf("**** 1.add 2.del *****\n");
- printf("**** 3.src 4.mod *****\n");
- printf("**** 5.sort 6.show *****\n");
- printf("**** 0.exit *****\n");
- printf("*************************\n");
- }
-
- int main()
- {
- int input = 0;
- Contact con = { 0 };
- InitContact(&con);
- do
- {
- menu();
- printf("请输入你的选择:>");
- scanf("%d",&input);
- switch (input)
- {
- case ADD:
- AddContact(&con);
- break;
- case DELETE:
- DelContact(&con);
- break;
- case SEARCH:
- FindContact(&con);
- break;
- case MODIFY:
- ModifyContact(&con);
- break;
- case SORT:
- SortContact(&con);
- break;
- case SHOW:
- ShowContact(&con);
- break;
- case EXIT:
- SaveContact(&con);
- DestoryContact(&con);
- printf("退出通讯录\n");
- break;
- default:
- printf("输入错误,请重新选择\n");
- break;
- }
- } while (input);
-
- return 0;
- }
contact.h
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <string.h>
-
- enum OPTION
- {
- EXIT,//0
- ADD,//1
- DELETE,//2
- SEARCH,//3
- MODIFY,//4
- SORT,//5
- SHOW//6
- };
-
- #define NAME_MAX 20
- #define SEX_MAX 5
- #define TELE_MAX 15
- #define ADDR_MAX 20
- #define DATA_MAX 100
- #define MAX 3
- #define INC_NUM 2
- //通讯录
- typedef struct PeoInfo
- {
- char name[NAME_MAX];
- int age;
- char sex[SEX_MAX];
- char tele[TELE_MAX];
- char addr[ADDR_MAX];
- }PeoInfo;
-
- //静态
- //typedef struct Contact
- //{
- // PeoInfo data[DATA_MAX];
- // int sz;//记录当前结构体成员个数
- //}Contact;
- //动态
- typedef struct Contact
- {
- PeoInfo* data;
- int sz;//记录当前结构体成员个数
- int capacity;//容量
- }Contact;
-
- //初始化通讯录
- void InitContact(Contact* pc);
-
- //增加联系人
- void AddContact(Contact* pc);
-
- //展示通讯录
- void ShowContact(Contact* pc);
-
- //删除联系人
- void DelContact(Contact* pc);
-
- //查找联系人
- void FindContact(Contact* pc);
-
- //修改联系人
- void ModifyContact(Contact* pc);
-
- //排序
- void SortContact(Contact* pc);
-
- //销毁
- void DestoryContact(Contact* pc);
-
- //保存通讯录
- void SaveContact(Contact* pc);
contact.c
- #define _CRT_SECURE_NO_WARNINGS 1
- #include "contact.h"
-
- 初始化通讯录
- //void InitContact(Contact* pc)
- //{
- // assert(pc);
- // memset(pc->data, 0, sizeof(PeoInfo) * DATA_MAX);
- // pc->sz = 0;
- //}
-
- 动态初始化通讯录
- //void InitContact(Contact* pc)
- //{
- // assert(pc);
- // pc->data = (PeoInfo*)calloc(MAX, sizeof(PeoInfo));
- // if (pc->data == NULL)
- // {
- // perror("calloc");
- // return;
- // }
- // pc->sz = 0;
- // pc->capacity = MAX;
- //}
- int CheckCapacity(Contact* pc);
- void LoadContact(Contact* pc)
- {
- FILE* pf = fopen("contact.dat", "rb");
- if (pf == NULL)
- {
- perror("LoadContact");
- return;
- }
- PeoInfo tmp = { 0 };
- while (fread(&tmp, sizeof(PeoInfo), 1, pf))
- {
- CheckCapacity(pc);
- pc->data[pc->sz] = tmp;
- pc->sz++;
- }
- fclose(pf);
- pf = NULL;
- }
- //动态加载初始化通讯录
- void InitContact(Contact* pc)
- {
- assert(pc);
- pc->data = (PeoInfo*)calloc(MAX, sizeof(PeoInfo));
- if (pc->data == NULL)
- {
- perror("calloc");
- return;
- }
- pc->sz = 0;
- pc->capacity = MAX;
- LoadContact(pc);
- }
-
- //增加联系人
- //void AddContact(Contact* pc)
- //{
- // assert(pc);
- //
- // //通讯录满了
- // if (pc->sz == DATA_MAX)
- // {
- // printf("通讯录已满,无法增加\n");
- // 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].tele));
- // printf("请输入联系人的地址:>");
- // scanf("%s", &((pc->data)[pc->sz].addr));
- //
- // pc->sz++;
- // printf("成功添加联系人\n");
- //
- //}
-
- int CheckCapacity(Contact* pc)
- {
- if (pc->sz == pc->capacity)
- {
- PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_NUM) * sizeof(PeoInfo));
- if (ptr == NULL)
- {
- perror("CheckCapacity");
- return 0;
- }
- else
- {
- pc->data = ptr;
- pc->capacity += INC_NUM;
- printf("扩容成功\n");
- }
-
- }
- return 1;
- }
-
- void AddContact(Contact* pc)
- {
- assert(pc);
- if (0 == CheckCapacity(pc))
- {
- printf("增容失败\n");
- 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].tele));
- printf("请输入联系人的地址:>");
- scanf("%s", &((pc->data)[pc->sz].addr));
-
- pc->sz++;
- printf("成功添加联系人\n");
-
- }
-
- //展示通讯录
- void ShowContact(Contact* pc)
- {
- assert(pc);
- if (pc->sz == 0)
- {
- printf("通讯录为空,无需展示\n");
- return;
- }
- printf("%-10s%-10s%-5s%-15s%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
- int i = 0;
- for (i = 0; i < pc->sz; i++)
- {
- printf("%-10s%-10d%-5s%-15s%-10s\n",
- (pc->data[i]).name,
- (pc->data[i].age),
- (pc->data[i]).sex,
- (pc->data[i]).tele,
- (pc->data[i]).addr);
- }
-
- }
- //查找联系人
- static int SearchContact(Contact* pc,char* name)
- {
- int i = 0;
- for (i = 0; i < pc->sz; i++)
- {
- if (strcmp(pc->data[i].name, name) == 0)
- {
- return i;
- }
- }
- return -1;//没找到返回-1
- }
-
- //删除联系人
- void DelContact(Contact* pc)
- {
- assert(pc);
- if (pc->sz == 0)
- {
- printf("通讯录为空,无需删除\n");
- return;
- }
- char name[NAME_MAX];
- printf("请输入要删除联系人的名字:>");
- scanf("%s",name);
- //查找联系人
- int ret = SearchContact(pc, name);
- if (ret == -1)
- {
- printf("要删除的联系人不存在\n");
- return;
- }
- //删除
- int i = 0;
- for (i = ret; i < (pc->sz)-1; i++)
- {
- pc->data[i] = pc->data[i + 1];
- }
-
- pc->sz--;
- printf("成功删除联系人\n");
-
- }
-
- //查找联系人
- void FindContact(Contact* pc)
- {
- assert(pc);
- char name[NAME_MAX];
- printf("请输入要删除联系人的名字:>");
- scanf("%s", name);
- //查找联系人
- int ret = SearchContact(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- return;
- }
- printf("%-10s%-10s%-5s%-15s%-10s\n", "姓名", "年龄", "性别", "电话", "地址");
- printf("%-10s%-10d%-5s%-15s%-10s\n",
- (pc->data[ret]).name,
- (pc->data[ret].age),
- (pc->data[ret]).sex,
- (pc->data[ret]).tele,
- (pc->data[ret]).addr);
-
- }
-
- //修改联系人
- void ModifyContact(Contact* pc)
- {
- assert(pc);
- if (pc->sz == 0)
- {
- printf("通讯录为空,无需修改\n");
- return;
- }
- char name[NAME_MAX];
- printf("请输入要修改联系人的姓名:>");
- scanf("%s", name);
- //查找联系人
- int ret = SearchContact(pc, name);
- if (ret == -1)
- {
- printf("要查找的联系人不存在\n");
- return;
- }
-
- printf("请输入联系人的姓名:>");
- scanf("%s", (pc->data)[ret].name);
- printf("请输入联系人的年龄:>");
- scanf("%d", &((pc->data[ret]).age));
- printf("请输入联系人的性别:>");
- scanf("%s", &((pc->data)[ret].sex));
- printf("请输入联系人的电话:>");
- scanf("%s", &((pc->data)[ret].tele));
- printf("请输入联系人的地址:>");
- scanf("%s", &((pc->data)[ret].addr));
-
- printf("成功修改联系人\n");
- }
-
- //排序联系人
- int cmp_by_name(const void* p1, const void* p2)
- {
- return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
- }
- int cmp_by_age(const void* p1, const void* p2)
- {
- return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age;
- }
- void SortContact(Contact* pc)
- {
- assert(pc);
- if (pc->sz == 0)
- {
- printf("通讯录为空,无需排序\n");
- return;
- }
- int opt = 0;
- printf("您希望按什么排序(1.按姓名 2.按年龄):>");
- scanf("%d", &opt);
- if (opt == 1)
- {
- qsort(pc->data,pc->sz,sizeof(PeoInfo),cmp_by_name);
- printf("已为您按姓名升序排好\n");
- }
- else
- {
- qsort(pc->data, pc->sz, sizeof(PeoInfo), cmp_by_age);
- printf("已为您按年龄序排好\n");
- }
- }
-
- //销毁通讯录
- void DestoryContact(Contact* pc)
- {
- assert(pc);
- free(pc->data);
- pc->data = 0;
- pc->capacity = 0;
-
- }
-
- //保存通讯录
- void SaveContact(Contact* pc)
- {
- FILE* pf = fopen("contact.dat", "wb");
- if (pf == NULL)
- {
- perror("SaveContact");
- return;
- }
- Contact tmp = { 0 };
- int i = 0;
- for (i = 0; i < pc->sz; i++)
- {
- fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
- }
-
- //关闭文件
- fclose(pf);
- pf = NULL;
- }