目录
1、功能菜单
2、通讯录结构体
1、通讯录的初始化及加载信息
2、添加信息
3、删除信息
4、查找信息
5、展示信息
6、修改信息
7、排序信息
8、保存信息
9、退出并销毁通讯录
感谢阅读,如有错误请批评指正
一、通讯录基本结构的实现
1、功能菜单
根据通讯录所要实现的功能,设计菜单的选择功能。通过switch case语句实现简单的功能选择。
2、通讯录结构体
代码如下:
# define MAX_NAME 20 //采用宏 定义名字的数据类型的大小,方便后期对数据进行维护
# define MAX_SEX 5 //性别
# define MAX_TEL 12 //电话
# define MAX_ADDR 30 //地址
enum option //由于枚举常量在不初始化的情况下默认从0开始依次递增1,所以这里可以用枚举常量来一一列
举功能,提高代码的可读性。
{
EXIT, //0
ADD, //1
DEL, //2
SEARCH,
MODIFY,
SHOW,
SORT,
SAVE //7
};
typedef struct peopleInfo //定义一个结构体数据类型,描述通讯录中人的信息,包含5个成员;
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tel[MAX_TEL];
char addr[MAX_ADDR];
}peopleInfo;
//通讯录类型
typedef struct contact
{
struct peopleInfo *data; //存放人的信息;
int size; //记录当前已有元素个数;
int capacity; //当前通讯录的最大容量;
}con;
void menu()
{
printf("*********************************\n");
printf("**** 1.add 2.del ****\n");
printf("**** 3.search 4.modify ****\n");
printf("**** 5.show 6.sort ****\n");
printf("**** 7.save 0.exit ****\n");
printf("*********************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:->");
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 :
//销毁通讯录-释放动态开辟的内存
destroycontact(&con);
printf("退出通讯录\n");
break;
case SAVE:
savecontact(&con);
break;
default :
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
二、通讯录功能的实现
1、通讯录的初始化及加载信息
在main函数中创建一个通讯录结构体后,首先需要对其进行初始化,否则可能出现难以预料的问题。(注意想要通过函数修改主函数内变量的值,就需要在函数调用传变量的地址。函数传参时,参数需要压栈,会有时间和空间上的系统开销,结构体过大时,参数压栈的系统开销比较大,导致性能下降。因此后面的函数调用均用传址的方式进行) 代码如下:
# define DEFAULT_SZ 3 //定义通讯录初始容量为3个信息;
void initcontact(struct contact* ps)
{
ps->data = (struct peopleInfo*)malloc(DEFAULT_SZ*sizeof(struct peopleInfo)); //使用
malloc()函数动态开辟3个元素的空间;
if (ps->data == NULL) //设置通讯录最初只有0个元素;
{
return;
}
ps->size = 0;
ps->capacity = DEFAULT_SZ;
loadcontact(ps);//把文件中已经存放的通讯录的信息加载到通讯录中
}
void checkcapacity(struct contact* ps);//声明函数;检查当前通讯录是否已满
void loadcontact(contact* ps) //通讯录的信息加载
{
peopleInfo tmp= {0};
FILE*pfRead = fopen("contact.dat", "rb");
if (pfRead == NULL) //判断文件是否存在
{
printf("loadcontact::%s\n", strerror(errno));
return;
}
//读取文件,存放到通讯录中;
while (fread(&tmp, sizeof(peopleInfo), 1, pfRead))
{
checkcapacity(ps);
ps->data[ps->size] = tmp;
ps->size++;
}
fclose(pfRead);
pfRead = NULL;
}
2、添加信息
添加信息时要先检查当前通讯录是否已满,如果已满则需要扩容,否则直接添加即可。代码如下:
void checkcapacity(struct contact* ps) //判断通讯录是否已满,进行单独封装,方便后续功能的使
用,降低程序的重复性。
{
if (ps->size == ps->capacity)
{
//增容
struct peopleInfo* ptr = (struct peopleInfo*)realloc(ps->data, (ps->capacity+2)*sizeof(peopleInfo)); //使用realloc()函数进行扩容;
if (ptr != NULL)
{
ps->data = ptr;
ps->capacity += 2;//扩容成功后,注意容量计数的增加;
printf("扩容成功\n");
}
else
{
printf("扩容失败\n");
}
}
}
void addcontact(struct contact* ps)
{
//检测当前通讯录的容量
//1.如果满了,就增加空间
//2.如果不满,啥事都不干
checkcapacity(ps);
//增加数据
printf("请输入名字:>");
scanf("%s", ps->data[ps->size].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[ps->size].age));
printf("请输入性别:>");
scanf("%s", ps->data[ps->size].sex);
printf("请输入电话:>");
scanf("%s", ps->data[ps->size].tel);
printf("请输入地址:>");
scanf("%s", ps->data[ps->size].addr);
ps->size++;
printf("添加成功\n");
}
3、删除信息
删除信息时,需要输入要删除信息的姓名,然后找到这个信息再删除。由于这里采用名字来定位信息的代码在之后也会多次用到,所以这里将它封装为函数来调用,这样可以让代码更加简洁,同时可读性更好。代码如下:
static int findbyname(const struct contact* ps, char name[MAX_NAME])//因在删除,查找,修改等功能中均需先进行元素的查找后,再完成相应的功能,为避免代码重复,封装一个查找函数进行简化;
{//static 限定本函数只在该文件中使用;
int i = 0;
for (i = 0; i < ps->size; i++)
{
if(0 == strcmp(ps->data[i], name))
{
return i;
}
}
return -1;//找不到的情况;
}
void delcontact(struct contact* ps)
{
char name[MAX_NAME];
printf("请输入要删除人的名字:>");
scanf("%s", name);
//1.查找要删除的人在什么位置;
//找到了返回名字所在元素的下标
//找不到返回 -1;
int pos = findbyname(ps, name);
// 2.删除
if (pos == -1)
{
printf("要删除的人不存在\n");
}
else
{
//删除数据;
int j = 0;
for (j = pos; j < ps->size-1; j++)//让被删除元素后面的元素向前移动一个位置,完成删除;
{
ps->data[j] = ps->data[j+1];
}
ps->size--;
printf("删除成功\n");
}
}
4、查找信息
通过findbyname()函数来实现需查找信息的定位,完成查找。代码如下:
void searchcontact(const struct contact* ps)
{
char name[MAX_NAME];
printf("请输入要查找人的名字:>");
scanf("%s", name);
int pos = findbyname(ps, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
}
else
{
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印标题;
for (i = 0; i < ps->size; i++)
{
printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].tel,
ps->data[i].addr);
}
}
}
5、展示信息
遍历通讯录信息。代码如下:
void showcontact(const struct contact* ps)
{
if (ps->size == 0)
{
printf("当前通讯录为空\n");
}
else
{
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印标题;
for (i = 0; i < ps->size; i++)
{
printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].tel,
ps->data[i].addr);
}
}
6、修改信息
通过findbyname()函数来实现需查找信息的定位,完成修改。代码如下:
void modifycontact(struct contact* ps)
{
char name[MAX_NAME];
printf("请输入要修改人的名字:>");
scanf("%s", name);
int pos = findbyname(ps, name);
if (pos == -1)
{
printf("要修改人的信息不存在\n");
}
else
{
printf("请输入名字:>");
scanf("%s", ps->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[pos].age));
printf("请输入性别:>");
scanf("%s", ps->data[pos].sex);
printf("请输入电话:>");
scanf("%s", ps->data[pos].tel);
printf("请输入地址:>");
scanf("%s", ps->data[pos].addr);
printf("修改完成\n");
}
}
7、排序信息
代码如下:
void sortcontact(struct contact* ps)
{
int i, j, t;
for (i=0; i<ps->size; i++)
{
for(j=i+1; j<pArr->size; j++)
{
if (ps->data[i].age > ps->data[j].age) //通过年龄来进行升序排列
{
t = ps->data[i].age;
ps->data[i].age = ps->data[j].age;
ps->data[j].age = t;
}
}
}
}
8、保存信息
代码如下:
void savecontact(contact* ps)
{
FILE* pfwrite = fopen("contact.dat", "wb");
if (pfwrite == NULL)
{
printf("%s\n", strerror(errno));
return ;
}
//写通讯录中数据到文件中
int i = 0;
for (i = 0; i < ps->size; i++)
{
fwrite(&(ps->data[i]), sizeof(peopleInfo), 1, pfWrite);
}
fclose(pfWrite);
pfWrite = NULL;
}
9、退出并销毁通讯录
代码如下:
void destroycontact(contact* ps)
{
free(ps->data);
ps->data = NULL;
}
三、完整代码
contact.h
# define DEFAULT_SZ 3
# define MAX_NAME 20
# define MAX_SEX 5
# define MAX_TEL 12
# define MAX_ADDR 30
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
enum option
{
EXIT, //0
ADD, //1
DEL,
SEARCH,
MODIFY,
SHOW,
SORT
};
typedef struct peopleInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tel[MAX_TEL];
char addr[MAX_ADDR];
}peopleInfo;
//通讯录类型
typedef struct contact
{
struct peopleInfo *data; //存放信息;
int size;//记录当前已有元素个数;
int capacity;//当前通讯录的最大容量;
}con;
//声明函数
void initcontact(struct contact* ps);//初始化通讯录的函数
void addcontact(struct contact* ps);//增加一个信息到通讯录;
void showcontact(const struct contact* ps);//打印通讯录中的信息
void delcontact(struct contact* ps);//删除指定的联系人
void searchcontact(const struct contact* ps);//查找指定的人信息
void modifycontact(struct contact* ps);//修改指定联系人
void sortcontact(struct contact* ps);//排序通讯录内容;
void destroycontact(contact* ps);//释放动态开辟的内存
void savecontact(contact* ps);//保存通讯录信息
contact.c
# include "contact.h"
void initcontact(struct contact* ps)
{
ps->data = (struct peopleInfo*)malloc(DEFAULT_SZ*sizeof(struct peopleInfo)); //动态开辟3个元素的空间;
if (ps->data == NULL); //设置通讯录最初只有0个元素;
{
return;
}
ps->size = 0;
ps->capacity = DEFAULT_SZ;
}
void checkcapacity(struct contact* ps)
{
if (ps->size == ps->capacity)
{
//增容
struct peopleInfo* ptr = realloc(ps->data, (ps->capacity+2)*sizeof(peopleInfo));
if (ptr != NULL)
{
ps->data = ptr;
ps->capacity += 2;
printf("扩容成功\n");
}
else
{
printf("扩容失败\n");
}
}
}
void addcontact(struct contact* ps)
{
//检测当前通讯录的容量
//1.如果满了,就增加空间
//2.如果不满,啥事都不干
checkcapacity(ps);
//增加数据
printf("请输入名字:>");
scanf("%s", ps->data[ps->size].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[ps->size].age));
printf("请输入性别:>");
scanf("%s", ps->data[ps->size].sex);
printf("请输入电话:>");
scanf("%s", ps->data[ps->size].tel);
printf("请输入地址:>");
scanf("%s", ps->data[ps->size].addr);
ps->size++;
printf("添加成功\n");
}
void showcontact(const struct contact* ps)
{
if (ps->size == 0)
{
printf("当前通讯录为空\n");
}
else
{
int i = 0;
printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印标题;
for (i = 0; i < ps->size; i++)
{
printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].tel,
ps->data[i].addr);
}
}
}
static int findbyname(const struct contact* ps, char name[MAX_NAME])
{
int i = 0;
for (i = 0; i < ps->size; i++)
{
if(0 == strcmp(ps->data[i], name))
{
return i;
}
}
return -1;//找不到的情况;
}
void delcontact(struct contact* ps)
{
char name[MAX_NAME];
printf("请输入要删除人的名字:>");
scanf("%s", name);
//1.查找要删除的人在什么位置;
//找到了返回名字所在元素的下标
//找不到返回 -1;
int pos = findbyname(ps, name);
// 2.删除
if (pos == -1)
{
printf("要删除的人不存在\n");
}
else
{
//删除数据;
int j = 0;
for (j = pos; j < ps->size-1; j++)//让被删除元素后面的元素向前移动一个位置,完成删除;
{
ps->data[j] = ps->data[j+1];
}
ps->size--;
printf("删除成功\n");
}
}
void searchcontact(const struct contact* ps)
{
char name[MAX_NAME];
printf("请输入要查找人的名字:>");
scanf("%s", name);
int pos = findbyname(ps, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
}
else
{
printf("%-20s\t%-4s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印标题;
printf("%-20s\t%-4d\t%-5s\t%-12s\t%-20s\n",
ps->data[i].name,
ps->data[i].age,
ps->data[i].sex,
ps->data[i].tel,
ps->data[i].addr);
}
}
void modifycontact(struct contact* ps)
{
char name[MAX_NAME];
printf("请输入要修改人的名字:>");
scanf("%s", name);
int pos = findbyname(ps, name);
if (pos == -1)
{
printf("要修改人的信息不存在\n");
}
else
{
printf("请输入名字:>");
scanf("%s", ps->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(ps->data[pos].age));
printf("请输入性别:>");
scanf("%s", ps->data[pos].sex);
printf("请输入电话:>");
scanf("%s", ps->data[pos].tel);
printf("请输入地址:>");
scanf("%s", ps->data[pos].addr);
printf("修改完成\n");
}
}
void sortcontact(struct contact* ps)
{
int i, j, t;
for (i=0; i<ps->size; i++)
{
for(j=i+1; j<pArr->size; j++)
{
if (ps->data[i].age > ps->data[j].age)
{
t = ps->data[i].age;
ps->data[i].age = ps->data[j].age;
ps->data[j].age = t;
}
}
}
}
void destroycontact(contact* ps)
{
free(ps->data);
ps->data = NULL;
}
void savecontact(contact* ps)
{
FILE* pfwrite = fopen("contact.dat", "wb");
if (pfwrite == NULL)
{
printf("%s\n", strerror(errno));
return ;
}
int i = 0;
for (i = 0; i < ps->size; i++)
{
fwrite(&(ps->data[i]), sizeof(peopleInfo), 1, pfWrite);
}
fclose(pfWrite);
pfWrite = NULL;
}
test.c
void menu()
{
printf("*********************************\n");
printf("**** 1.add 2.del ****\n");
printf("**** 3.search 4.modify ****\n");
printf("**** 5.show 6.sort ****\n");
printf("**** 0.exit 7.save ****\n");
printf("*********************************\n");
}
int main()
{
int input = 0;
//创建通讯录信息
struct contact con;//con就是通讯录,里边包含data指针和capacity和size;
//初始化通讯录
initcontact(&con);
do
{
menu();
printf("请选择:->");
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 :
//销毁通讯录-释放动态开辟的内存
destroycontact(&con);
printf("退出通讯录\n");
break;
case SAVE:
savecontact(&con);
break;
default :
printf("选择错误\n");
break;
}
} while (input);
return 0;
}