上一篇博客,写了通讯录的简单版本,虽然需要的功能基本都有,但是仍然存在许多问题:
1.当通讯录的实际人数只有几十个时,开辟500个人的信息的内存,显然会浪费,当通讯录人数多于500时,没有足够的内存去存储这么多人的信息;
2.当程序退出时,输入的信息无法保存下来,程序再次打开时,原先输入的数据已经没有了。
鉴于以上两点,对程序进行了改进:一方面,使用malloc,realloc,free等函数动态开辟内存,当人数增加时,可以动态增加内存;另一方面,使用fread,fwrite,fopen,fclose等函数,在程序退出时将数据写入文件中进行保存,当程序再次打开时,可以将文件中的数据加载到程序中。
在功能上,与上一版一致,包括联系人的添加,删除,修改,查找,展示,排序,清空及退出。
头文件contact.h
#ifndef __CONTACT_H__
#define __CONTACT_H__
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#define NAME_MAX 20//姓名能占用的最大空间
#define SEX_MAX 5//性别
#define ADDR_MAX 30//地址
#define TELE_MAX 12 //电话
#define DEFAULT_SZ 3 //默认容量
#define DEFAULT_ADD 2//增容增加的容量
#define FILENAME "contact.dat"//文件名称
typedef struct PeoInfo
{
char name[NAME_MAX];
int age;
char sex[SEX_MAX];
char addr[ADDR_MAX];
char tele[TELE_MAX];
}PeoInfo;//struct PeoInfo a; <=> PeoInfo a;
typedef struct Contact
{
PeoInfo* data;//数据存储区域
int sz;//有效元素个数
int capacity;//当前容量
}Contact, *pContact;
//函数声明
void InitContact(pContact pcon);//初始化
void AddContact(pContact pcon);//添加
void ShowContact(const pContact pcon);//浏览
void DelContact(pContact pcon);//删除
void SearchContact(pContact pcon);//查找
void ModifyContact(pContact pcon);//修改
void SortContach(pContact pcon);//排序
void ClearContact(pContact pcon);//清空
void DestroyContact(pContact pcon);//释放动态内存
void SaveContactData(pContact pcon);//保存数据,写入文件
void LoadContactData(pContact pcon);//加载信息
#endif
源文件contact.c
#include "contact.h"
void InitContact(pContact pcon)//开辟动态内存并初始化
{
pcon->sz = 0;
pcon->data = malloc(DEFAULT_SZ*sizeof(PeoInfo));
if (pcon->data == NULL)
{
perror("use malloc");
exit(EXIT_FAILURE);
}
memset(pcon->data, 0, DEFAULT_SZ*sizeof(PeoInfo));
pcon->capacity = DEFAULT_SZ;
LoadContactData(pcon);
}
static void CheckCapacity(pContact pcon)//检查是否需要增容,static修饰的函数只能在本文件中使用
{
if (pcon->sz == pcon->capacity)
{
//增容
PeoInfo* ptr = realloc(pcon->data, (pcon->capacity + DEFAULT_ADD)*sizeof(PeoInfo));
if (ptr == NULL)
{
perror("use realloc");
exit(EXIT_FAILURE);//失败退出
}
else
pcon->data = ptr;
pcon->capacity += DEFAULT_ADD;
//printf("增容成功\n");
}
}
void AddContact(pContact pcon)//添加
{
assert(pcon);//断言,用于检验是否为NULL,便于调试,
//若函数错误的接受了一个NULL参数,程序就会停止,并打印出提示信息;
//若表达式为真(非零),它不会打印任何东西,程序继续执行。
CheckCapacity(pcon);
printf("请输入名字:> ");
scanf("%s", pcon->data[pcon->sz].name);
printf("请输入年龄:> ");
scanf("%d", &pcon->data[pcon->sz].age);
printf("请输入性别:> ");
scanf("%s", pcon->data[pcon->sz].sex);
printf("请输入地址:> ");
scanf("%s", pcon->data[pcon->sz].addr);
printf("请输入电话:> ");
scanf("%s", pcon->data[pcon->sz].tele);
pcon->sz++;
printf("\n添加成功!\n");
}
void ShowContact(const pContact pcon)//浏览所有联系人
{
int i = 0;
assert(pcon);
printf("%8s\t%8s\t%8s\t%8s\t%8s\n", "name", "age", "sex", "addr", "tele");
for (i = 0; i < pcon->sz; i++)
{
printf("%8s\t", pcon->data[i].name);
printf("%8d\t", pcon->data[i].age);
printf("%8s\t", pcon->data[i].sex);
printf("%8s\t", pcon->data[i].addr);
printf("%8s\n", pcon->data[i].tele);
}
}
static int find(pContact pcon,char *name1)//查找函数,如果找到返回联系人所在的排名,否则返回-1
{
int i = 0;
assert(pcon);
assert(name1);
for (i = 0; i < pcon->sz; i++)
{
if (strcmp(pcon->data[i].name, name1) == 0)
{
return i;
}
}
return -1;
}
void DelContact(pContact pcon)//删除
{
int find_name;
int i = 0;
char name1[NAME_MAX];
assert(pcon);
printf("请输入删除的人姓名:> ");
scanf("%s", name1);
find_name = find(pcon, name1);
if (find_name != -1)
{
for (i = find_name; i < pcon->sz; i++)
pcon->data[i] = pcon->data[i + 1];//后一个人信息覆盖到前一个
pcon->sz--;
printf("删除成功\n");
}
}
void SearchContact(pContact pcon)//查找联系人
{
int ret = 0;
int find_name = 0;
char name1[NAME_MAX];
assert(pcon);
do
{
printf("请输入要查找的人名字:> ");
scanf("%s", name1);
find_name = find(pcon, name1);
if (find_name != -1)
{
printf("\n");
printf("姓名:%s\n", pcon->data[find_name].name);
printf("年龄:%d\n", pcon->data[find_name].age);
printf("性别:%s\n", pcon->data[find_name].sex);
printf("地址:%s\n", pcon->data[find_name].addr);
printf("电话:%s\n", pcon->data[find_name].tele);
}
else
printf("没有找到此人\n");
printf("是否继续,继续查找请选择1,结束查找请选择0:> ");
scanf("%d", &ret);
while (ret != 0 && ret != 1)
{
printf("选择错误!请重新选择:> ");
scanf("%d", &ret);
}
} while (ret);
}
void ModifyContact(pContact pcon)//修改信息
{
int ret = 0;
int find_name = 0;
char name1[NAME_MAX];
assert(pcon);
do
{
printf("请输入要修改的人名字:> ");
scanf("%s", name1);
find_name = find(pcon, name1);
if (find_name != -1)
{
printf("\n");
printf("请输入修改后的姓名:");
scanf("%s", pcon->data[find_name].name);
printf("请输入修改后的年龄:");
scanf("%d", &pcon->data[find_name].age);
printf("请输入修改后的性别:");
scanf("%s", pcon->data[find_name].sex);
printf("请输入修改后的地址:");
scanf("%s", pcon->data[find_name].addr);
printf("请输入修改后的电话:");
scanf("%s", pcon->data[find_name].tele);
}
else
printf("没有找到此人\n");
printf("是否继续,继续修改请选择1,结束修改请选择0:> ");
scanf("%d", &ret);
while (ret != 0 && ret != 1)
{
printf("选择错误!请重新选择:> ");
scanf("%d", &ret);
}
} while (ret);
}
void SortContach(pContact pcon)//对联系人按姓名排序
{
int i = 0;
int j = 0;
assert(pcon);
printf("姓名从A-Z的顺序为:\n");
for (i = 0; i < pcon->sz; i++)
{
for (j = 0; j < pcon->sz - i - 1; j++)
{
if (strcmp(pcon->data[j].name, pcon->data[j + 1].name)>0)
{
PeoInfo tmp;
tmp = pcon->data[j];
pcon->data[j] = pcon->data[j + 1];
pcon->data[j + 1] = tmp;
}
}
}
ShowContact(pcon);
}
void ClearContact(pContact pcon)//清空联系人
{
int ret = 0;
assert(pcon);
printf("确定清空?确定选择1,取消选择0:) ");
scanf("%d", &ret);
if (ret == 1)
{
pcon->sz = 0;//没有显示
memset(pcon->data, 0, sizeof(pcon->data));
printf("删除成功\n");
}
while (ret != 0 && ret != 1)
{
printf("选择错误!请重新选择:) ");
scanf("%d", &ret);
}
}
void DestroyContact(pContact pcon)//释放动态内存
{
free(pcon->data);
pcon->data = NULL;
pcon->capacity = 0;
pcon->sz = 0;
}
void SaveContactData(pContact pcon)//保存数据写入文件
{
FILE* pfout = fopen(FILENAME, "w");
int i = 0;
if (pfout == NULL)
{
perror("SaveContactData::fopen");//报错
exit(EXIT_FAILURE);
}
for (i = 0; i < pcon->sz; i++)
{
fwrite(pcon->data + i, sizeof(PeoInfo), 1, pfout);
}
fclose(pfout);
}
void LoadContactData(pContact pcon)//加载文件中的数据
{
FILE* pfin = fopen(FILENAME, "r");
PeoInfo tmp = { 0 };
if (pfin == NULL)
{
perror("LoadContactData::fopen");
exit(EXIT_FAILURE);
}
while (fread(&tmp, sizeof(PeoInfo), 1, pfin))
{
CheckCapacity(pcon);
pcon->data[pcon->sz] = tmp;
pcon->sz++;
}
fclose(pfin);
}
测试函数test.c
#define _CRT_SECURE_NO_WARNINGS
#include "contact.h"
void menu()//菜单
{
printf("\n");
printf("******************************************\n");
printf("***********1.添加 2.浏览 **********\n");
printf("***********3.删除 4.查找 **********\n");
printf("***********5.修改 6.排序 **********\n");
printf("***********7.清空 0.退出 **********\n");
printf("******************************************\n");
}
enum//枚举
{
EXIT,//0.退出
ADD,//1.添加
SHOW,//2.浏览
DEL,//3.删除
SEARCH,//4.查找
MODIFY,//5.修改
SORT,//6.排序
CLEAR,//7.清空
};
void test()
{
int input = 0;
Contact my_con;
InitContact(&my_con);
do
{
menu();
printf("\n请输入你的选择:> ");
scanf("%d", &input);
switch (input)
{
case ADD://添加联系人
AddContact(&my_con);
break;
case SHOW://浏览联系人
ShowContact(&my_con);
break;
case DEL://删除联系人
DelContact(&my_con);
break;
case SEARCH://查找联系人
SearchContact(&my_con);
break;
case MODIFY://修改联系人
ModifyContact(&my_con);
break;
case SORT://按姓名排序联系人
SortContach(&my_con);
break;
case CLEAR://清空联系人
ClearContact(&my_con);
break;
case EXIT://退出,写入信息到文件,并释放开辟的动态内存
SaveContactData(&my_con);
DestroyContact(&my_con);
break;
}
} while (input);
}
int main()
{
test();
return 0;
}