前言
使用C语言模拟一个通讯录,通讯录的初始可以存储3个联系人的数据,当存满之后,自动增加2个联系人的空间。
存储的信息包括:姓名、性别、年龄、电话号码、地址
能实现的功能包括:1。新增联系人;2.删除联系人;3.查找联系人:根据姓名查找;4.修改联系人;5.排序联系人:将通讯录中的联系人根据姓名首字母的大小升序排列、6.打印通讯录中的联系人的所有信息、7.退出通讯录
目录
一、通讯录菜单
二、通讯录主函数
三、枚举通讯录选项
四、定义通讯录和联系人
1.定义联系人的信息(结构体)
2.定义通讯录信息(结构体)
五、全局变量声明
六、通过姓名查找联系人的函数
七、通讯录增容函数
八、销毁通讯录函数
九、实现通讯录功能的函数
1.初始化通讯录
2.新增联系人
3.删除联系人
4.查找联系人
5.修改联系人
6.排序联系人
7.打印联系人
十、头文件
十一、完整代码
设计一个菜单,向用户展示功能,用来和用户交互
void menu()
{
printf("******************************\n");
printf("**** 1.add 2.del *****\n");
printf("**** 3.search 4.modify *****\n");
printf("**** 5.sort 6.print *****\n");
printf("**** 0.exit *****\n");
printf("******************************\n");
}
打印出来的效果
函数主体使用do……while循环对输入的选项进行判断,当输入为0时跳出循环,程序结束。不为0时,用switch语句跳转到相对应的功能,代码如下:
void test()
{
int input = 0;
Contacts con;
InitCon(&con);//初始化通讯录
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContacts(&con);//增加联系人
break;
case DEL:
DelContacts(&con);//删除联系人
break;
case SEARCH:
SearchContacts(&con);//查找联系人
break;
case MODIFY:
ModifyContacts(&con);//更改联系人
break;
case SORT:
SortContacts(&con);//排序联系人
break;
case PRINT:
PrintContacts(&con);//打印联系人
break;
case EXIT:
DestoryContacts(&con);//销毁通讯录
printf("退出通讯录\n");
break;
default:
printf("请输入正确的选项:>\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
switch语句会根据输入值,跳入不同的case语句中。上面代码为了可读性将case后面的数值替换成了对应的选项,无法达到switch的效果,因此使用枚举对选项赋值。
//枚举选项
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
PRINT,
};
联系人的信息不是单一类型,使用结构体创建一个联系人类型
//创建联系人数据类型
typedef struct Peodata
{
char name[NAME_MAX];
char tele[TELE_MAX];
int age;
char sxe[SEX_MAX];
char addr[ADDR_MAX];
}Peodata;
这里我们创建一个上述联系人结构体类型的指针,用来指向动态内存开辟的空间。同时也创建一个int类型的变量,用来保存联系人的个数。创建一个int型的变量,保存通讯录的容量
//创建通讯录数据类型
typedef struct Contacts
{
int sz;//联系人的个数
int capacity;//最大容量
Peodata* data;//指向存放联系人的地址
}Contacts;
为了方便日后对通讯录的修改和完善,将所有需要指定数组元素个数的数据进行声明
//定义的类型
#define NAME_MAX 20
#define TELE_MAX 11
#define SEX_MAX 5
#define ADDR_MAX 20
//查找联系人,找到了返回下标,没找到返回-1
static int Searchdata(const Contacts* pc, const char* pn)
{
assert(pc && pn);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, pn) == 0)
{
return i;
}
}
return -1;
}
因为我们这个通讯录初始空间是有限的,当联系人的个数等于最大容量的时候,使用realloc函数增加容量
//判断通讯录是否需要增容
static void IsCapacity(Contacts* pc)
{
assert(pc);
if (pc->capacity == pc->sz)
{
Peodata* tmp = (Peodata*)realloc(pc->data, (pc->capacity + 2) * sizeof(Peodata));
if (tmp == NULL)
{
perror("IsContacts : realloc");
return;
}
else
{
pc->data = tmp;
}
pc->capacity += 2;
}
}
因为使用了动态内存分配函数,为了避免出现内存泄漏的现象,退出通讯录的时候,需要将像内存申请的空降释放。同时为避免出现野指针将创建的指针置为空
//销毁通讯录
void DestoryContacts(Contacts* pc)
{
assert(pc);
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
printf("通讯录被销毁\n");
}
用calloc函数像堆区申请3个联系人结构体大小的空间,并将申请好的空间地址传给给之前创建好的指针。
//初始化通讯录
void InitCon(Contacts* pc)
{
assert(pc);
pc->sz = 0;
pc->capacity = 3;
pc->data = (Peodata*)calloc(pc->capacity, sizeof(Peodata));
if (pc->data == NULL)
{
perror("InitCon : calloc");
return;
}
}
当通讯录中没有人的时候,count的值为0,数组的下标也是0,新增的信息要放在数组下标为0处;当通讯录中有1个人时,count为1时,新增的信息要放在数组的下标为1处。按此规律count的值正好等于等于要新增的信息所存放的数组的下标
//增加联系人
void AddContacts(Contacts* pc)
{
assert(pc);
IsCapacity(pc);//判断通讯录是否需要增容
printf("请输入姓名:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sxe);
printf("请输入年龄:>");
scanf("%d", &pc->data[pc->sz].age);
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入住址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("录入成功\n");
}
封装一个函数FindByName,通过输入名字查找要删除的联系人
//删除联系人
void DelContacts(Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
char name[NAME_MAX] = { 0 };
printf("请输入您要删除联系人的姓名:>");
scanf("%s", name);
int ret = Searchdata(pc, name);
if (ret == -1)
{
printf("联系人不存在\n");
return;
}
memmove(&pc->data[ret], &pc->data[ret + 1], (pc->sz - ret) * sizeof(pc->data[0]));
pc->sz--;
}
//查找联系人
void SearchContacts(const Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
char name[NAME_MAX] = { 0 };
printf("请输入您要查找联系人的姓名:>");
scanf("%s", name);
int ret = Searchdata(pc, name);
if (ret == -1)
{
printf("联系人不存在\n");
return;
}
printf("%-20s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-20s %-5s %-5d %-15s %-20s\n", pc->data[ret].name, pc->data[ret].sxe, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr);
}
//更改联系人
void ModifyContacts(Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
char name[NAME_MAX] = { 0 };
printf("请输入您要更改联系人的姓名:>");
scanf("%s", name);
int ret = Searchdata(pc, name);
if (ret == -1)
{
printf("联系人不存在\n");
return;
}
printf("请输入姓名:>");
scanf("%s", pc->data[ret].name);
printf("请输入性别:>");
scanf("%s", pc->data[ret].sxe);
printf("请输入年龄:>");
scanf("%d", &pc->data[ret].age);
printf("请输入电话:>");
scanf("%s", pc->data[ret].tele);
printf("请输入住址:>");
scanf("%s", pc->data[ret].addr);
}
//qsort判断函数
int Cmpdata(const void* e1, const void* e2)
{
return strcmp(((Peodata*)e1)->name, ((Peodata*)e2)->name);
}
//排序联系人
void SortContacts(Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
qsort(pc->data, pc->sz, sizeof(pc->data[0]), Cmpdata);
printf("排序完成\n");
}
这里我用for循环
//打印联系人
void PrintContacts(const Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
printf("%-20s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
int i = 0;
for (i = 0; i < pc->sz; i++)
{
printf("%-20s %-5s %-5d %-15s %-20s\n", pc->data[i].name, pc->data[i].sxe, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
}
}
#include
#include
#include
#include
//contacts.h
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
//变量的声明
#define NAME_MAX 20
#define TELE_MAX 11
#define SEX_MAX 5
#define ADDR_MAX 20
//创建联系人数据类型
typedef struct Peodata
{
char name[NAME_MAX];
char tele[TELE_MAX];
int age;
char sxe[SEX_MAX];
char addr[ADDR_MAX];
}Peodata;
//创建通讯录数据类型
typedef struct Contacts
{
int sz;//联系人的个数
int capacity;//最大容量
Peodata* data;//指向存放联系人的地址
}Contacts;
//枚举选项
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SORT,
PRINT,
};
//函数的声明
//初始化通讯录
void InitCon(Contacts* pc);
//增加联系人
void AddContacts(Contacts* pc);
//删除联系人
void DelContacts(Contacts* pc);
//查找联系人
void SearchContacts(const Contacts* pc);
//更改联系人
void ModifyContacts(Contacts* pc);
//排序联系人
void SortContacts(Contacts* pc);
//打印联系人
void PrintContacts(const Contacts* pc);
//销毁通讯录
void DestoryContacts(Contacts* pc);
//contacts.c
#include "contacts.h"
//初始化通讯录
void InitCon(Contacts* pc)
{
assert(pc);
pc->sz = 0;
pc->capacity = 3;
pc->data = (Peodata*)calloc(pc->capacity, sizeof(Peodata));
if (pc->data == NULL)
{
perror("InitCon : calloc");
return;
}
}
//判断通讯录是否需要增容
static void IsCapacity(Contacts* pc)
{
assert(pc);
if (pc->capacity == pc->sz)
{
Peodata* tmp = (Peodata*)realloc(pc->data, (pc->capacity + 2) * sizeof(Peodata));
if (tmp == NULL)
{
perror("IsContacts : realloc");
}
else
{
pc->data = tmp;
}
pc->capacity += 2;
}
}
//增加联系人
void AddContacts(Contacts* pc)
{
assert(pc);
IsCapacity(pc);//判断通讯录是否需要增容
printf("请输入姓名:>");
scanf("%s", pc->data[pc->sz].name);
printf("请输入性别:>");
scanf("%s", pc->data[pc->sz].sxe);
printf("请输入年龄:>");
scanf("%d", &pc->data[pc->sz].age);
printf("请输入电话:>");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入住址:>");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("录入成功\n");
}
//查找联系人,找到了返回下标,没找到返回-1
static int Searchdata(const Contacts* pc, const char* pn)
{
assert(pc && pn);
int i = 0;
for (i = 0; i < pc->sz; i++)
{
if (strcmp(pc->data[i].name, pn) == 0)
{
return i;
}
}
return -1;
}
//删除联系人
void DelContacts(Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
char name[NAME_MAX] = { 0 };
printf("请输入您要删除联系人的姓名:>");
scanf("%s", name);
int ret = Searchdata(pc, name);
if (ret == -1)
{
printf("联系人不存在\n");
return;
}
memmove(&pc->data[ret], &pc->data[ret + 1], (pc->sz - ret) * sizeof(pc->data[0]));
pc->sz--;
}
//查找联系人
void SearchContacts(const Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
char name[NAME_MAX] = { 0 };
printf("请输入您要查找联系人的姓名:>");
scanf("%s", name);
int ret = Searchdata(pc, name);
if (ret == -1)
{
printf("联系人不存在\n");
return;
}
printf("%-20s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
printf("%-20s %-5s %-5d %-15s %-20s\n", pc->data[ret].name, pc->data[ret].sxe, pc->data[ret].age, pc->data[ret].tele, pc->data[ret].addr);
}
//更改联系人
void ModifyContacts(Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
char name[NAME_MAX] = { 0 };
printf("请输入您要更改联系人的姓名:>");
scanf("%s", name);
int ret = Searchdata(pc, name);
if (ret == -1)
{
printf("联系人不存在\n");
return;
}
printf("请输入姓名:>");
scanf("%s", pc->data[ret].name);
printf("请输入性别:>");
scanf("%s", pc->data[ret].sxe);
printf("请输入年龄:>");
scanf("%d", &pc->data[ret].age);
printf("请输入电话:>");
scanf("%s", pc->data[ret].tele);
printf("请输入住址:>");
scanf("%s", pc->data[ret].addr);
}
//qsort判断函数
int Cmpdata(const void* e1, const void* e2)
{
return strcmp(((Peodata*)e1)->name, ((Peodata*)e2)->name);
}
//排序联系人
void SortContacts(Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
qsort(pc->data, pc->sz, sizeof(pc->data[0]), Cmpdata);
printf("排序完成\n");
}
//打印联系人
void PrintContacts(const Contacts* pc)
{
assert(pc);
if (pc->sz == 0)
{
printf("通讯录为空\n");
return;
}
printf("%-20s %-5s %-5s %-15s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
int i = 0;
for (i = 0; i < pc->sz; i++)
{
printf("%-20s %-5s %-5d %-15s %-20s\n", pc->data[i].name, pc->data[i].sxe, pc->data[i].age, pc->data[i].tele, pc->data[i].addr);
}
}
//销毁通讯录
void DestoryContacts(Contacts* pc)
{
assert(pc);
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->sz = 0;
printf("通讯录被销毁\n");
}
//test.c
#include "contacts.h"
void menu()
{
printf("******************************\n");
printf("**** 1.add 2.del ****\n");
printf("**** 3.search 4.modify ****\n");
printf("**** 5.sort 6.print ****\n");
printf("**** 0.exit ****\n");
printf("******************************\n");
}
void test()
{
int input = 0;
Contacts con;
InitCon(&con);//初始化通讯录
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContacts(&con);//增加联系人
break;
case DEL:
DelContacts(&con);//删除联系人
break;
case SEARCH:
SearchContacts(&con);//查找联系人
break;
case MODIFY:
ModifyContacts(&con);//更改联系人
break;
case SORT:
SortContacts(&con);//排序联系人
break;
case PRINT:
PrintContacts(&con);//打印联系人
break;
case EXIT:
DestoryContacts(&con);//销毁通讯录
printf("退出通讯录\n");
break;
default:
printf("请输入正确的选项:>\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}