admin管理员组文章数量:1487745
通讯录进阶,支持动态内存与数据存储的通讯录
如果你没有看过通讯录初级,请先移步到那。 在前面我们写了一个静态的通讯录,通讯录的大小都是固定的,同时每次启动通讯录都需要重新输入数据。这用起来肯定是不人性化的。 进阶通讯录与原版的不同点就在于,通讯录的大小是会随着数据的添加而增大的,也就是动态内存管理,以及会对通讯录的数据进行存储,一旦通讯录被关闭数据就会自动存放在相应的文件。同时在下一次打开通讯录时,会自动将文件中的数据导入通讯录中。
1.对结构体contact的修改
代码语言:javascript代码运行次数:0运行复制//静态
//typedef struct contact
//{
// buddies data[MAX];
// int size;
//}contact;
//动态
typedef struct contact
{
buddies* data;
int size;
int capacity;
}contact;
capacity的添加是为了可以清楚的知道目前我们为通讯录开放的多大的空间。
2.对通讯录初始化的修改
代码语言:javascript代码运行次数:0运行复制//静态
//void InitContact(contact* pc)
//{
// memset(pc->data, 0, sizeof(pc->data));
// pc->size = 0;
//}
//动态
void InitContact(contact* pc)
{
pc->data = (buddies*)malloc(sizeof(buddies) * 2);
pc->size = 0;
pc->capacity = 2;
}
动态内存开辟,这里我们的规定是初始给2个联系人的空间,你可以自行修改。然后将malloc开辟空间是地址给pc->data
3.对通讯录添加数据的修改
代码语言:javascript代码运行次数:0运行复制//静态
//void AddContact(contact* pc)
//{
// if (pc->size > MAX)
// {
// printf("通讯录已满\n");
// return;
// }
// printf("请输入姓名:>");
// scanf("%s", pc->data[pc->size].name);
// printf("请输入年龄:>");
// scanf("%d", &pc->data[pc->size].age);
// printf("请输入性别:>");
// scanf("%s", pc->data[pc->size].sex);
// printf("请输入电话:>");
// scanf("%s", pc->data[pc->size].tel);
// printf("请输入地址:>");
// scanf("%s", pc->data[pc->size].add);
// printf("联系人添加完成\n");
// //添加成功,size要加1
// pc->size += 1;
//}
int check_capacity(contact* pc)//检查当前容量是否需要进行扩容
{
if (pc->size == pc->capacity)//扩容了
{
buddies* tmp = (buddies*)realloc(pc->data, sizeof(buddies) * (pc->capacity + 2));//利用realloc进行扩容,每次添加2个空间的大小,最佳扩容方法应该是每次扩大1.5倍~2倍。因为频繁的扩容容易造成内存碎片增多
if (tmp == NULL)
{
//扩容失败
perror("realloc");
return 0;
}
pc->data = tmp;
pc->capacity += 2;
printf("扩容成功\n");
return 1;
}
else//还没满
{
return 1;
}
}
//动态
void AddContact(contact* pc)
{
if (check_capacity(pc) == 0)
{
return;
}
printf("请输入姓名:>");
scanf("%s", pc->data[pc->size].name);
printf("请输入年龄:>");
scanf("%d", &pc->data[pc->size].age);
printf("请输入性别:>");
scanf("%s", pc->data[pc->size].sex);
printf("请输入电话:>");
scanf("%s", pc->data[pc->size].tel);
printf("请输入地址:>");
scanf("%s", pc->data[pc->size].add);
printf("联系人添加完成\n");
//添加成功,size要加1
pc->size += 1;
}
因为原版通讯录的大小是固定的,只需要检查空间是否满了就可以了。而动态的通讯录在检查后还需要进行扩容,扩容失败返回-1,没满返回1,扩容成功也返回1。AddContact函数再根据返回值来做下一步大操作。
3.通讯录的销毁
因为通讯录的空间是动态内存开辟的,所以再最后是需要还给存储系统的,我们需要释放空间。 至于什么时候释放,当用户退出程序时释放空间。
代码语言:javascript代码运行次数:0运行复制void DestoryContact(contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->size = 0;
pc->capacity = 0;
}
int main()
{
int input = 0;
contact ct;
InitContact(&ct);
do
{
menu();//菜单
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&ct);
break;
case DELE:
DeleteContact(&ct);
break;
case SEAR:
SearchContact(&ct);
break;
case REVI:
ReviseContact(&ct);
break;
case SHOW:
ShowContact(&ct);
break;
case SORT:
SortContact(&ct);
break;
case EXIT:
DestoryContact(&ct);//空间释放
printf("退出程序\n");
break;
default:
printf("请重新输入\n");
break;
}
} while (input);
return 0;
}
用free函数来释放空间,然后让指针置为NULL。
4.利用文件保存通讯录数据
这里我们利用fwrite将数据转换为二进制存入文件。 然后这个函数需要放在退出程序的位置,当程序退出前就会自动保存数据。
代码语言:javascript代码运行次数:0运行复制void SaveContact(contact* pc)
{
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return;
}
//写入文件
fwrite(pc->data, sizeof(buddies), pc->size, pf);
fclose(pf);
pf = NULL;
}
5.将文件数据导入通讯录
利用fread将文件中的二进制数据导入通讯录,我们先创立一个临时的变量来存放数据,然后在把这个数据转移给通讯录。 该函数一个放在通讯录初始化完后。
代码语言:javascript代码运行次数:0运行复制void LoadContact(contact* pc)
{
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return;
}
//读取文件
buddies tmp = { 0 };
while (fread(&tmp, sizeof(buddies), 1, pf))
{
if (check_capacity(pc) == 0)
{
return;
}
pc->data[pc->size] = tmp;
pc->size += 1;
}
fclose(pf);
pf = NULL;
}
代码整合
代码语言:javascript代码运行次数:0运行复制//contact.h
#pragma once
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 10
#define MAX_TEL 16
#define MAX_ADD 30
enum select
{
EXIT,
ADD,
DELE,
SEAR,
REVI,
SHOW,
SORT
};
typedef struct buddies
{
char name[MAX_NAME];//姓名
int age;//年龄
char sex[MAX_SEX];//性别
char tel[MAX_TEL];//电话
char add[MAX_ADD];//地址
}buddies;
//静态
//typedef struct contact
//{
// buddies data[MAX];
// int size;
//}contact;
typedef struct contact
{
buddies* data;
int size;
int capacity;
}contact;
void InitContact(contact* pc);
void AddContact(contact* pc);
void DeleteContact(contact* pc);
void SearchContact(contact* pc);
void ReviseContact(contact* pc);
void ShowContact(contact* pc);
void SortContact(contact* pc);
void DestoryContact(contact* pc);
void SaveContact(contact* pc);
void LoadContact(contact* pc);
//contact.c
#include "contact.h"
//静态
//void InitContact(contact* pc)
//{
// memset(pc->data, 0, sizeof(pc->data));
// pc->size = 0;
//}
void InitContact(contact* pc)
{
pc->data = (buddies*)malloc(sizeof(buddies) * 2);
pc->size = 0;
pc->capacity = 2;
}
//void AddContact(contact* pc)
//{
// if (pc->size > MAX)
// {
// printf("通讯录已满\n");
// return;
// }
// printf("请输入姓名:>");
// scanf("%s", pc->data[pc->size].name);
// printf("请输入年龄:>");
// scanf("%d", &pc->data[pc->size].age);
// printf("请输入性别:>");
// scanf("%s", pc->data[pc->size].sex);
// printf("请输入电话:>");
// scanf("%s", pc->data[pc->size].tel);
// printf("请输入地址:>");
// scanf("%s", pc->data[pc->size].add);
// printf("联系人添加完成\n");
// //添加成功,size要加1
// pc->size += 1;
//}
int check_capacity(contact* pc)
{
if (pc->size == pc->capacity)//扩容了
{
buddies* tmp = (buddies*)realloc(pc->data, sizeof(buddies) * (pc->capacity + 2));
if (tmp == NULL)
{
//扩容失败
perror("realloc");
return 0;
}
pc->data = tmp;
pc->capacity += 2;
printf("扩容成功\n");
return 1;
}
else
{
return 1;
}
}
//动态
void AddContact(contact* pc)
{
if (check_capacity(pc) == 0)
{
return;
}
printf("请输入姓名:>");
scanf("%s", pc->data[pc->size].name);
printf("请输入年龄:>");
scanf("%d", &pc->data[pc->size].age);
printf("请输入性别:>");
scanf("%s", pc->data[pc->size].sex);
printf("请输入电话:>");
scanf("%s", pc->data[pc->size].tel);
printf("请输入地址:>");
scanf("%s", pc->data[pc->size].add);
printf("联系人添加完成\n");
//添加成功,size要加1
pc->size += 1;
}
//找到返回下标,没找到返回-1
int FindCon(contact* pc)
{
char tmp[MAX_NAME] = { 0 };
printf("请输入姓名:>");
scanf("%s", tmp);
for (int i = 0; i < pc->size; ++i)
{
if (strcmp(tmp, pc->data[i].name) == 0)
{
return i;
}
}
return -1;
}
void DeleteContact(contact* pc)
{
//通讯录为空,就退出
if (pc->size == 0)
{
printf("通讯录为空\n");
return;
}
//查找要删除的联系人
int pos = FindCon(pc);
if (pos == -1)
{
printf("找不到\n");
return;
}
//因为有一个数据要被删除,当它被删除时,其后面的数据需要挪动到前面一格。
for (int i = pos; i < pc->size - 1; ++i)
{
pc->data[i] = pc->data[i + 1];//后面数据往前覆盖
}
printf("删除联系人成功\n");
pc->size -= 1;
}
void SearchContact(contact* pc)
{
//通讯录为空,就退出
if (pc->size == 0)
{
printf("通讯录为空\n");
return;
}
//查找要打印的联系人
int pos = FindCon(pc);
if (pos == -1)
{
printf("找不到\n");
return;
}
printf("%-10s\t%-5s\t%-6s\t%-16s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
printf("%-10s\t%-5d\t%-6s\t%-16s\t%-20s\n", pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].tel,
pc->data[pos].add);
}
void ReviseContact(contact* pc)
{
//通讯录为空,就退出
if (pc->size == 0)
{
printf("通讯录为空\n");
return;
}
//查找要修改的联系人
int pos = FindCon(pc);
if (pos == -1)
{
printf("找不到\n");
return;
}
printf("请输入姓名:>");
scanf("%s", pc->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &pc->data[pos].age);
printf("请输入性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入电话:>");
scanf("%s", pc->data[pos].tel);
printf("请输入地址:>");
scanf("%s", pc->data[pos].add);
printf("联系人修改完成\n");
}
void ShowContact(contact* pc)
{
printf("%-10s\t%-5s\t%-6s\t%-16s\t%-20s\n", "姓名", "年龄", "性别", "电话", "地址");
for (int i = 0; i < pc->size; ++i)
{
printf("%-10s\t%-5d\t%-6s\t%-16s\t%-20s\n", pc->data[i].name,
pc->data[i].age,
pc->data[i].sex,
pc->data[i].tel,
pc->data[i].add);
}
}
int cmp_contact(void* p1, void* p2)
{
return strcmp(((buddies*)p1)->name, ((buddies*)p2)->name);
}
void SortContact(contact* pc)
{
qsort(pc->data, pc->size, sizeof(buddies), cmp_contact);
ShowContact(pc);
}
void DestoryContact(contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->size = 0;
pc->capacity = 0;
}
void SaveContact(contact* pc)
{
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("fopen");
return;
}
//写入文件
fwrite(pc->data, sizeof(buddies), pc->size, pf);
fclose(pf);
pf = NULL;
}
void LoadContact(contact* pc)
{
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("fopen");
return;
}
//读取文件
buddies tmp = { 0 };
while (fread(&tmp, sizeof(buddies), 1, pf))
{
if (check_capacity(pc) == 0)
{
return;
}
pc->data[pc->size] = tmp;
pc->size += 1;
}
fclose(pf);
pf = NULL;
}
//test.c
#include "contact.h"
void menu()
{
printf("******************************\n");
printf("****1.ADD 2.DELE ****\n");
printf("****3.SEAR 4.REVI ****\n");
printf("****5.SHOW 6.SORT ****\n");
printf("****0.EXIT ****\n");
printf("******************************\n");
}
int main()
{
int input = 0;
contact ct;
InitContact(&ct);
LoadContact(&ct);
do
{
menu();//菜单
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&ct);
break;
case DELE:
DeleteContact(&ct);
break;
case SEAR:
SearchContact(&ct);
break;
case REVI:
ReviseContact(&ct);
break;
case SHOW:
ShowContact(&ct);
break;
case SORT:
SortContact(&ct);
break;
case EXIT:
SaveContact(&ct);
DestoryContact(&ct);
printf("退出程序\n");
break;
default:
printf("请重新输入\n");
break;
}
} while (input);
return 0;
}
完
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2024-10-15,如有侵权请联系 cloudcommunity@tencent 删除数据存储datasize程序数据本文标签: 通讯录进阶,支持动态内存与数据存储的通讯录
版权声明:本文标题:通讯录进阶,支持动态内存与数据存储的通讯录 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/shuma/1754817344a3179969.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论