c语言通讯录实现
我们可以先想一下通讯录的信息包含有哪些
姓名 年龄 性别 地址 手机号…等(我们可以额外增加其他的内容)
通讯录的一些功能实现如:增加联系人、修改联系人、查看联系人、整理联系人(由首字母开始向后)、查找联系人和删除联系人
首先我们需要创建三个文件进行整理
test.c用来测试代码正常运行
contact.h作为头文件来进行函数分装的声明
contact.c来进行函数的实现功能
1.创建菜单栏
首先创建一个菜单,菜单包含着我们通讯录的一些功能选择界面
代码如下
void menu()
{
printf("********************************************\n");
printf("******** 1.add 2.delete *********\n");
printf("******** 3.search 4.modify *********\n");
printf("******** 5.show 6.sort *********\n");
printf("******** 0.exit *********\n");
printf("********************************************\n");
}
2.主函数入口
当我们设定好了菜单,在主函数中设置一个输入选项,选中该选项来进行实现功能,设定一个dowhile循环来保证代码至少执行一次
当输入0时0为假,循环不会继续退出循环,当输入超出范围内的数字,重新输入
int main()
{
int import;
do
{
menu();
printf("请输入你的选项:>>>>>>>>");
scanf("%d", &import);
switch (import)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("输入错误\n");
break;
}
} while (import);
3.自定义数据类型的实现(创建通讯录)
因为我们通讯录中需要包含的信息有很多,我们可以使用struct来自定义类型,后续可以通过结构体成员来访问
结构体类型我们只是声明,我们可以将声明放到头文件中
这里我们可以将数组的元素define定义到头文件中,这样我们可以直接进行修改,不需要从结构体内部修改
#define Max 100
#define Name_Max 20
#define Sex_Max 5
#define Address_Max 30
#define Tele_Max 12
typedef struct information//成员的信息
//typedef 修改成员名信息为PeoInfor
{
char name[Name_Max];
int age;
char sex[Sex_Max];
char address[Address_Max];
char tele[Tele_Max];
}PeoInfor;
当我们设置好了成员名的信息后,因为我们想要的联系人不止一个,我们需要定义一个数组,数组可以大一些,比如100,放100个联系人
可以将这个数组写为PeoInfor Data[100],这样我们就有了100个元素来存放成员信息。
但是我们不知道我们一共添加了几个联系人,通讯录目前共多少个,设置一个int sz来存放我们联系人的个数,因为数组下标是从0开始的
这样我们就可以写一个结构体将两个数组存放起来
typedef struct Contact
{
//创建通讯录
PeoInfor Data[100];//存放100个信息
int sz;//当前通讯录的信息个数
}Contact;
在main函数中创建刚才创建的结构体类型
Contact con;//分装自定义类型
4.初始化通讯录信息
我们将Contact con中的结构体成员和成员个数初始化为0
main.c
InitContact(&con);
这里我们声明一下
Contact.h
void InitContact(Contact* pc);//初始话通讯录
Contact.c
void InitContact(Contact *pc)
{
assert(pc);//断言
pc->sz = 0;//结构体的个数植为0
memset(pc->Data, 0, sizeof(pc->Data));//初始化pc->sz整个数组的大小
//memset函数可以将制定的数组中所有字节数置为指定数值
第一个值为元素首地址,第二个为值为0,第三个为元素所占用的字节数
}
5.当我们的初始化完成后,接下来就是选择语句中的函数功能实现了
1.Add函数实现(添加通讯录)
void AddContact(Contact *pc)
{
assert(pc);
if (pc->sz == Max)
//这里我们的条件是如果通讯录已经100,无法添加
{
printf("您好,通讯录已满,无法添加\n");
return;
}
//增加一个人的信息
printf("请输入名字:>");
scanf("%s", pc->Data[pc->sz].name);//输入下标为0的结构体类型
printf("请输入年龄:>");
scanf("%d", &(pc->Data[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->Data[pc->sz].sex);
printf("请输入地址:>");
scanf("%s", pc->Data[pc->sz].address);
printf("请输入电话:>");
scanf("%s", pc->Data[pc->sz].tele);
pc->sz++;//sz++,联系人加1
}
2.显示联系人
void ShowContact( Contact *pc)
{
assert(pc);
printf(" %-20s\t%-4s\t%-4s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
//访问的是结构体中的成员信息,循环方式打印
for (int i = 0; i < pc->sz; i++)
{
printf(" %-20s\t%-4d\t%-4s\t%-20s\t%-12s\n", pc->Data[i].name,
pc->Data[i].age,
pc->Data[i].sex,
pc->Data[i].address,
pc->Data[i].tele);
}
}
3.删除联系人
int Find_By_Name(const Contact* pc,char name[])//查找函数分装
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->Data[i].name, name) == 0) // 数组中与想要的名字相同进入
{
return i;
break;
}
}
return -1;
}
void DelContact(Contact* pc)
{
assert(pc);
char name[Name_Max] = {0};
//这里后面我们需要创建一个输入指定名字的变量
int i = 0;
if (pc->sz == 0)//条件如果为0,没有联系人
{
printf("通讯录为空,无法删除\n");
}
//找到要删除的人
printf("请输入你要删除的人的名字:>>>>");
scanf("%s", name);
//查找
int ret = Find_By_Name(pc, name);//查找我们输入的名字是否在数组中,并返回
//因为我们后面还需要使用到Find函数,所以我们需要分装出来
if(ret==-1)
{
printf("要删除的人不存在此备忘录\n");
return;
}
// 删除
for (i = ret; i < pc->sz-1;i++)//sz-1为98,程序+1不能越界访问
{
pc->Data[i] = pc->Data[i + 1];
}
pc->sz--;//将删除的下标益处
printf("删除成功\n");
}
4.查找联系人
void SearchContact( const Contact* pc)
{
assert(pc);
char name[Name_Max] = {0};
printf("请输入要查找人的名字:>>>");
scanf("%s", name);
int pos = Find_By_Name(pc, name);
if(pos==-1)
{
printf("该通讯录没有要查找的联系人\n");
return;
}
printf(" %-20s\t%-4s\t%-4s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
printf(" %-20s\t%-4d\t%-4s\t%-20s\t%-12s\n", pc->Data[pos].name,
pc->Data[pos].age,
pc->Data[pos].sex,
pc->Data[pos].address,
pc->Data[pos].tele);
}
5.修改联系人
void ModifyContact(Contact* pc)
{
assert(pc);
char name[Name_Max] = {0};
printf("请输入修改人的名字:>>>>");
scanf("%s", name);
int pos = Find_By_Name(pc, name);
if(pos==-1)
{
printf("你想要修改的名字未在通讯录中\n");
return;
}
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].address);
printf("请输入电话:>");
scanf("%s", pc->Data[pos].tele);
printf("修改完成\n");//提示
}
6.联系人排序整理
int cmp_name(const void* e1, const void* e2)
{
return (strcmp(((Contact*)e1)->Data->name, ((Contact*)e2)->Data->name));
//比较两个数
}
//联系人排序
void SortContact(Contact* pc)
{
assert(pc);
//这里我们需要引入qsort函数,来比较内存中的字节的大小,进行排序
qsort(pc->Data, pc->sz, sizeof(pc->Data[0]), cmp_name);
//第一个参数是首元素地址,第二个为元素的个数,第三个为类型字节数,第四个参数为比较
//打印
printf("排序完成\n");
ShowContact(pc);//打印一下
}
test.c 测试
#include"contact.c"
void menu()
{
printf("********************************************\n");
printf("******** 1.add 2.delete *********\n");
printf("******** 3.search 4.modify *********\n");
printf("******** 5.show 6.sort *********\n");
printf("******** 0.exit *********\n");
printf("********************************************\n");
}
int main()
{
int import;
Contact con;//分装自定义类型
//初始化通讯录
InitContact(&con);
do
{
menu();
printf("请输入你的选项:>>>>>>>>");
scanf("%d", &import);
switch (import)
{
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
SearchContact(&con);
break;
case 4:
ModifyContact(&con);
break;
case 5:
ShowContact(&con);
break;
case 6:
SortContact(&con);
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("输入错误\n");
break;
}
} while (import);
return 0;
}
Contact.h函数声明
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#define Max 100
#define Name_Max 20
#define Sex_Max 5
#define Address_Max 30
#define Tele_Max 12
//声明
typedef struct information
{
char name[Name_Max];
int age;
char sex[Sex_Max];
char address[Address_Max];
char tele[Tele_Max];
}PeoInfor;
typedef struct Contact
{
//创建通讯录
PeoInfor Data[100];//存放100个信息
int sz;//当前通讯录的信息个数
}Contact;
void InitContact(Contact* pc);//初始话通讯录
void AddContact(Contact* pc); //增加联系人信息
void ShowContact( Contact* pc);//打印联系人
void DelContact(Contact* pc);//删除指定联系人
void SearchContact(const Contact* pc);//查找指定联系人
void ModifyContact(Contact* pc);//修改联系人
void SortContact(Contact* pc);//整理联系人
Contact.c函数实现
#include"contact.h"
//实现
void InitContact(Contact *pc)
{
assert(pc);
pc->sz = 0;
memset(pc->Data, 0, sizeof(pc->Data));//初始化pc->sz整个数组的大小
}
void AddContact(Contact *pc)
{
assert(pc);
if (pc->sz == Max)
{
printf("您好,通讯录已满,无法添加\n");
return;
}
//增加一个人的信息
printf("请输入名字:>");
scanf("%s", pc->Data[pc->sz].name);//输入下标为0的结构体类型
printf("请输入年龄:>");
scanf("%d", &(pc->Data[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->Data[pc->sz].sex);
printf("请输入地址:>");
scanf("%s", pc->Data[pc->sz].address);
printf("请输入电话:>");
scanf("%s", pc->Data[pc->sz].tele);
pc->sz++;//sz++,联系人加1
}
void ShowContact( Contact *pc)
{
assert(pc);
printf(" %-20s\t%-4s\t%-4s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
for (int i = 0; i < pc->sz; i++)
{
printf(" %-20s\t%-4d\t%-4s\t%-20s\t%-12s\n", pc->Data[i].name,
pc->Data[i].age,
pc->Data[i].sex,
pc->Data[i].address,
pc->Data[i].tele);
}
}
int Find_By_Name(const Contact* pc,char name[])//查找函数分装
{
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->Data[i].name, name) == 0) // 数组中与想要的名字相同进入
{
return i;
break;
}
}
return -1;
}
void DelContact(Contact* pc)
{
assert(pc);
char name[Name_Max] = {0};
int i = 0;
if (pc->sz == 0)
{
printf("通讯录为空,无法删除\n");
}
//找到要删除的人
printf("请输入你要删除的人的名字:>>>>");
scanf("%s", name);
//查找
int ret = Find_By_Name(pc, name);
if(ret==-1)
{
printf("要删除的人不存在此备忘录\n");
return;
}
// 删除
for (i = ret; i < pc->sz-1;i++)//sz-1为98,程序+1不能越界访问
{
pc->Data[i] = pc->Data[i + 1];
}
pc->sz--;//将删除的下标益处
printf("删除成功\n");
}
void SearchContact( const Contact* pc)
{
assert(pc);
char name[Name_Max] = {0};
printf("请输入要查找人的名字:>>>");
scanf("%s", name);
int pos = Find_By_Name(pc, name);
if(pos==-1)
{
printf("该通讯录没有要查找的联系人\n");
return;
}
printf(" %-20s\t%-4s\t%-4s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");
printf(" %-20s\t%-4d\t%-4s\t%-20s\t%-12s\n", pc->Data[pos].name,
pc->Data[pos].age,
pc->Data[pos].sex,
pc->Data[pos].address,
pc->Data[pos].tele);
}
void ModifyContact(Contact* pc)
{
assert(pc);
char name[Name_Max] = {0};
printf("请输入修改人的名字:>>>>");
scanf("%s", name);
int pos = Find_By_Name(pc, name);
if(pos==-1)
{
printf("你想要修改的名字未在通讯录中\n");
return;
}
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].address);
printf("请输入电话:>");
scanf("%s", pc->Data[pos].tele);
printf("修改完成\n");
}
int cmp_name(const void* e1, const void* e2)
{
return (strcmp(((Contact*)e1)->Data->name, ((Contact*)e2)->Data->name));
//比较两个数
}
//联系人排序
void SortContact(Contact* pc)
{
assert(pc);
qsort(pc->Data, pc->sz, sizeof(pc->Data[0]), cmp_name);
//打印
printf("排序完成\n");
ShowContact(pc);//打印一下
}
动态开辟空间
因为我们的通讯录需要设定创建的人数是有限的,太高会浪费内存,过少用户会添加不了新的信息到通讯录,所以我们可以使用动态来开辟一个空间
typedef struct Contact
{
//创建通讯录
PeoInfor* Data;//指向了存放的人的信息
int sz;//当前通讯录的信息个数
int capacity; //来记录我们当前最大的容量
}Contact;
当我们将结构体类型设置好后,我们需要将我们结构体内所有的信息进行初始化
所以在主函数中定义一个函数进行初始化
1.通讯录的个数首先肯定是从0开始
2.而我们的Data的个数先设置多少个呢,这里我们可以在.h文件中define声明一下,Default_Sz来初始化为3个,这样也方便我们的测试
我们直接使用calloc来开辟一个动态空间,将元素的个数,和需要开辟空间的大小放入,引入一个临时的指针来接收一下开辟的动态空间,判断一下是否开辟成功,然后我们可以将ptr这个指针指向的空间赋给原空间pc->Data。
3.capacity来作为我们的一个容量,来记录我们容量的变化,因为我们的容量默认为Default_Sz个,后续用来判断,如果容量满了,我们就可以进行扩容
void InitContact(Contact *pc)
{
assert(pc);
pc->sz = 0;
PeoInfor* ptr =(PeoInfor*)calloc(Default_Sz,sizeof(PeoInfor));
//第一个:Default_Sz个元素,第二个:PeoInfor的字节空间大小,
if(ptr==NULL)
{
perror("InitContact");
return;
}
pc->Data = ptr;
pc->capacity = Default_Sz;
}
增加联系人(扩容)
void Expand_Capacity(Contact* p)//判断容量是否满了
{
if (p->sz == p->capacity)//这里是判断我们默认的容量
{
//增容
PeoInfor* ptr = (PeoInfor*)realloc(p->Data, (p->capacity+Inc_Sz)* sizeof(PeoInfor));
//这里的realloc可以调整我们当前已经动态开辟空间的大小
//第一个放入我们的起始位置, 第二个是我们的容量(3+2)*类型的大小(算上我们当初已经拥有的容量)
if(ptr==NULL)
{
perror("Expand_Capacity::");
return;
}
p->Data = ptr;
p->capacity += Inc_Sz;
}
}
//动态
void AddContact(Contact *pc)
{
assert(pc);
Expand_Capacity(pc);//这里我们直接可以做一个扩容的函数
// 增加一个人的信息
printf("请输入名字:>");
scanf("%s", pc->Data[pc->sz].name);//输入下标为0的结构体类型
printf("请输入年龄:>");
scanf("%d", &(pc->Data[pc->sz].age));
printf("请输入性别:>");
scanf("%s", pc->Data[pc->sz].sex);
printf("请输入地址:>");
scanf("%s", pc->Data[pc->sz].address);
printf("请输入电话:>");
scanf("%s", pc->Data[pc->sz].tele);
pc->sz++;//sz++,联系人加1
}
销毁动态开辟的空间
当我们系统已经结束后,选择为0,退出时,我们需要销毁我们动态开辟的空间
Destory_Contact(&con);//这里我们在主函数中实现,用来销毁我们动态开辟的空间
声明
void Destory_Contact(Contact* pc);//销毁通讯录
实现
//销毁
void Destory_Contact(Contact* pc)
{
free(pc->Data);
pc->Data = NULL;
pc->capacity = 0;
pc->sz = 0;
pc = NULL;
}
扩容成功界面
代码实现扩容成功