通讯录
首先利用结构体创建个人的基本信息
代码如下
struct PeoInfor
{
char name[20]; //姓名
int age; //年龄
char sex[10]; //性别
char telephone[15]; //电话号码
char address[20]; //居住地址
};
再用一个结构体来创建通讯录
代码如下
struct Contact
{
struct PeoInfor* data; //结构体指针,将要指向每个人的信息
int length; //个人信息的个数
int capacity; //空间容量
};
我们在主函数中用test函数来封装通讯录的基本流程
代码如下
int main()
{
test();
return 0;
}
test函数代码如下
void test()
{
int input = 0;
//创建一个通讯录
struct Contact con;
//初始化通讯录
InitContact(&con);
do
{
menu();
printf("请选择要进行的操作:");
scanf("%d", &input);
switch (input)
{
case Exit:
printf("退出通讯录!\n");
//销毁通讯录
DestoryContact(&con);
break;
case Add:
//添加个人信息
AddContact(&con);
break;
case Modify:
//修改个人信息
ModifyContact(&con);
break;
case Delete:
//删除个人信息
DeleteContact(&con);
break;
case Sort:
//排序个人信息
SortContact(&con);
break;
case Search:
//查找指定人员
SearchContact(&con);
break;
case Show:
//显示个人信息
ShowContact(&con);
break;
case Save:
//保存通讯录到文件中
SaveContact(&con);
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
}
在test函数中,我们利用menu函数来打印操作菜单
代码如下
void menu()
{
printf("---------------------------------\n");
printf("------- This is a contact! ------\n");
printf("-------------1.add---------------\n");
printf("-------------2.modify------------\n");
printf("-------------3.delete------------\n");
printf("-------------4.sort--------------\n");
printf("-------------5.search------------\n");
printf("-------------6.show--------------\n");
printf("-------------7.save--------------\n");
printf("-------------0.exit--------------\n");
printf("---------------------------------\n");
}
在test函数中,我们利用了枚举常量的特性,使代码具有更高的可读性
代码如下
enum Option
{
Exit, //0
Add, //1
Modify, //2
Delete, //3
Sort, //4
Search, //5
Show, //6
Save //7
};
我们利用InitContact函数来实现初始化通讯录的功能
代码如下
void InitContact(struct Contact* pc)
{
pc->length = 0;
//通讯录开始默认只能存放三个人的信息
pc->capacity = 3;
//分配三个人的信息空间
pc->data = (struct PeoInfor*)malloc(sizeof(struct PeoInfor) * 3);
if (pc->data == NULL)
{
printf("通讯录初始化失败!\n");
//异常退出程序
exit(1);
}
// 从文件中加载数据到内存中
LoadContact(pc);
}
InitContact函数中,我们利用LoadContact函数来实现从文件中加载信息的功能
代码如下
void LoadContact(struct Contact* pc)
{
//以只读的方式打开指定二进制文件Contact.dat
FILE* p = fopen("Contact.dat", "rb");
if (p == NULL)
{
//利用strerror函数来打印错误原因
printf("%s\n", strerror(errno));
return;
}
//创建临时变量来存储个人信息
struct PeoInfor temp = { 0 };
//二进制输入文件信息
while (fread(&temp, sizeof(struct PeoInfor), 1, p))
{
//检查空间是否够用,不够即增添空间
CheakCapacity(pc);
pc->data[pc->length] = temp;
pc->length++;
}
fclose(p);
p = NULL;
}
由于在在LoadContact函数中,我们不断地加载个人信息,以防通讯录空间不够,我们利用CheakCapacity函数来检查空间是否够用,如果不够即增添空间
代码如下
void CheakCapacity(struct Contact* pc)
{
if (pc->capacity == pc->length)
{
struct PeoInfor* ptr = (struct PeoInfor*)realloc(pc->data, sizeof(struct PeoInfor) * (pc->capacity + 2));
if (ptr == NULL)
{
//利用strerror函数来打印错误原因
printf("%s\n", strerror(errno));
return;
}
else
{
//因为realloc函数扩大空间的特性,我们以防指针丢失,将指针重新赋回
pc->data = ptr;
pc->capacity += 2;
}
}
}
我们利用AddContact函数来实现添加人员信息的功能
代码如下
void AddContact(struct Contact* pc)
{
//检查剩余空间是否够用,不够就增添空间
CheakCapacity(pc);
//录入个人的基本信息
printf("输入姓名:");
scanf("%s", pc->data[pc->length].name);
printf("请输入年龄:");
scanf("%d", &(pc->data[pc->length].age));
printf("请输入性别:");
scanf("%s", pc->data[pc->length].sex);
printf("请输入电话号码:");
scanf("%s", pc->data[pc->length].telephone);
printf("请输入居住地址:");
scanf("%s", pc->data[pc->length].address);
pc->length++;
printf("添加成功!\n");
}
我们利用ModifyContact函数来实现修改个人信息的功能
代码如下
void ModifyContact(struct Contact* pc)
{
if (pc->length == 0)
{
printf("通讯录为空,无法修改!\n");
}
else
{
//利用SearchByName函数来实现按姓名查找指定联系人
int ret = SearchByName(pc);
if (ret != -1)
{
printf("通讯录存在该人,可以修改\n");
int enter = 0;
printf("----1.全部修改----\n");
printf("----2.单个修改----\n");
scanf("%d", &enter);
do
{
if (enter == 1)
{
//修改基本信息
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].telephone);
printf("请输入居住地址:");
scanf("%s", pc->data[ret].address);
}
else if (enter == 2)
{
int ENTER = 0;
//打印修改菜单
ModifyMenu();
scanf("%d", &ENTER);
//修改单个信息
switch (ENTER)
{
case 1:
printf("输入姓名:");
scanf("%s", pc->data[ret].name);
break;
case 2:
printf("请输入年龄:");
scanf("%d", &(pc->data[ret].age));
break;
case 3:
printf("请输入性别:");
scanf("%s", pc->data[ret].sex);
break;
case 4:
printf("请输入电话号码:");
scanf("%s", pc->data[ret].telephone);
break;
case 5:
printf("请输入居住地址:");
scanf("%s", pc->data[ret].address);
break;
}
}
else
{
printf("选择错误,请重新选择!\n");
}
} while (!(enter == 1 || enter == 2));
}
else
{
printf("通讯录不存在该人!\n");
}
}
}
我们在ModifyContact函数中,利用SearchByName函数来实现按姓名查找指定联系人的功能
代码如下
int SearchByName(struct Contact* pc)
{
char NAME[20] = { 0 };
printf("请输入人的姓名:");
scanf("%s", NAME);
for (int i = 0; i < pc->length; i++)
{
if (strcmp(pc->data[i].name, NAME) == 0)
{
return i;
}
}
return -1;
}
其次,如果要修改单项信息,我们利用ModifyMenu函数来打印修改菜单
代码如下
void ModifyMenu()
{
printf("------------------------\n");
printf("-------1.修改姓名--------\n");
printf("-------2.修改年龄--------\n");
printf("-------3.修改性别--------\n");
printf("------4.修改电话号码------\n");
printf("------5.修改居住地址------\n");
printf("------------------------\n");
}
我们利用DeleteContact函数来实现删除个人信息的功能
代码如下
void DeleteContact(struct Contact* pc)
{
int in = 0;
printf("------1.删除全部信息-------\n");
printf("------2.删除单项信息-------\n");
do
{
scanf("%d", &in);
if (in == 1)
{
pc->length = 0;
printf("删除全部信息成功!\n");
}
else if (in == 2)
{
//利用SearchByName函数来实现按姓名查找指定联系人
int pos = SearchByName(pc);
if (pos != -1)
{
//删除即用后面的信息覆盖前面的信息,
将要删除信息的后面的全部信息向前移动一个个人信息的结构体大小
for (int i = pos; i < pc->length - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->length--;
printf("删除成功!\n");
}
else
{
printf("通讯录不存在该人!");
}
}
else
{
printf("选择错误,请重新选择!\n");
}
} while (!(in == 1 || in == 2));
}
我们利用SortContact函数来实现通讯录排序功能
代码如下
void SortContact(struct Contact* pc)
{
if (pc->length == 0)
{
printf("通讯录为空,无法排序!\n");
}
else
{
printf("按年龄排序!\n");
//这里利用冒泡排序的思想来实现排序功能
for (int i = 0; i < pc->length - 1; i++)
{
for (int j = 0; j < pc->length - 1 - i; j++)
{
if (pc->data[j].age > pc->data[j + 1].age)
{
struct PeoInfor temp = pc->data[j];
pc->data[j] = pc->data[j + 1];
pc->data[j + 1] = temp;
}
}
}
//排序完显示通讯录
printf("%-s\t%-4s\t%-2s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话号码", "居住地址");
for (int i = 0; i < pc->length; i++)
{
printf("%-s\t%-4d\t%-2s\t%-12s\t%-10s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].telephone,
pc->data[i].address);
}
}
}
我们利用SearchContact函数来实现查找指定联系人的功能
代码如下
void SearchContact(struct Contact* pc)
{
if (pc->length == 0)
{
printf("通讯录为空!\n");
}
else
{
int rec = SearchByName(pc);
if (rec != -1)
{
printf("找到了,下面是该人员的信息!\n");
//打印该人的基本信息
printf("%-s\t%-4s\t%-2s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话号码", "居住地址");
printf("%-s\t%-4d\t%-2s\t%-12s\t%-10s\n",
pc->data[rec].name,
pc->data[rec].age,
pc->data[rec].sex,
pc->data[rec].telephone,
pc->data[rec].address);
}
else
{
printf("通讯录不存在该人!\n");
}
}
}
我们利用ShowContact函数来实现显示通讯录的功能
代码如下
void ShowContact(struct Contact* pc)
{
//如果通讯录为空,无法打印
if (pc->length == 0)
{
printf("通讯录为空!\n");
}
else
{
//打印通讯录
printf("%-s\t%-4s\t%-2s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话号码", "居住地址");
for (int i = 0; i < pc->length; i++)
{
printf("%-s\t%-4d\t%-2s\t%-12s\t%-10s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].telephone,
pc->data[i].address);
}
}
}
我们利用DestoryContact函数来实现销毁通讯录的功能
代码如下
void DestoryContact(struct Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->length = 0;
}
我们利用SaveContact函数来实现保存通讯录到文件中
代码如下
void SaveContact(struct Contact* pc)
{
//以只写的方式打开指定二进制文件Contact.dat,没有就创建
FILE* p = fopen("Contact.dat", "wb");
if (p == NULL)
{
//利用strerror函数来打印错误原因
printf("%s\n", strerror(errno));
return;
}
for (int i = 0; i < pc->length; i++)
{
//二进制输出信息到文件中
fwrite(pc->data + i, sizeof(struct PeoInfor), 1, p);
}
fclose(p);
p = NULL;
printf("保存成功!\n");
}
为了更好的封装代码,我们将代码分为三个模块,即Contact.h,Contact.c和test.c三个代码模块
其中Contact.h存放着头文件、宏定义、函数声明等,Contact.c存放着函数的实现过程,test.c存放着通讯录的基本实现流程
下面是整体代码
Contact.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<errno.h>
//初始化通讯录
void InitContact(struct Contact* pc);
//添加个人信息
void AddContact(struct Contact* pc);
//修改个人信息
void ModifyContact(struct Contact* pc);
//删除个人信息
void DeleteContact(struct Contact* pc);
//排序个人信息
void SortContact(struct Contact* pc);
//查找个人人员
void SearchContact(struct Contact* pc);
//显示个人信息
void ShowContact(struct Contact* pc);
//保存个人信息
void SaveContact(struct Contact* pc);
//销毁通讯录
void DestoryContact(struct Contact* pc);
//每个人的信息
struct PeoInfor
{
char name[20]; //姓名
int age; //年龄
char sex[10]; //性别
char telephone[15]; //电话号码
char address[20]; //居住地址
};
//通讯录信息
struct Contact
{
struct PeoInfor* data; //结构体指针,将要指向每个人的信息
int length; //个人信息的数量
int capacity; //空间容量
};
//枚举常量来表示对应的选项,给代码带来更好的可读性
enum Option
{
Exit, //0
Add, //1
Modify, //2
Delete, //3
Sort, //4
Search, //5
Show, //6
Save //7
};
Contact.c
#include"contact.h"
void ModifyMenu()
{
printf("------------------------\n");
printf("-------1.修改姓名--------\n");
printf("-------2.修改年龄--------\n");
printf("-------3.修改性别--------\n");
printf("------4.修改电话号码------\n");
printf("------5.修改居住地址------\n");
printf("------------------------\n");
}
//空间增容
void CheakCapacity(struct Contact* pc)
{
if (pc->capacity == pc->length)
{
struct PeoInfor* ptr = (struct PeoInfor*)realloc(pc->data, sizeof(struct PeoInfor) * (pc->capacity + 2));
if (ptr == NULL)
{
//利用strerror函数来打印错误原因
printf("%s\n", strerror(errno));
return;
}
else
{
//因为realloc函数扩大空间的特性,我们以防指针丢失,将指针重新赋回
pc->data = ptr;
pc->capacity += 2;
}
}
}
//从文件中读取内容
void LoadContact(struct Contact* pc)
{
//以只读的方式打开指定二进制文件Contact.dat
FILE* p = fopen("Contact.dat", "rb");
if (p == NULL)
{
//利用strerror函数来打印错误原因
printf("%s\n", strerror(errno));
return;
}
//创建临时结果体变量来存储个人信息
struct PeoInfor temp = { 0 };
//二进制输入文件信息
while (fread(&temp, sizeof(struct PeoInfor), 1, p))
{
//检查空间是否够用,不够即增添空间
CheakCapacity(pc);
pc->data[pc->length] = temp;
pc->length++;
}
fclose(p);
p = NULL;
}
//初始化通讯录
void InitContact(struct Contact* pc)
{
pc->length = 0;
//通讯录开始默认只能存放三个人的信息
pc->capacity = 3;
//分配三个人的信息空间
pc->data = (struct PeoInfor*)malloc(sizeof(struct PeoInfor) * 3);
if (pc->data == NULL)
{
printf("通讯录初始化失败!\n");
//异常退出程序
exit(1);
}
//如果空间不够用,就增添空间
LoadContact(pc);
}
//添加个人信息
void AddContact(struct Contact* pc)
{
//检查剩余空间是否够用,不够就增添空间
CheakCapacity(pc);
//录入个人的基本信息
printf("输入姓名:");
scanf("%s", pc->data[pc->length].name);
printf("请输入年龄:");
scanf("%d", &(pc->data[pc->length].age));
printf("请输入性别:");
scanf("%s", pc->data[pc->length].sex);
printf("请输入电话号码:");
scanf("%s", pc->data[pc->length].telephone);
printf("请输入居住地址:");
scanf("%s", pc->data[pc->length].address);
pc->length++;
printf("添加成功!\n");
}
//按姓名查找指定联系人
int SearchByName(struct Contact* pc)
{
char NAME[20] = { 0 };
printf("请输入人的姓名:");
scanf("%s", NAME);
for (int i = 0; i < pc->length; i++)
{
if (strcmp(pc->data[i].name, NAME) == 0)
{
return i;
}
}
return -1;
}
//修改个人信息
void ModifyContact(struct Contact* pc)
{
if (pc->length == 0)
{
printf("通讯录为空,无法修改!\n");
}
else
{
//利用SearchByName函数来实现按姓名查找人员
int ret = SearchByName(pc);
if (ret != -1)
{
printf("通讯录存在该人员,可以修改\n");
int enter = 0;
printf("----1.全部修改----\n");
printf("----2.单个修改----\n");
scanf("%d", &enter);
do
{
if (enter == 1)
{
//修改基本信息
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].telephone);
printf("请输入居住地址:");
scanf("%s", pc->data[ret].address);
}
else if (enter == 2)
{
int ENTER = 0;
//打印修改菜单
ModifyMenu();
scanf("%d", &ENTER);
//修改单个信息
switch (ENTER)
{
case 1:
printf("输入姓名:");
scanf("%s", pc->data[ret].name);
break;
case 2:
printf("请输入年龄:");
scanf("%d", &(pc->data[ret].age));
break;
case 3:
printf("请输入性别:");
scanf("%s", pc->data[ret].sex);
break;
case 4:
printf("请输入电话号码:");
scanf("%s", pc->data[ret].telephone);
break;
case 5:
printf("请输入居住地址:");
scanf("%s", pc->data[ret].address);
break;
}
}
else
{
printf("选择错误,请重新选择!\n");
}
} while (!(enter == 1 || enter == 2));
}
else
{
printf("通讯录不存在该人!\n");
}
}
}
//删除个人信息
void DeleteContact(struct Contact* pc)
{
if (pc->length == 0)
{
printf("通讯录为空,无法进行删除操作!\n");
}
else
{
int in = 0;
printf("------1.删除全部信息-------\n");
printf("------2.删除单项信息-------\n");
do
{
scanf("%d", &in);
if (in == 1)
{
pc->length = 0;
printf("删除全部信息成功!\n");
}
else if (in == 2)
{
//利用SearchByName函数来实现按姓名查找指定联系人
int pos = SearchByName(pc);
if (pos != -1)
{
//删除即用后面的信息覆盖前面的信息,将要删除信息的后面的全部信息向前移动一个个人信息的结构体大小
for (int i = pos; i < pc->length - 1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->length--;
printf("删除成功!\n");
}
else
{
printf("通讯录不存在该人!");
}
}
else
{
printf("选择错误,请重新选择!\n");
}
} while (!(in == 1 || in == 2));
}
}
//排序人员信息
void SortContact(struct Contact* pc)
{
if (pc->length == 0)
{
printf("通讯录为空,无法排序!\n");
}
else
{
printf("按年龄排序!\n");
//这里利用冒泡排序的思想来实现排序功能
for (int i = 0; i < pc->length - 1; i++)
{
for (int j = 0; j < pc->length - 1 - i; j++)
{
if (pc->data[j].age > pc->data[j + 1].age)
{
struct PeoInfor temp = pc->data[j];
pc->data[j] = pc->data[j + 1];
pc->data[j + 1] = temp;
}
}
}
//排序完显示通讯录
printf("%-s\t%-4s\t%-2s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话号码", "居住地址");
for (int i = 0; i < pc->length; i++)
{
printf("%-s\t%-4d\t%-2s\t%-12s\t%-10s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].telephone,
pc->data[i].address);
}
}
}
//查找个人信息
void SearchContact(struct Contact* pc)
{
if (pc->length == 0)
{
printf("通讯录为空!\n");
}
else
{
int rec = SearchByName(pc);
if (rec != -1)
{
printf("找到了,下面是该人员的信息!\n");
//打印该人的基本信息
printf("%-s\t%-4s\t%-2s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话号码", "居住地址");
printf("%-s\t%-4d\t%-2s\t%-12s\t%-10s\n",
pc->data[rec].name,
pc->data[rec].age,
pc->data[rec].sex,
pc->data[rec].telephone,
pc->data[rec].address);
}
else
{
printf("通讯录不存在该人!\n");
}
}
}
//显示个人信息
void ShowContact(struct Contact* pc)
{
//如果通讯录为空,无法打印
if (pc->length == 0)
{
printf("通讯录为空!\n");
}
else
{
//打印通讯录
printf("%-s\t%-4s\t%-2s\t%-12s\t%-10s\n", "姓名", "年龄", "性别", "电话号码", "居住地址");
for (int i = 0; i < pc->length; i++)
{
printf("%-s\t%-4d\t%-2s\t%-12s\t%-10s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].telephone,
pc->data[i].address);
}
}
}
//销毁通讯录
void DestoryContact(struct Contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->capacity = 0;
pc->length = 0;
}
//保存通讯录
void SaveContact(struct Contact* pc)
{
//以只写的方式打开指定二进制文件Contact.dat,没有就创建
FILE* p = fopen("Contact.dat", "wb");
if (p == NULL)
{
//利用strerror函数来打印错误原因
printf("%s\n", strerror(errno));
return;
}
for (int i = 0; i < pc->length; i++)
{
//二进制输出信息到文件中
fwrite(pc->data + i, sizeof(struct PeoInfor), 1, p);
}
fclose(p);
p = NULL;
printf("保存成功!\n");
}
test.c
#include"contact.h"
//显示菜单
void menu()
{
printf("---------------------------------\n");
printf("------- This is a contact! ------\n");
printf("-------------1.add---------------\n");
printf("-------------2.modify------------\n");
printf("-------------3.delete------------\n");
printf("-------------4.sort--------------\n");
printf("-------------5.search------------\n");
printf("-------------6.show--------------\n");
printf("-------------7.save--------------\n");
printf("-------------0.exit--------------\n");
printf("---------------------------------\n");
}
void test()
{
int input = 0;
//创建一个通讯录
struct Contact con;
//初始化通讯录
InitContact(&con);
do
{
menu();
printf("请选择要进行的操作:");
scanf("%d", &input);
switch (input)
{
case Add:
//添加个人信息
AddContact(&con);
break;
case Modify:
//修改个人信息
ModifyContact(&con);
break;
case Delete:
//删除个人信息
DeleteContact(&con);
break;
case Sort:
//排序个人信息
SortContact(&con);
break;
case Search:
//查找指定联系人
SearchContact(&con);
break;
case Show:
//显示个人信息
ShowContact(&con);
break;
case Save:
//保存通讯录到文件中
SaveContact(&con);
break;
case Exit:
printf("退出通讯录!\n");
//销毁通讯录
DestoryContact(&con);
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
下面是运行结果展示
添加人员信息
依次存入5个联系人的消息并显示
修改人员信息
可以看到张琪的年龄已修改
删除个人信息
排序通讯录
保存通讯录