通讯录管理系统(C语言实现) 动态扩容,文件读写
2020-01-14 10:29
169 查看
通讯录可以用来存储个人的信息,每个人的信息包括:姓名、性别、年龄、电话、住址。而一个通讯录的管理系统,应该至少具备增、删、查、改等几项功能,并要对其进行拓展。
所以我们要实现的功能如下:
- 添加联系人信息
- 删除指定联系人信息
- 查找指定联系人信息
- 修改指定联系人信息
- 显示所有联系人信息
- 清空所有联系人
- 对联系人进行排序
- 通讯录应该是可扩容而非定长的
- 通讯录的数据应该存储在文件当中,以便多次使用
明确了目标,下面开始实现。
首先我们要选择合适的数据结构,对于这种线性的通讯录,顺序表无疑是最好的选择,在设置结构体的同时,还需要考虑到内存对齐的因素,将占用空间较小的成员尽量集中到一起。
同时为了通讯录的长度合适,我们运用了动态内存管理,当通讯录不够时自动扩容
typedef struct info { char name[NAME_MAX_SIZE]; char tel[TEL_MAX_SIZE]; char addr[ADDR_MAX_SIZE]; char gender[GENDER_MAX_SIZE]; int age; //先存放四个字符型再存放整形,利用内存对齐来达到空间利用最大化 }info; typedef struct { info* data; int capacity; int size; }contact, *pcontact; //采用顺序表的数据类型来存放数据
首先我们要对通讯录进行初始化
void InitContact(pcontact p) { p->data = (info*)malloc(CONTACT_SIZE * sizeof(info)); if (NULL == p->data) { printf("初始化失败!!!\n"); exit(0); } p->capacity = CONTACT_SIZE; p->size = 0; }
通讯录扩容
int CheckCapacity(pcontact p) { assert(p); if (p->size == p->capacity) { printf("通讯录已满,进行扩容\n"); ; info *temp = realloc(p->data, (p->capacity + CONTACT_SIZE) * sizeof(info)); if (NULL == temp) { printf("扩容失败\n"); return 0; } else { p->data = temp; p->capacity += CONTACT_SIZE; printf("扩容成功!!!\n"); } } return 1; }
添加联系人信息
void AddContact(pcontact p) { assert(p); //防止传入空指针,后面会一直使用 system("cls"); //清空之前的屏幕,防止画面太过杂乱 if (0 == CheckCapacity(p)) //判断通讯录是否已满,如果通讯录满且扩容失败将返回 { printf("通讯录已满,添加失败\n"); return; } printf("请输入姓名:\n"); scanf("%s", p->data[p->size].name); printf("请输入电话:\n"); scanf("%s", p->data[p->size].tel); printf("请输入性别:\n"); scanf("%s", p->data[p->size].gender); printf("请输入地址:\n"); scanf("%s", p->data[p->size].addr); printf("请输入年龄:\n"); scanf("%d", &(p->data[p->size].age)); printf("添加成功!!!\n"); p->size++; }
添加联系人信息
void DelContact(pcontact p) { assert(p); system("cls"); int pos, i; char name[NAME_MAX_SIZE]; if (!p->size) { printf("通讯录为空\n"); return; } printf("请输入要删除的人的姓名:\n"); scanf("%s", name); pos = GetPosition(name, p); if (-1 == pos) { printf("此人不存在\n"); } else { for (i = pos; pos < p->size - 1; i++) { p->data[i] = p->data[i + 1]; } p->size--; printf("删除成功!!!\n"); } }
按照名字获取通讯录的位置
这一个是为了给后面的查找和删除模块获取位置
int GetPosition(char* name, pcontact p) { assert(p); int pos; for (pos = 0; pos < p->size; pos++) { if (0 == strcmp(name, p->data[pos].name)) { return pos; } } return -1; }
查找联系人信息
void SearchContact(pcontact p) { assert(p); system("cls"); char name[NAME_MAX_SIZE]; int pos; printf("请输入要查找的人的姓名:\n"); scanf("%s", name); pos = GetPosition(name, p); if (-1 == pos) { printf("此人不存在:\n"); } else { printf("*******************************************\n"); printf("姓名:%s \n", p->data[pos].name); printf("性别:%s \n", p->data[pos].gender); printf("年龄:%d \n", p->data[pos].age); printf("地址:%s \n", p->data[pos].addr); printf("电话:%s \n", p->data[pos].tel); printf("*******************************************\n"); printf("查找成功!!!\n"); } }
修改联系人信息
void ModifyContact(pcontact p) { assert(p); system("cls"); char name[NAME_MAX_SIZE]; int pos; printf("请输入要修改的人的姓名:\n"); scanf("%s", name); pos = GetPosition(name, p); if (-1 == pos) { printf("此人不存在\n"); } else { printf("请输入修改后的姓名:\n"); scanf("%s", p->data[pos].name); printf("请输入修改后的电话:\n"); scanf("%s", p->data[pos].tel); printf("请输入修改后的性别:\n"); scanf("%s", p->data[pos].gender); printf("请输入修改后的年龄:\n"); scanf("%d", &(p->data[pos].age)); printf("请输入修改后的地址:\n"); scanf("%s", p->data[pos].addr); printf("修改成功!!!\n"); } }
显示所有联系人信息
void ShowContact(pcontact p) { assert(p); system("cls"); int i; if (!p->size) { printf("通讯录为空\n"); return; } for (i = 0; i < p->size; i++) { printf("*******************************************\n"); printf("********** 第 %d 位联系人 **********\n", i + 1); printf("姓名:%s \n", p->data[i].name); printf("性别:%s \n", p->data[i].gender); printf("年龄:%d \n", p->data[i].age); printf("地址:%s \n", p->data[i].addr); printf("电话:%s \n", p->data[i].tel); printf("*******************************************\n"); } }
清空通讯录
void EmptyContact(pcontact p) { assert(p); system("cls"); if (!p->size) { printf("通讯录为空\n"); return; } else { free(p->data); p->data = NULL; p->size = 0; p->capacity = 0; printf("通讯录清空成功!!!\n"); } }
为了通讯录方便我们查看,我们还需要排序,因为数据量过少以及排序不是这里的主体,所以采用最简单的冒泡排序
void SortContact(pcontact p) { assert(p); system("cls"); int i, j, flag = 1; info temp = { 0 }; for (i = p->size; i > 0 && flag; i--) { flag = 0; for (j = 1; j < p->size; j++) { if (strcmp(p->data[j].name, p->data[j - 1].name) < 0) { temp = p->data[j]; p->data[j] = p->data[j - 1]; p->data[j - 1] = temp; flag = 1; } } } printf("排序成功!!!\n"); }
同时,一个通讯录不可能每次使用都要重新输入数据,并且数据在关闭的时候会清空,所以我们要将数据的内容进行保存,而保存的方式我选择用二进制的形式保存,因为二进制的存储方式比ascii的存储方式操作更加简单和安全。唯一的缺点就是不方便查看。
保存数据
void SaveContact(pcontact p) { assert(p); system("cls"); FILE* pf = fopen("contact.dat", "wb"); int i; if (NULL == pf) { printf("文件打开失败\n"); return; } for (i = 0; i < p->size; i++) { fwrite(&(p->data[i]), sizeof(info), 1, pf); } printf("通讯录保存成功\n"); fclose(pf); pf = NULL; }
读取数据
void LoadContact(pcontact p) { assert(p); system("cls"); FILE* pf = fopen("contact.dat", "rb"); if (NULL == pf) { printf("文件打开失败\n"); return; } while (fread(&(p->data[p->size]), sizeof(info), 1, pf)) { if (CheckCapacity(p)) { p->size++; } } printf("通讯录读取成功\n"); fclose(pf); pf = NULL; }
同时,在结束时还要进行内存的释放,防止内存溢出
void EndContact(pcontact p) { free(p->data); p->data = NULL; p->size = 0; p->capacity = 0; exit(0); }
在主函数方面,为了简化代码和去掉重复代码,我选择用函数指针数组来实现菜单
void Test() { int input; contact book; void (*p[10])(pcontact p) = { EndContact, AddContact, DelContact, ModifyContact, SearchContact, SortContact, ShowContact, EmptyContact, SaveContact, LoadContact, }; //利用函数指针数组简化不必要的代码 InitContact(&book); //初始化 do { Menu(); printf("请输入要进行的操作:"); scanf("%d", &input); if ((input <= 9 && input >= 0)) { (*p[input])(&book); } else { printf("输入错误:\n"); } } while (input); }
就这样,一个简单的通讯录管理系统就完成了
简单演示一下,剩下的部分就不再演示了
完整代码如下:
头文件部分Contact book.h
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<assert.h> #include<stdlib.h> #include<Windows.h> #define NAME_MAX_SIZE 20 #define TEL_MAX_SIZE 20 #define ADDR_MAX_SIZE 30 #define GENDER_MAX_SIZE 10 #define CONTACT_SIZE 10 typedef struct info { char name[NAME_MAX_SIZE]; char tel[TEL_MAX_SIZE]; char addr[ADDR_MAX_SIZE]; char gender[GENDER_MAX_SIZE]; int age; //先存放四个字符型再存放整形,利用内存对齐来达到空间利用最大化 }info; typedef struct { info* data; int capacity; int size; }contact, *pcontact; //采用顺序表的数据类型来存放数据 void InitContact(pcontact p); void AddContact(pcontact p); void DelContact(pcontact p); void SearchContact(pcontact p); void SortContact(pcontact p); void ShowContact(pcontact p); void ModifyContact(pcontact p); void EmptyContact(pcontact p); int CheckCapacity(pcontact p); int GetPosition(char* name, pcontact p); void SaveContact(pcontact p); void LoadContact(pcontact p); void EndContact(pcontact p);
函数实现部分Contact book.c:
#include "Contact Book.h" void InitContact(pcontact p) { p->data = (info*)malloc(CONTACT_SIZE * sizeof(info)); if (NULL == p->data) { printf("初始化失败!!!\n"); exit(0); } p->capacity = CONTACT_SIZE; p->size = 0; } void AddContact(pcontact p) { assert(p); system("cls"); if (0 == CheckCapacity(p)) { printf("通讯录已满,添加失败\n"); return; } printf("请输入姓名:\n"); scanf("%s", p->data[p->size].name); printf("请输入电话:\n"); scanf("%s", p->data[p->size].tel); printf("请输入性别:\n"); scanf("%s", p->data[p->size].gender); printf("请输入地址:\n"); scanf("%s", p->data[p->size].addr); printf("请输入年龄:\n"); scanf("%d", &(p->data[p->size].age)); printf("添加成功!!!\n"); p->size++; } void DelContact(pcontact p) { assert(p); system("cls"); int pos, i; char name[NAME_MAX_SIZE]; if (!p->size) { printf("通讯录为空\n"); return; } printf("请输入要删除的人的姓名:\n"); scanf("%s", name); pos = GetPosition(name, p); if (-1 == pos) { printf("此人不存在\n"); } else { for (i = pos; pos < p->size - 1; i++) { p->data[i] = p->data[i + 1]; } p->size--; printf("删除成功!!!\n"); } } void ShowContact(pcontact p) { assert(p); system("cls"); int i; if (!p->size) { printf("通讯录为空\n"); return; } for (i = 0; i < p->size; i++) { printf("*******************************************\n"); printf("********** 第 %d 位联系人 **********\n", i + 1); printf("姓名:%s \n", p->data[i].name); printf("性别:%s \n", p->data[i].gender); printf("年龄:%d \n", p->data[i].age); printf("地址:%s \n", p->data[i].addr); printf("电话:%s \n", p->data[i].tel); printf("*******************************************\n"); } }void ModifyContact(pcontact p) { assert(p); system("cls"); char name[NAME_MAX_SIZE]; int pos; printf("请输入要修改的人的姓名:\n"); scanf("%s", name); pos = GetPosition(name, p); if (-1 == pos) { printf("此人不存在\n"); } else { printf("请输入修改后的姓名:\n"); scanf("%s", p->data[pos].name); printf("请输入修改后的电话:\n"); scanf("%s", p->data[pos].tel); printf("请输入修改后的性别:\n"); scanf("%s", p->data[pos].gender); printf("请输入修改后的年龄:\n"); scanf("%d", &(p->data[pos].age)); printf("请输入修改后的地址:\n"); scanf("%s", p->data[pos].addr); printf("修改成功!!!\n"); } } void SearchContact(pcontact p) { assert(p); system("cls"); char name[NAME_MAX_SIZE]; int pos; printf("请输入要查找的人的姓名:\n"); scanf("%s", name); pos = GetPosition(name, p); if (-1 == pos) { printf("此人不存在:\n"); } else { printf("*******************************************\n"); printf("姓名:%s \n", p->data[pos].name); printf("性别:%s \n", p->data[pos].gender); printf("年龄:%d \n", p->data[pos].age); printf("地址:%s \n", p->data[pos].addr); printf("电话:%s \n", p->data[pos].tel); printf("*******************************************\n"); printf("查找成功!!!\n"); } } int GetPosition(char* name, pcontact p) { assert(p); int pos; for (pos = 0; pos < p->size; pos++) { if (0 == strcmp(name, p->data[pos].name)) { return pos; } } return -1; } void EmptyContact(pcontact p) { assert(p); system("cls"); if (!p->size) { printf("通讯录为空\n"); return; } else { free(p->data); p->data = NULL; p->size = 0; p->capacity = 0; printf("通讯录清空成功!!!\n"); } } int CheckCapacity(pcontact p) { assert(p); if (p->size == p->capacity) { printf("通讯录已满,进行扩容\n"); ; info *temp = realloc(p->data, (p->capacity + CONTACT_SIZE) * sizeof(info)); if (NULL == temp) { printf("扩容失败\n"); return 0; } else { p->data = temp; p->capacity += CONTACT_SIZE; printf("扩容成功!!!\n"); } } return 1; } void SortContact(pcontact p) { assert(p); system("cls"); int i, j, flag = 1; info temp = { 0 }; for (i = p->size; i > 0 && flag; i--) { flag = 0; for (j = 1; j < p->size; j++) { if (strcmp(p->data[j].name, p->data[j - 1].name) < 0) { temp = p->data[j]; p->data[j] = p->data[j - 1]; p->data[j - 1] = temp; flag = 1; } } } printf("排序成功!!!\n"); } void SaveContact(pcontact p) { assert(p); system("cls"); FILE* pf = fopen("contact.dat", "wb"); int i; if (NULL == pf) { printf("文件打开失败\n"); return; } for (i = 0; i < p->size; i++) { fwrite(&(p->data[i]), sizeof(info), 1, pf); } printf("通讯录保存成功\n"); fclose(pf); pf = NULL; } void LoadContact(pcontact p) { assert(p); system("cls"); FILE* pf = fopen("contact.dat", "rb"); if (NULL == pf) { printf("文件打开失败\n"); return; } while (fread(&(p->data[p->size]), sizeof(info), 1, pf)) { if (CheckCapacity(p)) { p->size++; } } printf("通讯录读取成功\n"); fclose(pf); pf = NULL; } void EndContact(pcontact p) { free(p->data); p->data = NULL; p->size = 0; p->capacity = 0; exit(0); }
测试部分:
test.c
#include "Contact Book.h" void Menu() { printf("************************************************\n"); printf("** 0.退出程序 1.添加联系人 **\n"); printf("** 2.删除联系人 3.修改联系人 **\n"); printf("** 4.查找联系人 5.通讯录排序 **\n"); printf("** 6.显示所有联系人 7.删除所有联系人 **\n"); printf("** 8.保存通讯录 9.读取通讯录 **\n"); printf("************************************************\n"); } void Test() { int input; contact book; void (*p[10])(pcontact p) = { EndContact, AddContact, DelContact, ModifyContact, SearchContact, SortContact, ShowContact, EmptyContact, SaveContact, LoadContact, }; //利用函数指针数组简化不必要的代码 InitContact(&book); //初始化 do { Menu(); printf("请输入要进行的操作:"); scanf("%d", &input); if ((input <= 9 && input >= 0)) { (*p[input])(&book); } else { printf("输入错误:\n"); } } while (input); } int main() { Test(); return 0; }
github链接:https://github.com/HONGYU-LEE/test/tree/master/project/Contact%20Book
- 点赞 1
- 收藏
- 分享
- 文章举报
相关文章推荐
- C实现通讯录管理系统(亮点:纯链表实现、子串匹配,文件读写)
- c语言实现通讯录管理系统(c课程设计)
- 【c语言】通讯录的简单实现文件版本(动态开辟内存)
- 文件读写操作+动态内存分配+结构体指针+函数指针数组实现通讯录系统
- C语言构建WEB管理系统(五):CGI实现上传文件
- C语言实现通讯录系统——容量自增,文件版本
- C语言通讯录管理系统 利用fwrite和fread进行文件存取
- Linux环境下C语言实现简单的基于文件的学生信息管理系统
- [置顶] c语言文件读取 学生成绩管理系统的设计与实现
- C语言实现通讯录管理系统
- 通讯录管理系统——文件的读写
- C语言实现学生信息管理系统(包含文件存取)
- 通讯录c语言实现(动态内存开辟&文件存储)
- 用C语言实现一个学生成绩管理系统 实现学生信息管理。包括:录入、查询、排序等功能。 要求: 用数据文件保存学生基本信息(学号 姓名 课程1 课程2 课程3…) ,利用菜单可以循环实现各个功能。
- c语言学生信息管理系统(基于文件、链表)
- 歌厅歌曲管理系统(转)用c语言实现的一个课程设计
- 【大话QT之一】QTreeWidget实现动态加载本地文件系统
- (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】
- C语言实现二进制文件读写
- C语言通讯录管理系统