且视他人之凝目如盏盏鬼火,大胆的去走你的夜路。 ——史铁生

目录

前言:

一.通讯录的前期准备

1.创建文件

2.菜单的打印

3.枚举的使用

4.以及所需要的头文件

二.通讯录要实现的功能

1.初始化通讯录

2.增加联系人

3.显示联系人

4.删除联系人

5.查找指定的联系人

6.修改指定的联系人

7.使用联系人的名字进行排序

8.测试样例

三.静态通讯录的完整代码

1.test.c:

2.Contact.c:

3.Contact.h

四.优化通讯录

1.将结构体的成员改为指针

2.修改初始化通讯录

3.写一个增容的函数

4.退出程序,释放内存

五.优化版本的完整代码

1.test.c

2.Contact.c

3.Contact.h


前言:

我们需要用C语言模拟一个通讯录可以用来存储100个人的信息
每个人的信息包括:名字、性别、年龄、电话、住址。
功能介绍:
1.增加联系人
2.显示联系人
3.删除联系人
4.查找指定的联系人
5.修改指定的联系人
6.使用联系人的名字进行排序
7.最后退出通讯录,并且销毁通讯录

之前学习了数据结构的顺序表,通讯录就显得很简单了。

一.通讯录的前期准备

1.创建文件

在实现通讯录的时候我们一样是把完整的代码分装为三个文件:

1.test.c:测试通讯录的相关功能

2.Contact.h:函数声明

3.Contact.c:通讯录的实现代码

2.菜单的打印

对于菜单的实现:增加用户对代码的可读性,看到菜单,就能知道通讯录有哪些功能。所以对于有一个菜单来说是很重要的。

菜单的打印:

void menu(){printf("***************************\n");printf("****** 1.Add2.Del *****\n");printf("***** 3.Search 4.Modify ***\n");printf("***** 5.Show 6.Sort *****\n");printf("***** 0.Exit*************\n");printf("***************************\n");}

3.枚举的使用

使用枚举,也是增加我们代码的可读性,看到英文就能知道要实现什么功能。
我们就使用枚举出来的英文来代替case语句里面的数字。

enum option{Exit,//从0开始,依次往下递增1Add,//1Del,//2Search,//3Modify,//4Show,//5Sort//6};int main(){int input = 0;do {menu();printf("请你选择要实现的功能:>\n");scanf("%d", &input);switch (input){case Add:AddContact();break;case Del:DelContact();break;case Search:SearchContact();break;case Modify:ModifyContact();break;case Show:ShowContact();break;case Sort:SortContact();break;case Exit:DestroyContact();printf("退出通讯录\n");break;}} while (input);return 0;}

4.以及所需要的头文件

我们使用宏定义我们

#pragma once#include#include#include#include#define MAX 100#define NAME_MAX 20#define SEX_MAX 5#define TELE_MAX 15#define ADDR_MAX 10//使用结构体存储一个人的信息typedef struct people{char name[NAME_MAX];char sex[SEX_MAX];int age;char tele[TELE_MAX];char addr[ADDR_MAX];}people;typedef struct Contact{people data[MAX];//存储100个人的信息int size;}Contact;

二.通讯录要实现的功能

1.初始化通讯录

第一步:我们使用一个memset函数把data数组里面的每一个字节赋值为0。也就是我们平常说的初始化。

void InitContact(Contact* ps){ps->size = 0;memset(ps->data, 0, sizeof(ps->data));//将data数组里面的每个字节都初始化为0}

2.增加联系人

第二步:我们完成第一步就可以创建关于增加联系人的函数,这个很简单我们只需要访问通讯录结构体里面的数组中的每个元素然后输入对应值就可以了。

void AddContact(Contact* ps){if (ps->size == MAX){printf("通讯录已经满了,不能添加联系人了\n");return;}printf("请你输入你要添加的名字:>");scanf("%s", ps->data[ps->size].name);printf("请你输入性别:>");scanf("%s", ps->data[ps->size].sex);printf("请你输入年龄:>");scanf("%d", &(ps->data[ps->size].age));printf("请你输入电话号码:>");scanf("%s", ps->data[ps->size].tele);printf("请你输入地址:>");scanf("%s", ps->data[ps->size].addr);ps->size++;printf("添加成功\n");}

3.显示联系人

第三步:如果我们选择5,我们把增加了的联系人显示一下,这里注意我们使用%-10s这种,前面的-就是左对齐的意思,10就是占十个空格,这样打印出来会更加好看。

void ShowContact(Contact* ps){int i = 0;printf("%-10s %-5s %-5s %-12s %-30s\n", "名字", "性别", "年龄", "电话", "地址");for (i = 0; i size; i++){printf("%-10s %-5s %-5d %-12s %-30s\n", ps->data[i].name,ps->data[i].sex, ps->data[i].age, ps->data[i].tele, ps->data[i].addr);}}

4.删除联系人

第四步:我们输入要删除的联系人的名字,然后使用strcmp函数来比较,如果找到了,我们的目的就是把他从这个通讯录里面删除,我们使用的方法就是使数组后面的内容全部往前移一位把要删除的联系人给覆盖掉。

这里我们使用到查找联系人,后面查找指定联系人也会用到查找联系人,这里我们就把查找联系人封装为一个函数,每次要使用的时候,我们直接调用这个函数即可。

查找一个联系人的函数:

int FindByname(Contact* ps, char name[]){int i = 0;for (i = 0; i size; i++)//使用一个for循环遍历整个数组{if (0==strcmp(name, ps->data[i].name))//strcmp的返回值是0就说明找到了{return i;}}return -1;//没找到就返回-1}

删除联系人的函数:

void DelContact(Contact* ps){char name[NAME_MAX] = { 0 };if (ps->size == 0){printf("通讯录为空,无法删除\n");return;}printf("请你输入要删除联系人的名字:>");scanf("%s", name);int pos = FindByname(ps, name);if (pos == -1){printf("你要删除的人不存在\n");return;}int i = 0;for (i = pos; i size - 1; i++){ps->data[i] = ps->data[i + 1];}ps->size--;printf("删除成功\n");}

5.查找指定的联系人

查找指定的联系人和删除联系人所实现的代码其实是差不多的,都要调用查找函数。输入你要查找联系人的名字,再使用一个for循环来遍历整个数组,如果发现你要查找的人在数组中找到了,就返回他的下标。最后再使用下标,把找到的联系人给打印出来

void SearchContact(Contact* ps){char name[NAME_MAX] = { 0 };printf("输入你要查找联系人的名字:>");scanf("%s", name);int pos= FindByname(ps, name);if (pos == -1){printf("你要查找的联系人不存在\n");return;}printf("这是你要查找的人:>\n");printf("%-10s %-5s %-5s %-12s %-30s\n", "名字", "性别", "年龄", "电话", "地址");printf("%-10s %-5s %-5d %-12s %-30s\n", ps->data[pos].name,ps->data[pos].sex, ps->data[pos].age, ps->data[pos].tele, ps->data[pos].addr);}

6.修改指定的联系人

这也是很简单的,这就和前面的内容大致不差。

void ModifyContact(Contact* ps){char name[NAME_MAX] = { 0 };printf("输入你要修改联系人的名字\n");scanf("%s", name);int pos = FindByname(ps, name);if (pos == -1){printf("你要修改的人不存在\n");return;}printf("请你输入你要添加的名字:>");scanf("%s", ps->data[pos].name);printf("请你输入性别:>");scanf("%s", ps->data[pos].sex);printf("请你输入年龄:>");scanf("%d", &(ps->data[pos].age));printf("请你输入电话号码:>");scanf("%s", ps->data[pos].tele);printf("请你输入地址:>");scanf("%s", ps->data[pos].addr);printf("修改成功\n");}

7.使用联系人的名字进行排序

这里排序我们使用qsort排序,也就是快排,对联系人的名字进行排序。

void cmp_name(void* p1, void* p2){return strcmp(((people*)p1)->name, ((people*)p2)->name);}//对联系人名字进行排序void SortContact(Contact* ps){qsort(ps->data, ps->size, sizeof(people), cmp_name);}

8.测试样例

三.静态通讯录的完整代码

1.test.c:

#define _CRT_SECURE_NO_WARNINGS 1#include"Contact.h"void menu(){printf("***************************\n");printf("****** 1.Add2.Del *****\n");printf("***** 3.Search 4.Modify ***\n");printf("***** 5.Show 6.Sort *****\n");printf("***** 0.Exit*************\n");printf("***************************\n");}enum option{Exit,//从0开始,依次往下递增1Add,Del,Search,Modify,Show,Sort};int main(){int input = 0;Contact con;InitContact(&con);do {menu();printf("请你选择要实现的功能:>\n");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:printf("退出通讯录\n");break;}} while (input);return 0;}

2.Contact.c:

#define _CRT_SECURE_NO_WARNINGS 1#include"Contact.h"//初始化通讯录void InitContact(Contact* ps){ps->size = 0;memset(ps->data, 0, sizeof(ps->data));}//增加联系人void AddContact(Contact* ps){if (ps->size == MAX){printf("通讯录已经满了,不能添加联系人了\n");return;}printf("请你输入你要添加的名字:>");scanf("%s", ps->data[ps->size].name);printf("请你输入性别:>");scanf("%s", ps->data[ps->size].sex);printf("请你输入年龄:>");scanf("%d", &(ps->data[ps->size].age));printf("请你输入电话号码:>");scanf("%s", ps->data[ps->size].tele);printf("请你输入地址:>");scanf("%s", ps->data[ps->size].addr);ps->size++;printf("添加成功\n");}//显示联系人void ShowContact(Contact* ps){int i = 0;printf("%-10s %-5s %-5s %-12s %-30s\n", "名字", "性别", "年龄", "电话", "地址");for (i = 0; i size; i++){printf("%-10s %-5s %-5d %-12s %-30s\n", ps->data[i].name,ps->data[i].sex, ps->data[i].age, ps->data[i].tele, ps->data[i].addr);}}//查找联系人int FindByname(Contact* ps, char name[]){int i = 0;for (i = 0; i size; i++){if (0==strcmp(name, ps->data[i].name)){return i;}}return -1;}//删除联系人void DelContact(Contact* ps){char name[NAME_MAX] = { 0 };if (ps->size == 0){printf("通讯录为空,无法删除\n");return;}printf("请你输入要删除联系人的名字:>");scanf("%s", name);int pos = FindByname(ps, name);if (pos == -1){printf("你要删除的人不存在\n");return;}int i = 0;for (i = pos; i size - 1; i++){ps->data[i] = ps->data[i + 1];}ps->size--;printf("删除成功\n");}//查找联系人void SearchContact(Contact* ps){char name[NAME_MAX] = { 0 };printf("输入你要查找联系人的名字:>");scanf("%s", name);int pos= FindByname(ps, name);if (pos == -1){printf("你要查找的联系人不存在\n");return;}printf("这是你要查找的人:>\n");printf("%-10s %-5s %-5s %-12s %-30s\n", "名字", "性别", "年龄", "电话", "地址");printf("%-10s %-5s %-5d %-12s %-30s\n", ps->data[pos].name,ps->data[pos].sex, ps->data[pos].age, ps->data[pos].tele, ps->data[pos].addr);}//修改联系人void ModifyContact(Contact* ps){char name[NAME_MAX] = { 0 };printf("输入你要修改联系人的名字\n");scanf("%s", name);int pos = FindByname(ps, name);if (pos == -1){printf("你要修改的人不存在\n");return;}printf("请你输入你要添加的名字:>");scanf("%s", ps->data[pos].name);printf("请你输入性别:>");scanf("%s", ps->data[pos].sex);printf("请你输入年龄:>");scanf("%d", &(ps->data[pos].age));printf("请你输入电话号码:>");scanf("%s", ps->data[pos].tele);printf("请你输入地址:>");scanf("%s", ps->data[pos].addr);printf("修改成功\n");}void cmp_name(void* p1, void* p2){return strcmp(((people*)p1)->name, ((people*)p2)->name);}//对联系人名字进行排序void SortContact(Contact* ps){qsort(ps->data, ps->size, sizeof(people), cmp_name);int i = 0;}

3.Contact.h

#pragma once#include#include#include#include#define MAX 100#define NAME_MAX 20#define SEX_MAX 5#define TELE_MAX 15#define ADDR_MAX 10//使用结构体存储一个人的信息typedef struct people{char name[NAME_MAX];char sex[SEX_MAX];int age;char tele[TELE_MAX];char addr[ADDR_MAX];}people;typedef struct Contact{people data[MAX];//存储100个人的信息int size;}Contact;//初始化通讯录void InitContact(Contact* ps);//增加联系人void AddContact(Contact* ps);//显示联系人void ShowContact(Contact* ps);//删除联系人void DelContact(Contact* ps);//查找联系人void SearchContact(Contact* ps);//修改联系人void ModifyContact(Contact* ps);//对联系人名字进行排序void SortContact(Contact* ps); 

四.优化通讯录

上面我们们写的静态通讯录,只有100个容量,当我们的联系人很少的时候,100个容量又太大了,很浪费空间。当联系人的人数超过100个人时,通讯录的容量又不够

所以我们可以优化通讯录,把静态通讯录修改为动态通讯录,这里我们就使用动态内存开辟的开辟,空间不够了,它会自动开辟空间。也不会浪费空间

1.将结构体的成员改为指针

typedef struct Contact{people *data;//创建的动态数组int size;//存放数据的个数int Capacity;//动态数组的容量的大小}Contact;

2.修改初始化通讯录

我们使用malloc函数来动态开辟空间,这里会用到两个宏定义

#define INC_SZ 2//不够了新开辟2个空间#define INI_MAX 3//初始化的3个空间
void InitContact(Contact* ps){ps->data = (people*)malloc(sizeof(people) * INI_MAX);if (ps->data == NULL){printf("初始化通讯录失败:%s", strerror(errno));//打印错误的信息return;}ps->size = 0;ps->Capacity = INI_MAX;}

3.写一个增容的函数

因为我们初始化通讯录时,容量的大小是3,在我们在增加联系人的时候,增加了三个联系人之后,通讯录容量就满了,所以我们就要增容,而每次增容的量是两个。

这里我们使用realloc函数在原有的基础上,再开辟两个空间。

在我们要使用增加联系人的函数的时候,在函数的最前面调用一下增容函数即可。

void CheckCapaticy(Contact* ps){if (ps->size == ps->Capacity){people* ptr = realloc(ps->data, sizeof(people) * (ps->Capacity + INC_SZ));if (ptr == NULL){printf("CheckCapacity:%s", strerror(errno));return;}else{ps->data = ptr;ps->Capacity += INC_SZ;printf("增容成功,容量是%s", ps->Capacity);}}}

4.退出程序,释放内存

上面我们使用了malloc函数和realloc函数,所以最后我们要释放内存。

void DestoryContact(Contact* ps){free(ps->data);ps->data = NULL;ps->size = 0;ps->Capacity = 0;printf("内存已经销毁……\n");}

五.优化版本的完整代码

1.test.c

#define _CRT_SECURE_NO_WARNINGS 1#include"Contact.h"void menu(){printf("***************************\n");printf("****** 1.Add2.Del *****\n");printf("***** 3.Search 4.Modify ***\n");printf("***** 5.Show 6.Sort *****\n");printf("***** 0.Exit*************\n");printf("***************************\n");}enum option{Exit,//从0开始,依次往下递增1Add,Del,Search,Modify,Show,Sort};int main(){int input = 0;Contact con;InitContact(&con);do {menu();printf("请你选择要实现的功能:>\n");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;}

2.Contact.c

#define _CRT_SECURE_NO_WARNINGS 1#include"Contact.h"//初始化通讯录void InitContact(Contact* ps){ps->data = (people*)malloc(sizeof(people) * INI_MAX);if (ps->data == NULL){printf("初始化通讯录失败:%s", strerror(errno));return;}ps->size = 0;ps->Capacity = INI_MAX;}//检查容量void CheckCapaticy(Contact* ps){if (ps->size == ps->Capacity){people* ptr = realloc(ps->data, sizeof(people) * (ps->Capacity + INC_SZ));if (ptr == NULL){printf("CheckCapacity:%s", strerror(errno));return;}else{ps->data = ptr;ps->Capacity += INC_SZ;printf("增容成功,容量是%d\n", ps->Capacity);}}}//增加联系人void AddContact(Contact* ps){CheckCapaticy(ps);printf("请你输入你要添加的名字:>");scanf("%s", ps->data[ps->size].name);printf("请你输入性别:>");scanf("%s", ps->data[ps->size].sex);printf("请你输入年龄:>");scanf("%d", &(ps->data[ps->size].age));printf("请你输入电话号码:>");scanf("%s", ps->data[ps->size].tele);printf("请你输入地址:>");scanf("%s", ps->data[ps->size].addr);ps->size++;printf("添加成功\n");}//显示联系人void ShowContact(Contact* ps){int i = 0;printf("%-10s %-5s %-5s %-12s %-30s\n", "名字", "性别", "年龄", "电话", "地址");for (i = 0; i size; i++){printf("%-10s %-5s %-5d %-12s %-30s\n", ps->data[i].name,ps->data[i].sex, ps->data[i].age, ps->data[i].tele, ps->data[i].addr);}}//查找联系人int FindByname(Contact* ps, char name[]){int i = 0;for (i = 0; i size; i++){if (0==strcmp(name, ps->data[i].name)){return i;}}return -1;}//删除联系人void DelContact(Contact* ps){char name[NAME_MAX] = { 0 };if (ps->size == 0){printf("通讯录为空,无法删除\n");return;}printf("请你输入要删除联系人的名字:>");scanf("%s", name);int pos = FindByname(ps, name);if (pos == -1){printf("你要删除的人不存在\n");return;}int i = 0;for (i = pos; i size - 1; i++){ps->data[i] = ps->data[i + 1];}ps->size--;printf("删除成功\n");}//查找联系人void SearchContact(Contact* ps){char name[NAME_MAX] = { 0 };printf("输入你要查找联系人的名字:>");scanf("%s", name);int pos= FindByname(ps, name);if (pos == -1){printf("你要查找的联系人不存在\n");return;}printf("这是你要查找的人:>\n");printf("%-10s %-5s %-5s %-12s %-30s\n", "名字", "性别", "年龄", "电话", "地址");printf("%-10s %-5s %-5d %-12s %-30s\n", ps->data[pos].name,ps->data[pos].sex, ps->data[pos].age, ps->data[pos].tele, ps->data[pos].addr);}//修改联系人void ModifyContact(Contact* ps){char name[NAME_MAX] = { 0 };printf("输入你要修改联系人的名字\n");scanf("%s", name);int pos = FindByname(ps, name);if (pos == -1){printf("你要修改的人不存在\n");return;}printf("请你输入你要添加的名字:>");scanf("%s", ps->data[pos].name);printf("请你输入性别:>");scanf("%s", ps->data[pos].sex);printf("请你输入年龄:>");scanf("%d", &(ps->data[pos].age));printf("请你输入电话号码:>");scanf("%s", ps->data[pos].tele);printf("请你输入地址:>");scanf("%s", ps->data[pos].addr);printf("修改成功\n");}void cmp_name(void* p1, void* p2){return strcmp(((people*)p1)->name, ((people*)p2)->name);}//对联系人名字进行排序void SortContact(Contact* ps){qsort(ps->data, ps->size, sizeof(people), cmp_name);}void DestoryContact(Contact* ps){free(ps->data);ps->data = NULL;ps->size = 0;ps->Capacity = 0;printf("内存已经销毁……\n");}

3.Contact.h

#pragma once#include#include#include#include#define NAME_MAX 20#define SEX_MAX 5#define TELE_MAX 15#define ADDR_MAX 10#define INC_SZ 2#define INI_MAX 3//使用结构体存储一个人的信息typedef struct people{char name[NAME_MAX];char sex[SEX_MAX];int age;char tele[TELE_MAX];char addr[ADDR_MAX];}people;typedef struct Contact{people *data;//创建的动态数组int size;//存放数据的个数int Capacity;//动态数组的容量的大小}Contact;//初始化通讯录void InitContact(Contact* ps);//增加联系人void AddContact(Contact* ps);//显示联系人void ShowContact(Contact* ps);//删除联系人void DelContact(Contact* ps);//查找联系人void SearchContact(Contact* ps);//修改联系人void ModifyContact(Contact* ps);//对联系人名字进行排序void SortContact(Contact* ps); //退出程序,销毁内存void DestoryContact(Contact* ps);