这一片博客我会改进上次的静态+文件通讯录,先分析哪里可以改,然后再下手,最后测试。 先从动态方面开始改。
首先是储存联系人的潍坊可以更改,因为你写了100不一定能存上100个位置,这样容易浪费空间,或者是100个不够你还要手动去更改,很麻烦,我们可以让他刚开始分配一小块那日村,不够就一直扩容。 我们这里初始能放3个联系人,不够的话每次加2个。(数量少方便测试)
首先,因为动态内存函数的性质,我们需要把结构体: contacts.h
typedef struct person
{
char name[20];//名字
int age;//年龄
char sex[20];//性别
char phone[20];//电话
char location[20];//住址
}person;
typedef struct contacts
{
person *data;//存放人信息的位置
int count;//记录通讯录的人数
int capacity;//记录当前通讯录有多少人
}contacts;
存放人信息的位置给更改成指针,然后需要一个变量来统计通讯录的容量。 首先改一下初始化通讯录的函数: contacts.c
int initialize(contacts* pc)
{
assert(pc != NULL);
pc->count = 0;//将计数的变量初始化为0
pc->data = calloc(3,sizeof(person));//开辟一个动态内存,然后把地址传给data指针
if (pc->data == NULL)
{
printf("initialize:%s",strerror(errno));
return 1;
}
pc->capacity = 3;//一开始让通讯录只有三个人的容量
return 0;
}
这次改添加联系人的地方 既然是无限扩容,就没有通讯录已满这一说,我们把判断人是不是满给改掉。 当然,把增容的内容封装成一个函数更容易维护: contacts.c
void capacity_increase(contacts* pc)//增容
{
if (pc->count == pc->capacity)
{
person* str = (person*)realloc(pc->data, sizeof(person) * (pc->capacity + 2));
if (str == NULL)
{
printf("addcontact:%s", strerror(errno));
return 1;
}
else
{
pc->data = str;
pc->capacity += 2;
}
printf("增容成功\n");
}
}
int addcontact(contacts* pc)
{
assert(pc != NULL);//断言pc指向的位置不是空指针
capacity_increase(pc);//增容
printf("姓名:");
scanf("%s", pc->data[pc->count].name);
printf("年龄:");
scanf("%d", &(pc->data[pc->count].age));
printf("性别:");
scanf("%s", pc->data[pc->count].sex);
printf("电话号:");
scanf("%s", pc->data[pc->count].phone);
printf("家庭住址:");
scanf("%s", pc->data[pc->count].location);
pc->count++;
printf("增加成功\n");
}
当然,退出程序的时候也要释放掉开辟的内存,所以写一个销毁内存的函数。
void destroycontact(contacts* pc)
{
assert(pc != NULL);
free(pc->data);
pc->data = NULL;
}
contacts.h
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#define MAX 100//通讯录最大人数
//定义的结构体
typedef struct person
{
char name[20];//名字
int age;//年龄
char sex[20];//性别
char phone[20];//电话
char location[20];//住址
}person;
typedef struct contacts
{
person* data;//存放人信息的位置
int count;//记录通讯录的人数
int capacity;//记录当前通讯录有多少人
}contacts;
//函数声明区
int initialize(contacts* pc);//初始化通讯录
int addcontact(contacts* pc);//输入联系人信息
void showcontact(const contacts* pc);//打印通讯录
int delcontact(contacts* pc);//删除联系人
int modifycontact(contacts* pc);//修改联系人信息
int findcontact(contacts* pc);//查找联系人
void sortcontact(contacts* pc);//排序通讯录
void destroycontact(contacts* pc);//动态内存销毁
contacts.c
#include "contacts.h"
int find_out(char* p1, contacts* p2)
{
assert(p1 != NULL);
assert(p2 != NULL);
int i = 0;
for (i = 0; i < p2->count; i++)
{
if (!strcmp(p1, p2->data[i].name))//如果相等就返回0,前面加了!操作符,所以非零条件不成立
return i;
}
return -1;
}
void capacity_increase(contacts* pc)//增容
{
if (pc->count == pc->capacity)
{
person* str = (person*)realloc(pc->data, sizeof(person) * (pc->capacity + 2));
if (str == NULL)
{
printf("addcontact:%s", strerror(errno));
return 1;
}
else
{
pc->data = str;
pc->capacity += 2;
}
printf("增容成功\n");
}
}
int initialize(contacts* pc)
{
assert(pc != NULL);
pc->count = 0;//将计数的变量初始化为0
pc->data = (person*)calloc(3,sizeof(person));
if (pc->data == NULL)
{
printf("initialize:%s",strerror(errno));
return 1;
}
pc->capacity = 3;
return 0;
}
int addcontact(contacts* pc)
{
assert(pc != NULL);//断言pc指向的位置不是空指针
capacity_increase(pc);//增容
printf("姓名:");
scanf("%s", pc->data[pc->count].name);
printf("年龄:");
scanf("%d", &(pc->data[pc->count].age));
printf("性别:");
scanf("%s", pc->data[pc->count].sex);
printf("电话号:");
scanf("%s", pc->data[pc->count].phone);
printf("家庭住址:");
scanf("%s", pc->data[pc->count].location);
pc->count++;
printf("增加成功\n");
}
void showcontact(const contacts* pc)
{
assert(pc != NULL);
int i = 0;
printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20\t\n", "姓名", "年龄", "性别", "电话号", "家庭住址");
for (i = 0; i < pc->count; i++)
{
printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20\t\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].phone,
pc->data[i].location);
}
}
int delcontact(contacts* pc)
{
assert(pc != NULL);
char name[20] = { 0 };
printf("输入此人姓名\n");
scanf("%s", name);
int i = find_out(name, pc);
if (i == -1)
{
printf("无此人信息\n");
return 1;
}
pc->count = pc->count - 1;
while (i < pc->count)
{
pc->data[i] = pc->data[i + 1];
i++;
}
printf("删除成功\n");
}
int modifycontact(contacts* pc)
{
assert(pc != NULL);
printf("输入此人姓名\n");
char name[20] = { 0 };
scanf("%s", name);
int i = find_out(name, pc);
if (i == -1)
{
printf("无此人信息\n");
return 1;
}
printf("请输入要修改的信息\n");
printf("姓名:");
scanf("%s", pc->data[i].name);
printf("年龄:");
scanf("%d", &(pc->data[i].age));
printf("性别:");
scanf("%s", pc->data[i].sex);
printf("电话号:");
scanf("%s", pc->data[i].phone);
printf("家庭住址:");
scanf("%s", pc->data[i].location);
printf("修改成功\n");
}
int findcontact(contacts* pc)
{
assert(pc != NULL);
printf("输入此人姓名\n");
char name[20] = { 0 };
scanf("%s", name);
int i = find_out(name, pc);
if (i == -1)
{
printf("无此人信息\n");
return 1;
}
printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20\t\n", "姓名", "年龄", "性别", "电话号", "家庭住址");
printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20\t\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].phone,
pc->data[i].location);
}
int estimate(const void* p1, const void* p2)
{
return strcmp(((person*)p1)->name, ((person*)p2)->name);
}
void sortcontact(contacts* pc)
{
assert(pc != NULL);
qsort(pc->data, pc->count, sizeof(person), estimate);
printf("排序成功\n");
}
void destroycontact(contacts* pc)
{
assert(pc != NULL);
free(pc->data);
pc->data = NULL;
}
test.c
#include "contacts.h"
enum list
{
EXIT,
ADD,
DEL,
MODIFY,
FIND,
SHOW,
SORT
};
void catalogue()
{
printf("*********************************\n");
printf("*** 1.add 2.del ***\n");
printf("*** 3.modify 4.find ***\n");
printf("*** 5.show 6.sort ***\n");
printf("*** 0.exit ***\n");
printf("*********************************\n");
}
int main()
{
int n = 0;
contacts con;//通讯录
initialize(&con);//初始换通讯录
do
{
catalogue();//通讯录菜单
printf("请选择>");
scanf("%d", &n);//选择要做什么
switch (n)
{
case EXIT://退出程序
destroycontact(&con);
printf("退出通讯录\n");
break;
case ADD://添加联系人
addcontact(&con);
break;
case DEL://删除联系人
delcontact(&con);
break;
case FIND://查找联系人
findcontact(&con);
break;
case MODIFY://修改联系人信息
modifycontact(&con);
break;
case SHOW://展示联系人
showcontact(&con);
break;
case SORT://排序通讯录
sortcontact(&con);
break;
default:
printf("输入错误请重新输入\n");
}
} while (n);
return 0;
}
无论是静态通讯录还是动态的通讯录其实都是在内存里面,第二次打开后之前的数据就全都没有了,那么这次我们让数据储存到文件里。 contacts.c
void stockpilecontact(contacts* pc)
{
assert(pc != NULL);
FILE* p1 = fopen("contacts.txt", "wb");//打开文件,以二进制方式写
if (p1 == NULL)
{
perror("SaveContact");
return;
}
int i = 0;
for (i = 0; i < pc->count; i++)//输入通讯录中的成员信息
{
fwrite(pc->data + i, sizeof(person), 1, p1);
}
fclose(p1);//关闭文件
p1 = NULL;
}
运行之后我们添加三个人的信息
然后打开我们的文件目录来看看:
这个就是我们刚刚生成的文件,里面有我们输入三个联系人的信息:
有些地方是乱码看不懂是因为这是以二进制形式输入。 现在我们想办法让这个通讯录读取这些联系人。 打开文件的地方当然要在初始化通讯录的时候读取文件内容。 读取要注意,我们把读取的联系人存在内存时,要先判断能不能放的下,放不下就要增容。 contacts.c
void capacity_increase(contacts* pc)//增容
{
if (pc->count == pc->capacity)
{
person* str = (person*)realloc(pc->data, sizeof(person) * (pc->capacity + 2));
if (str == NULL)
{
printf("addcontact:%s", strerror(errno));
return 1;
}
else
{
pc->data = str;
pc->capacity += 2;
}
printf("增容成功\n");
}
}
void uploadcontacts(contacts* pc)//读取联系人函数
{
FILE* p2 = fopen("contacts.txt", "rb");//打开文件二进制方式读
if (p2 == NULL)
{
perror("OpenContacts");
return 1;
}
person arr = { 0 };//文件读取数据的储存位置
while (fread(&arr, sizeof(person), 1, p2))
{
capacity_increase(pc);//判断是否需要增容
pc->data[pc->count] = arr;//存入内存中
pc->count++;
}
fclose(p2);//关闭文件
p2=NULL;
}
int initialize(contacts* pc)
{
assert(pc != NULL);
pc->count = 0;//将计数的变量初始化为0
pc->data = (person*)calloc(3,sizeof(person));
if (pc->data == NULL)
{
printf("initialize:%s",strerror(errno));
return 1;
}
pc->capacity = 3;
uploadcontacts(pc);// 读取通讯录
return 0;
}
运行一下看看:
有上次输入的联系人。 我又添加了一个联系人,之后退出,再次打开然后展示:
contacts.h
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#define MAX 100//通讯录最大人数
//定义的结构体
typedef struct person
{
char name[20];//名字
int age;//年龄
char sex[20];//性别
char phone[20];//电话
char location[20];//住址
}person;
typedef struct contacts
{
person* data;//存放人信息的位置
int count;//记录通讯录的人数
int capacity;//记录当前通讯录有多少人
}contacts;
//函数声明区
int initialize(contacts* pc);//初始化通讯录
int addcontact(contacts* pc);//输入联系人信息
void showcontact(const contacts* pc);//打印通讯录
int delcontact(contacts* pc);//删除联系人
int modifycontact(contacts* pc);//修改联系人信息
int findcontact(contacts* pc);//查找联系人
void sortcontact(contacts* pc);//排序通讯录
void destroycontact(contacts* pc);//动态内存销毁
void stockpilecontact(contacts* pc);//储存到文件里
void uploadcontacts(contacts* pc);//读取文件
contacts.c
#include "contacts.h"
int find_out(char* p1, contacts* p2)
{
assert(p1 != NULL);
assert(p2 != NULL);
int i = 0;
for (i = 0; i < p2->count; i++)
{
if (!strcmp(p1, p2->data[i].name))//如果相等就返回0,前面加了!操作符,所以非零条件不成立
return i;
}
return -1;
}
void capacity_increase(contacts* pc)//增容
{
if (pc->count == pc->capacity)
{
person* str = (person*)realloc(pc->data, sizeof(person) * (pc->capacity + 2));
if (str == NULL)
{
printf("addcontact:%s", strerror(errno));
return 1;
}
else
{
pc->data = str;
pc->capacity += 2;
}
printf("增容成功\n");
}
}
void uploadcontacts(contacts* pc)//读取联系人函数
{
FILE* p2 = fopen("contacts.txt", "rb");//打开文件二进制方式读
if (p2 == NULL)
{
perror("OpenContacts");
return 1;
}
person arr = { 0 };
while (fread(&arr, sizeof(person), 1, p2))
{
capacity_increase(pc);//判断是否需要增容
pc->data[pc->count] = arr;
pc->count++;
}
fclose(p2);//关闭文件
p2 = NULL;
}
int initialize(contacts* pc)
{
assert(pc != NULL);
pc->count = 0;//将计数的变量初始化为0
pc->data = (person*)calloc(3,sizeof(person));
if (pc->data == NULL)
{
printf("initialize:%s",strerror(errno));
return 1;
}
pc->capacity = 3;
uploadcontacts(pc);// 读取通讯录
return 0;
}
int addcontact(contacts* pc)
{
assert(pc != NULL);//断言pc指向的位置不是空指针
capacity_increase(pc);//增容
printf("姓名:");
scanf("%s", pc->data[pc->count].name);
printf("年龄:");
scanf("%d", &(pc->data[pc->count].age));
printf("性别:");
scanf("%s", pc->data[pc->count].sex);
printf("电话号:");
scanf("%s", pc->data[pc->count].phone);
printf("家庭住址:");
scanf("%s", pc->data[pc->count].location);
pc->count++;
printf("增加成功\n");
}
void showcontact(const contacts* pc)
{
assert(pc != NULL);
int i = 0;
printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20\t\n", "姓名", "年龄", "性别", "电话号", "家庭住址");
for (i = 0; i < pc->count; i++)
{
printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20\t\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].phone,
pc->data[i].location);
}
}
int delcontact(contacts* pc)
{
assert(pc != NULL);
char name[20] = { 0 };
printf("输入此人姓名\n");
scanf("%s", name);
int i = find_out(name, pc);
if (i == -1)
{
printf("无此人信息\n");
return 1;
}
pc->count = pc->count - 1;
while (i < pc->count)
{
pc->data[i] = pc->data[i + 1];
i++;
}
printf("删除成功\n");
}
int modifycontact(contacts* pc)
{
assert(pc != NULL);
printf("输入此人姓名\n");
char name[20] = { 0 };
scanf("%s", name);
int i = find_out(name, pc);
if (i == -1)
{
printf("无此人信息\n");
return 1;
}
printf("请输入要修改的信息\n");
printf("姓名:");
scanf("%s", pc->data[i].name);
printf("年龄:");
scanf("%d", &(pc->data[i].age));
printf("性别:");
scanf("%s", pc->data[i].sex);
printf("电话号:");
scanf("%s", pc->data[i].phone);
printf("家庭住址:");
scanf("%s", pc->data[i].location);
printf("修改成功\n");
}
int findcontact(contacts* pc)
{
assert(pc != NULL);
printf("输入此人姓名\n");
char name[20] = { 0 };
scanf("%s", name);
int i = find_out(name, pc);
if (i == -1)
{
printf("无此人信息\n");
return 1;
}
printf("%-20s\t%-20s\t%-20s\t%-20s\t%-20\t\n", "姓名", "年龄", "性别", "电话号", "家庭住址");
printf("%-20s\t%-20d\t%-20s\t%-20s\t%-20\t\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].phone,
pc->data[i].location);
}
int estimate(const void* p1, const void* p2)
{
return strcmp(((person*)p1)->name, ((person*)p2)->name);
}
void sortcontact(contacts* pc)
{
assert(pc != NULL);
qsort(pc->data, pc->count, sizeof(person), estimate);
printf("排序成功\n");
}
void destroycontact(contacts* pc)
{
assert(pc != NULL);
free(pc->data);
pc->data = NULL;
}
void stockpilecontact(contacts* pc)
{
assert(pc != NULL);
FILE* p1 = fopen("contacts.txt", "wb");//打开文件,以二进制方式写
if (p1 == NULL)
{
perror("SaveContact");
return;
}
int i = 0;
for (i = 0; i < pc->count; i++)//输入通讯录中的成员信息
{
fwrite(pc->data + i, sizeof(person), 1, p1);
}
fclose(p1);//关闭文件
p1 = NULL;
}
test.c
#include "contacts.h"
enum list
{
EXIT,
ADD,
DEL,
MODIFY,
FIND,
SHOW,
SORT
};
void catalogue()
{
printf("*********************************\n");
printf("*** 1.add 2.del ***\n");
printf("*** 3.modify 4.find ***\n");
printf("*** 5.show 6.sort ***\n");
printf("*** 0.exit ***\n");
printf("*********************************\n");
}
int main()
{
int n = 0;
contacts con;//通讯录
initialize(&con);//初始换通讯录
do
{
catalogue();//通讯录菜单
printf("请选择>");
scanf("%d", &n);//选择要做什么
switch (n)
{
case EXIT://退出程序
stockpilecontact(&con);
destroycontact(&con);
printf("退出通讯录\n");
break;
case ADD://添加联系人
addcontact(&con);
break;
case DEL://删除联系人
delcontact(&con);
break;
case FIND://查找联系人
findcontact(&con);
break;
case MODIFY://修改联系人信息
modifycontact(&con);
break;
case SHOW://展示联系人
showcontact(&con);
break;
case SORT://排序通讯录
sortcontact(&con);
break;
default:
printf("输入错误请重新输入\n");
}
} while (n);
return 0;
}