建站公司网站模板论坛,合肥网站建设案例,网络营销外包的优点,上海最大的企业目录
动态内存管理
通讯录声明
静态版本 动态版本 初始化通讯录
静态版本
动态版本
Add增加通讯录
静态版本
动态版本 Checkcapacity增容
DestroyContact释放动态空间
文件操作
SaveContact保存信息到文件中
初始化通讯录
旧版本
文件版本
LoadContact加载…目录
动态内存管理
通讯录声明
静态版本 动态版本 初始化通讯录
静态版本
动态版本
Add增加通讯录
静态版本
动态版本 Checkcapacity增容
DestroyContact释放动态空间
文件操作
SaveContact保存信息到文件中
初始化通讯录
旧版本
文件版本
LoadContact加载文件信息到通讯录
test.c
contact.h
contact.c 我们前面已经学习完 动态内存管理 和 C语言操作文件相信你对内存的管理和操作有了更加深入的了解。那我们今天接着来优化一下前面我们写过的通讯录。
特别提醒函数如果放在后面在使用函数前面必须声明
动态内存管理
使用动态内存相关的知识优化通讯录。主要是从增加内存的方面去优化。我们设置为以下规则注意这种设置仅仅为了方便讲解和测试仅此而已。后期大家可以设置为自己想要的规则。
通讯录刚刚开始可以存放3个人的信息。通讯录放满可以增加容量每次增加2个人的信息的空间。
通讯录声明
静态版本
//通讯录---存放结构体的数组--每个结构体就是一个人的信息
typedef struct Contact
{PeoInfo data[MAX];//存放数据int sz;//记录当前通讯录中存放的人的信息个数
}Contact; 动态版本
//动态版本
typedef struct Contact
{PeoInfo* data;//存放数据可修改数组内存的空间了
//PeoInfo结构体类型的指针int sz;//记录当前通讯录中存放的人的信息个数int capacity;//记录的是通讯录的当前容量
}Contact;
当通讯录中存放的人的信息个数 sz 通讯录当前容量 capacity就可以考虑增加容量问题。目前的data是没有空间的需要在初始化的时候在堆区开辟3个人的信息空间。PeoInfo* data 存放数据可修改数组内存的空间了PeoInfo结构体类型的指针PeoInfo* data 指针维护开辟的空间 初始化通讯录
静态版本
void InitContact(Contact* pc)
{assert(pc);pc-sz 0;memset(pc-data, 0, sizeof(pc-data));
}
动态版本
#define DEFAULT_SZ 3 //后期容易修改
void InitContact(Contact* pc)
{assert(pc);pc-sz 0;pc-capacity DEFAULT_SZ;pc-data calloc(pc-capacity ,sizeof(PeoInfo));if (pc-data NULL){perror(InitContact-calloc);return;}
} PeoInfo* data 指针维护开辟的空间
Add增加通讯录
静态版本
void AddContact(Contact* pc)
{assert(pc);printf(请输入名字\n);scanf(%s, pc-data[pc-sz].name);//name是数组名不用printf(请输入年龄\n);scanf(%d, (pc-data[pc-sz].age));//printf(请输入性别\n);scanf(%s, pc-data[pc-sz].sex);printf(请输入电话\n);scanf(%s, pc-data[pc-sz].tele);printf(请输入地址\n);scanf(%s, pc-data[pc-sz].addr);//pc-sz;printf(增加成功\n);
}
动态版本
#define DEFAULT_INC 2//后期容易修改
//动态版本
void AddContact(Contact* pc)
{assert(pc);//满了增加容量if (pc-sz pc-capacity){PeoInfo* ptr (PeoInfo*)realloc(pc-data, (pc-capacity DEFAULT_INC) * sizeof(PeoInfo));if (ptr ! NULL){pc-data ptr;}else{perror(AddContact-realloc);return;}}//不需要增容填写人信息printf(请输入名字\n);scanf(%s, pc-data[pc-sz].name);//name是数组名不用printf(请输入年龄\n);scanf(%d, (pc-data[pc-sz].age));//printf(请输入性别\n);scanf(%s, pc-data[pc-sz].sex);printf(请输入电话\n);scanf(%s, pc-data[pc-sz].tele);printf(请输入地址\n);scanf(%s, pc-data[pc-sz].addr);//pc-sz;printf(增加成功\n);
}
当通讯录中存放的人的信息个数 sz 通讯录当前容量 capacity就可以考虑增加容量问题。
当然也可以封装成函数Checkcapacity Checkcapacity增容
Checkcapacity(pc);
void Checkcapacity(Contact* pc)
{if (pc-sz pc-capacity){PeoInfo* ptr (PeoInfo*)realloc(pc-data, (pc-capacity DEFAULT_INC) * sizeof(PeoInfo));if (ptr ! NULL){pc-data ptr;}else{perror(AddContact-realloc);return;}}
} 当然我们使用了动态内存的空间我们必须手动释放和销毁我们封装一个函数去销毁。
DestroyContact释放动态空间
void DestroyContact(Contact* pc);
case EXIT:DestroyContact(con);printf(退出通讯录\n);break;
void DestroyContact(Contact* pc)
{free(pc-data);pc-data NULL;pc-sz 0;pc-capacity 0;
}
文件操作
程序退出之后输入的信息都丢了。所以在通讯录之前最好把我们输入的信息全部保存到文件里。
SaveContact保存信息到文件中
//保存信息到文件
void SaveContact(Contact* pc);
case EXIT://保存通讯录中的数据到文件中SaveContact(con);DestroyContact(con);printf(退出通讯录\n);break;
void SaveContact(Contact* pc)
{//打开文件FILE* pf fopen(contact.txt, wb);//wb以二进制的方式写数据到文件if (pf NULL){perror(SaveContact);return;}//写信息到文件int i 0;//一个数据一个数据写for (i 0; i pc-sz; i){fwrite((pc-data[i]), sizeof(PeoInfo), 1, pf);fwrite(pc-datai, sizeof(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf NULL;
}
字符以ASCII码和二进制的存储的方式相同整型以ASCII码和二进制的存储的方式不同
初始化通讯录
但是当程序再次跑起来的时候还是看不到信息所以我们需要在执行通讯录等一系列的功能之前我们就要从文件里读取到数据信息。我们去修改初始化部分
旧版本
void InitContact(Contact* pc)
{assert(pc);pc-sz 0;pc-capacity DEFAULT_SZ;pc-data calloc(pc-capacity * sizeof(PeoInfo));if (pc-data NULL){perror(InitContact-calloc);return;}
}
文件版本
//文件版本
void InitContact(Contact* pc)
{assert(pc);pc-sz 0;pc-capacity DEFAULT_SZ;pc-data calloc(pc-capacity * sizeof(PeoInfo));if (pc-data NULL){perror(InitContact-calloc);return;}LoadContact(pc);
}
LoadContact加载文件信息到通讯录
//加载文件信息到通讯录
void LoadContact(Contact* pc);
void Checkcapacity(Contact* pc);//声明void LoadContact(Contact* pc)
{//打开文件FILE* pf fopen(contact.txt, rb);//以二进制的形式读if (pf NULL){perror(LoadContact);return;}//读文件PeoInfo tmp { 0 };//创建临时变量结构体PeoInfo类型while (fread(tmp, sizeof(PeoInfo), 1, pf))//读到就返回1没有读到就返回0一个一个读直到没有读到为0跳出循环{Checkcapacity(pc);//若文件中有5个人但是这里只有3个人的容量首先判断需不需要增容pc-data[pc-sz] tmp;pc-sz;}//关闭文件fclose(pf);pf NULL;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#includecontact.h
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 ***********\n);printf(************************************\n);
}
enum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT,//6
};
int main()
{int input 0;//创建通讯录Contact con;//初始化通讯录InitContact(con);do{menu();printf(请输入你的选择\n);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://保存通讯录中的数据到文件中SaveContact(con);DestroyContact(con);printf(退出通讯录\n);break;default:printf(选择错误请重新选择\n);break;}} while (input);return 0;
}
contact.h
#pragma once
#includestdio.h
#includestring.h
#includeassert.h
#define NAME_MAX 20
#define SEX_MAX 20
#define TELE_MAX 20
#define ADDR_MAX 30
#define MAX 100
#define DEFAULT_SZ 3
#define DEFAULT_INC 2
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;//静态版本
//typedef struct Contact
//{
// PeoInfo data[MAX];//存放数据
// int sz;//记录当前通讯录中存放的人的信息个数
//}Contact;//动态版本
typedef struct Contact
{PeoInfo* data;//存放数据int sz;//记录当前通讯录中存放的人的信息个数int capacity;//记录的是通讯录的当前容量
}Contact;//初始化通讯录
void InitContact(Contact* pc);
//增加个人信息
void AddContact(Contact* pc);
//展示个人信息
void ShowContact(Contact* pc);
//删除个人信息
void DelContact(Contact *pc);
//查找个人信息
void SearchContact(Contact* pc);
//修改个人信息
void ModifyContact(Contact* pc);
//排序
//void SortContact(Contact* pc);
//释放空间
void DestroyContact(Contact* pc);
//保存信息到文件
void SaveContact(Contact* pc);
//加载文件信息到通讯录
void LoadContact(Contact* pc);
contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#includecontact.h//初始化静态版本
//void InitContact(Contact* pc)
//{
// assert(pc);
// pc-sz 0;
// memset(pc-data, 0, sizeof(pc-data));
//}//动态版本
//void InitContact(Contact* pc)
//{
// assert(pc);
// pc-sz 0;
// pc-capacity DEFAULT_SZ;
// pc-data calloc(pc-capacity * sizeof(PeoInfo));
// if (pc-data NULL)
// {
// perror(InitContact-calloc);
// return;
// }
//}//文件版本
void Checkcapacity(Contact* pc);//声明
void LoadContact(Contact* pc)
{//打开文件FILE* pf fopen(contact.txt, rb);//以二进制的形式读if (pf NULL){perror(LoadContact);return;}//读文件PeoInfo tmp { 0 };while (fread(tmp, sizeof(PeoInfo), 1, pf)){Checkcapacity(pc);pc-data[pc-sz] tmp;pc-sz;}//关闭文件fclose(pf);pf NULL;
}
void InitContact(Contact* pc)
{assert(pc);pc-sz 0;pc-capacity DEFAULT_SZ;pc-data calloc(pc-capacity * sizeof(PeoInfo));if (pc-data NULL){perror(InitContact-calloc);return;}LoadContact(pc);
}//增加静态版本
//void AddContact(Contact* pc)
//{
// assert(pc);
// printf(请输入名字\n);
// scanf(%s, pc-data[pc-sz].name);//name是数组名不用
// printf(请输入年龄\n);
// scanf(%d, (pc-data[pc-sz].age));//
// printf(请输入性别\n);
// scanf(%s, pc-data[pc-sz].sex);
// printf(请输入电话\n);
// scanf(%s, pc-data[pc-sz].tele);
// printf(请输入地址\n);
// scanf(%s, pc-data[pc-sz].addr);
// //
// pc-sz;
// printf(增加成功\n);
//}//动态版本
void Checkcapacity(Contact* pc)
{if (pc-sz pc-capacity){PeoInfo* ptr (PeoInfo*)realloc(pc-data, (pc-capacity 2) * sizeof(PeoInfo));if (ptr ! NULL){pc-data ptr;}else{perror(AddContact-realloc);return;}}
}void AddContact(Contact* pc)
{assert(pc);//满了增加容量Checkcapacity(pc);//不需要增容填写人信息printf(请输入名字\n);scanf(%s, pc-data[pc-sz].name);//name是数组名不用printf(请输入年龄\n);scanf(%d, (pc-data[pc-sz].age));//printf(请输入性别\n);scanf(%s, pc-data[pc-sz].sex);printf(请输入电话\n);scanf(%s, pc-data[pc-sz].tele);printf(请输入地址\n);scanf(%s, pc-data[pc-sz].addr);//pc-sz;printf(增加成功\n);
}//展示
void ShowContact(const Contact* pc)
{assert(pc);if (pc-sz 0){printf(通讯录为空无需打印\n);return 0;}int i 0;//名字 年龄 性别 电话 地址//-左对齐//20是需要20字符的位置来放名字 printf(%-20s%-5s%-5s%-12s%-30s\n, 姓名, 年龄, 性别, 电话, 地址);for (i 0; i pc-sz; i){printf(%-20s%-5d%-5s%-12s%-30s\n,pc-data[i].name, pc-data[i].age, pc-data[i].sex, pc-data[i].tele, pc-data[i].addr);}
}//删除查找修改都需要使用
int FindByName(const Contact* pc, char name[])
{assert(pc);int i 0;for (i 0; i pc-sz; i){if (strcmp(pc-data[i].name, name) 0){return i;}}return -1;
}//删除
void DelContact(Contact* pc)
{char name[NAME_MAX];//assert(pc);if (pc-sz 0){printf(通讯录为空无法删除\n);return;}printf(输入要删除的名字);scanf(%s, name);int ret FindByName(pc, name);if (ret -1){printf(要删除的人不存在\n);return;}//存在返回这个人的所在data的下标放入retint i 0;for (i ret; i pc - sz - 1; i){pc-data[i] pc-data[i 1];}pc-sz--;printf(删除成功\n);
}//查找
void SearchContact(Contact* pc)
{char name[NAME_MAX];assert(pc);if (pc-sz 0){printf(通讯录为空无法查找\n);return;}//查找printf(输入要查找的名字);scanf(%s, name);int ret FindByName(pc, name);if (ret -1){printf(要查找的人不存在\n);return;}//返回下标显示这个的信息printf(%-20s%-5s%-5s%-12s%-30s\n, 姓名, 年龄, 性别, 电话, 地址);printf(%-20s%-5d%-5s%-12s%-30s\n,pc-data[ret].name, pc-data[ret].age, pc-data[ret].sex, pc-data[ret].tele, pc-data[ret].addr);
}//修改
void ModifyContact(Contact* pc)
{char name[NAME_MAX];assert(pc);if (pc-sz 0){printf(通讯录为空无法修改\n);return;}//查找printf(输入要修改的名字);scanf(%s, name);int ret FindByName(pc, name);if (ret -1){printf(要修改的人不存在\n);return;}//修改assert(pc);printf(请输入名字\n);scanf(%s, pc-data[ret].name);//name是数组名不用printf(请输入年龄\n);scanf(%d, (pc-data[ret].age));//printf(请输入性别\n);scanf(%s, pc-data[ret].sex);printf(请输入电话\n);scanf(%s, pc-data[ret].tele);printf(请输入地址\n);scanf(%s, pc-data[ret].addr);printf(修改成功\n);
}//释放动态空间
void DestroyContact(Contact* pc)
{free(pc-data);pc-data NULL;pc-sz 0;pc-capacity 0;
}//写函数到文件中
void SaveContact(Contact* pc)
{//打开文件FILE* pf fopen(contact.txt, wb);//wb以二进制的方式写数据到文件if (pf NULL){perror(SaveContact);return;}//写信息到文件int i 0;//一个数据一个数据写for (i 0; i pc-sz; i){fwrite((pc-data[i]), sizeof(PeoInfo), 1, pf);fwrite(pc-datai, sizeof(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf NULL;
}
✔✔✔✔✔最后感谢大家的阅读若有错误和不足欢迎指正
接下来的博文会更新一些练习题到实践中去加深对知识的理解。C语言的基本学习就快结束了还是要多加练习。
代码----------→【gitee:唐棣棣 (TSQXG) - Gitee.com】
联系----------→ 【邮箱2784139418qq.com】