摘要:之前的通讯录在程序退出后内部的数据就会消失,再次打开程序后只能重新输入数据,为此我们增加了一个保存功能来保存信息。
前言:
- 由于之前实现的通讯录在存储方面只能支持静态的1000人的存储量,但是如果联系人较少,则会造成较大的内存浪费。
- 而当联系人一旦超过1000时,就不能再继续存储信息了。因此我将通讯录改成动态扩容版本,就不会减少内存的浪费,同时也可以无限增加通讯录的内部信息。
- 之前的通讯录在程序退出后内部的数据就会消失,再次打开程序后只能重新输入数据,为此我们增加了一个保存功能来保存信息。
此版本将实现的功能:
- 新增联系人
- 查找联系人
- 删除联系人
- 修改联系人
- 查看所有联系人
清空所有联系人(新增)
- 按姓名排序联系人
- 保存联系人信息(新增)
注:之前版本写过的代码就不多做赘述了
如果有代码上的疑惑可以移步去 手把手教你用C语言实现通讯录(简易版 查看
本次仅对新增的内容进行解释和说明
目录
新增:
清空所有联系人选项(7)
保存联系人信息选项(8)
代码如下:
void menu(){ printf("*********************************/n"); printf("** 1. 添加联系人 **/n"); printf("** 2. 删除联系人 **/n"); printf("** 3. 查找联系人 **/n"); printf("** 4. 修改联系人 **/n"); printf("** 5. 显示所有联系人 **/n"); printf("** 6. 按姓名排序联系人 **/n"); printf("** 7. 清空所有联系人 **/n"); printf("** 8. 保存联系人信息 **/n"); printf("** 0. exit **/n"); printf("*********************************/n");}
执行结果:
新增:
case 分支中 清空通讯录选项 & 清空实现函数
case 分支中 保存通讯录选项 & 保存实现函数
case 分支中 退出时自动保存实现函数
代码如下:
int main(){ int input = 0; //创建通讯录 struct Contact con;//通讯录 //初始化通讯录 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: MoidfyContact(&con); break; case SHOW: ShowContact(&con); break; case DESTROY: DestroyContact(&con); break; case SORT: SortContact(&con); break; case SAVE: SaveContact(&con); break; case EXIT: SaveContact(&con); printf("退出通讯录/n"); break; default: printf("选择错误/n"); break; } } while (input); return 0;}
新增:
enum枚举 选择中新增 DESTROY & SAVE 的选项,通过枚举的方法对应 main 函数中的 case 分支。
代码如下:
//枚举:选择功能enum Choose{ EXIT, //0 ADD, //1 DEL, //2 SEARCH, //3 MODIFY, //4 SHOW, //5 SORT, //6 DESTROY, //7 SAVE //8};
新增:
typedef 定义 Contact 函数,使其能直接使用不需要 struct 修饰
整型 capacity 变量来表示当前通讯录的最大容量
代码如下:
//结构体:通讯录类型typedef struct Contact{ struct PeoInform *data;//存放信息 int size;//记录当前结构体内已经有的元素个数 int capacity;//当前通讯录的最大容量}Contact;
新增:
为了实现动态,我们将初始空间 Org_SPACE (orignial space 初始空间) 设置为5个
修改:
删去了最大空间为1000个的静态内存空间
代码如下:
//初始空间为5个#define ORG_SPACE 5#define MAX_NAME 20#define MAX_SEX 5#define MAX_PHONE 12#define MAX_ADDRESS 30
新增:
通过 malloc 函数动态开辟一块地址,初始容量 ORG_SPACE 可以存放 5 个联系人信息,同时初始化最大容量 ORG_SPACE
下方的 LoadContact 函数是为了读取信息来存放到通讯录中,来实现文件保存功能
代码如下:
//初始化通讯录的函数void InitContact(struct Contact *ps){ ps->data = (struct PeoInform*)malloc(ORG_SPACE*sizeof(struct PeoInform)); if(ps->data == NULL) { return; } ps->size = 0; ps->capacity = ORG_SPACE; //把文件中已经存放的通讯录中的信息加载到通讯录中 LoadContact(ps);}
那么既然上方的初始化通讯录中已经出现了这个读取函数,那么我们就来设计一下:
这里的 FR 来临时读取 contact.txt 保存文件中的信息,一旦FR内部为空,就代表文件内没有保存任何信息。
而后面是读取文件中的信息,存放到通讯录中的临时变量 tmp 中去,此时我们要考虑读取到通讯录的数据是否会溢出,所以我们要进行判断,一旦超过了5个的初始空间,就进行扩充。
最后关闭文件时,将 FR 内部的数据清空
//读取通讯录信息void LoadContact(Contact *ps){ PeoInform tmp = {0};//临时变量tmp FILE *FR = fopen("contact.txt", "rb"); if(FR == NULL) { printf("LoadContact::%s/n", strerror(errno)); return; } //读取文件,存放到通讯录中 while(fread(&tmp, sizeof(PeoInform), 1, FR)) { ExpandCapacity(ps); ps->data[ps->size] = tmp; ps->size++; } fclose(FR); FR = NULL;}
我们此时来设计一下通讯录扩充函数,同时使其能够实现检测当前通讯录的容量:
1. 如果满了,就增加空间
2. 如果不满,啥事都不干
3. 一旦存储达到5个以后就再使用realloc函数扩充5个动态空间
代码如下:
void ExpandCapacity(struct Contact *ps){ if(ps->size == ps->capacity) { struct PeoInform *ptr = realloc(ps->data, (ps->capacity+2)*sizeof(PeoInform)); if(ptr != NULL) { ps->data = ptr; ps->capacity += 5; //自动开辟五个动态空间 printf("扩充成功/n"); } else { printf("扩充失败/n"); } }}
新增:
errno 函数 需要引用的
头文件 malloc 函数 需要引用的
头文件
代码如下:
#include #include #include #include #include
代码如下:
//销毁通讯录中的所有信息void DestroyContact(Contact* ps){ printf("您确定要清空所有联系人吗? y/n/n"); char choice[2]; scanf("%s", &choice); if (strcmp(choice, "y") == 0) { ps->size = 0; printf("已清空所有联系人!/n"); } if (strcmp(choice, "n") == 0) { printf("指令已取消/n"); } //同时释放之前所开辟的动态空间 free(ps->data); ps->data = NULL;}
执行效果:
代码如下:
//保存联系人到文件void SaveContact(Contact* ps){ FILE* fp = fopen("contact.txt", "wb"); if (fp == NULL) { printf("SaveContact::%s/n", strerror(errno)); return; } //写通讯录中数据到为文件中 int i = 0; for (i = 0; i < ps->size; i++) { fwrite(&(ps->data[i]), sizeof(PeoInform), 1, fp); printf("已保存联系人!/n"); }}
执行效果:
关闭程序后再次打开:
#include #include #include #include #include //初始空间为5个#define ORG_SPACE 5#define MAX_NAME 20#define MAX_SEX 5#define MAX_PHONE 12#define MAX_ADDRESS 30//枚举:选择功能enum Choose{ EXIT, //0 ADD, //1 DEL, //2 SEARCH, //3 MODIFY, //4 SHOW, //5 SORT, //6 DESTROY, //7 SAVE //8}; //结构体:通讯录中每个成员的信息typedef struct PeoInform//将结构体指针类型命名为PeoInform{ char name[MAX_NAME]; int age; char sex[MAX_SEX]; char phone[MAX_PHONE]; char address[MAX_ADDRESS];}PeoInform; //结构体:通讯录类型typedef struct Contact{ struct PeoInform *data;//存放信息 int size;//记录当前结构体内已经有的元素个数 int capacity;//当前通讯录的最大容量}Contact;//通讯录扩充void ExpandCapacity(struct Contact *ps){ if(ps->size == ps->capacity) { struct PeoInform *ptr = realloc(ps->data, (ps->capacity+2)*sizeof(PeoInform)); if(ptr != NULL) { ps->data = ptr; ps->capacity += 5; //自动开辟五个动态空间 printf("扩充成功/n"); } else { printf("扩充失败/n"); } }}//读取通讯录信息void LoadContact(Contact *ps){ PeoInform tmp = {0};//临时变量tmp FILE *FR = fopen("contact.txt", "rb"); if(FR == NULL) { printf("LoadContact::%s/n", strerror(errno)); return; } //读取文件,存放到通讯录中 while(fread(&tmp, sizeof(PeoInform), 1, FR)) { ExpandCapacity(ps); ps->data[ps->size] = tmp; ps->size++; } fclose(FR); FR = NULL;}//初始化通讯录的函数void InitContact(struct Contact *ps){ ps->data = (struct PeoInform*)malloc(ORG_SPACE*sizeof(struct PeoInform)); if(ps->data == NULL) { return; } ps->size = 0; ps->capacity = ORG_SPACE; //把文件中已经存放的通讯录中的信息加载到通讯录中 LoadContact(ps);}//按姓名查找联系人是否存在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, name)) { return i; } } return -1;//找不到的情况}//增加一个信息到通讯录void AddContact(struct Contact *ps){ ExpandCapacity(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].phone); printf("请输入家庭地址:>"); scanf("%s", ps->data[ps->size].address); ps->size++; printf("添加成功/n");} //删除指定的联系人void DelContact(struct Contact *ps){ int pos = 0; char name[MAX_NAME]; printf("请输入要删除人的名字:>"); scanf("%s", name); //1.查找要删除的人在什么位置 //找到了返回名字所在元素的下标 //找不到返回 -1 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 = 0; //查找联系人的位置 pos = FindByName(ps, name); //2.删除 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[pos].name, ps->data[pos].age, ps->data[pos].sex, ps->data[pos].phone, ps->data[pos].address); }} //修改指定联系人的信息void MoidfyContact(struct Contact *ps){ char name[MAX_NAME]; printf("请输入要修改联系人的名字:>"); scanf("%s", name); int pos = 0; 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].phone); printf("请输入家庭地址:>"); scanf("%s", ps->data[pos].address); 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].phone, ps->data[i].address); } }}//销毁通讯录中的所有信息void DestroyContact(Contact* ps){ printf("您确定要清空所有联系人吗? y/n/n"); char choice[2]; scanf("%s", &choice); if (strcmp(choice, "y") == 0) { ps->size = 0; printf("已清空所有联系人!/n"); } if (strcmp(choice, "n") == 0) { printf("指令已取消/n"); } //同时释放之前所开辟的动态空间 free(ps->data); ps->data = NULL;}//按姓名排序通讯录内容void SortContact(struct Contact *ps){ if (ps->size <= 0){ printf("通讯录中没有联系人,请添加!/n"); } int i = 0; int j = 0; for (i = 0; i< ps->size - 1; i++) { for (j = 0; j< ps->size - i - 1; j++) { if (strcmp( ps->data[j].name, ( ps->data[j + 1]).name) > 0) { PeoInform tmp; tmp = ps->data[j]; ps->data[j] = ps->data[j + 1]; ps->data[j + 1] = tmp; } } printf("排序成功!/n"); }} //保存联系人到文件void SaveContact(Contact* ps){ FILE* fp = fopen("contact.txt", "wb"); if (fp == NULL) { printf("SaveContact::%s/n", strerror(errno)); return; } //写通讯录中数据到为文件中 int i = 0; for (i = 0; i < ps->size; i++) { fwrite(&(ps->data[i]), sizeof(PeoInform), 1, fp); printf("已保存联系人!/n"); }} void menu(){ printf("*********************************/n"); printf("** 1. 添加联系人 **/n"); printf("** 2. 删除联系人 **/n"); printf("** 3. 查找联系人 **/n"); printf("** 4. 修改联系人 **/n"); printf("** 5. 显示所有联系人 **/n"); printf("** 6. 按姓名排序联系人 **/n"); printf("** 7. 清空所有联系人 **/n"); printf("** 8. 保存联系人信息 **/n"); printf("** 0. exit **/n"); printf("*********************************/n");} int main(){ int input = 0; //创建通讯录 struct Contact con;//con就是通讯录,里面包含:1000个元素的数和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: MoidfyContact(&con); break; case SHOW: ShowContact(&con); break; case SORT: SortContact(&con); break; case DESTROY: DestroyContact(&con); break; case SAVE: SaveContact(&con); break; case EXIT: SaveContact(&con); printf("退出通讯录/n"); break; default: printf("选择错误/n"); break; } } while (input); return 0;}
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/119672.html
摘要:本篇文章将用语言代码实现一个通讯录管理系统,本片文章博主将会运用到架构提,枚举,动态内存开辟和文件操作等。这里存放数据的结构是线性表。这个指针就可以通过动态开辟内存来调整存放信息的大小。扩容成功这样就实现了检查通讯录是否需要扩容的函数。 ...
摘要:导航前言功能函数结构设定菜单交互主函数通讯录初始化新增联系人查找联系人删除联系人修改联系人查看所有联系人清空所有联系人以名字排序所有联系人结尾语前言本文将实现一个简易的电话簿管理。信息包括名字,性别,电话号码,年龄,住址。 ...
摘要:外部设备会自己处理字节序的问题。本地序和网络序从前面对于字节序的介绍可以知道采用小端序,而等采用大端序。协议很好的解决了这个问题,协议规定使用大端字节序作为网络字节序。提供了一组接口用于整型数据在本地序和网络序之间的转换。 ...
摘要:本文收录于技术专家修炼文中配套资料合集路线导图高清源文件点击跳转到文末点击底部卡片回复资料领取哈喽,大家好,我是一条最近粉丝问我有没有自学路线,有了方向才能按图索骥,事半功倍。 ...
阅读 1813·2021-10-09 09:44
阅读 2689·2021-09-22 15:38
阅读 2450·2021-09-09 09:33
阅读 685·2021-09-07 09:58
阅读 1783·2021-09-02 15:41
阅读 2484·2019-08-30 15:55
阅读 1795·2019-08-30 15:55
阅读 532·2019-08-30 15:44