大家好,我是苏貝,本篇博客带大家优化上一篇的通讯录,如果你觉得我写的还不错的话,可以给我一个赞吗,感谢❤️


目录

  • 一. 前言
  • 二. 动态通讯录
    • 2.1 通讯录结构体
    • 2.2 初始化通讯录
    • 2.3 增加联系人
    • 2.4 销毁通讯录
  • 三. 模块化代码实现
    • 3.1 test.c
    • 3.2 contact.h
    • 3.3 contact.c
    • 3.4 结果演示

一. 前言

在上一篇博文 实现通讯录管理系统 的最后,我们了解了那段代码的问题:通讯录的大小是固定的100个元素,如果想要存放1000个人的信息,那么空间就不够了;如果信息太少,只想存10个人的信息,那么空间就大了。即使可以在源代码中修改#define定义的值解决,也不免有些麻烦。怎么解决?用动态内存管理!

本篇博文要实现通讯录管理系统,假设初始时只能存储3个人的信息,若超过三人,则通讯录容量+2,再存储联系人信息


二. 动态通讯录

我们从test.c文件中往下看,明白要修改的代码

2.1 通讯录结构体

在test.c文件中,我们先定义了通讯录变量。那么,通讯录类型是否需要修改呢?人的信息的结构体类型自然是不用修改的

typedef struct PeoInfo{char name[NAME_MAX];int age;char gender[GENDER_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];}PeoInfo;

但是通讯录类型似乎需要修改。因为静态版本中规定了通讯录最大存储100个人的信息,而我们的优化是用malloc函数和realloc函数实现动态管理通讯录,所以从静态版本的data数组到动态版本的data指针,指向之后用malloc函数开辟的空间。除了要知道当前通讯录中存放的人的信息的个数,我们也要知道通讯录的容量。当存放的人的信息的个数==通讯录的容量时,我们就应该要增加容量了

//静态版本//typedef struct Contact//{//PeoInfo data[MAX];//int sz;//}Contact;//动态版本typedef struct Contact{PeoInfo *data;int sz;//当前通讯录中存放的人的信息的个数int capacity;//通讯录的容量}Contact;

2.2 初始化通讯录

静态初始化时,是将sz的值赋值为0,再将data数组中的内容全部初始化为0。动态初始化时,sz也要被赋值为0,通讯录容量capacity要被赋值为3,3是#define定义的标识符常量。将malloc函数或者calloc函数开辟的空间的起始位置的地址传给指针变量data,因为需要将开辟的空间全初始化为0,所以使用calloc函数。最后要判断空间是否开辟成功,如果不成功就会返回NULL,所以要对指针变量data判断

//静态初始化通讯录//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_CAP;//3pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact_calloc");return;}}

2.3 增加联系人

静态通讯录中,增加联系人时要先判断通讯录是否满了,那我们动态通讯录中,也需要判断通讯录是否满了,如果满了,那就要增加通讯录的容量。用realloc函数修改开辟的内存空间的大小,每次增容时,容量增加2,2是#define定义的标识符常量。判断增容是否成功,如果指针变量tmp是NULL,开辟失败。如果不是,那将变量tmp赋值给指针变量data

//静态增加联系人//void AddContact(Contact* pc)//{//assert(pc);//if (pc->sz == MAX)//{//printf("通讯录已满,增加失败\n");//return;//}//printf("请输入名字:");//scanf("%s",pc->data[pc->sz].name );//printf("请输入年龄:");//scanf("%d", &(pc->data[pc->sz].age));//printf("请输入性别:");//scanf("%s", pc->data[pc->sz].gender);//printf("请输入电话:");//scanf("%s", pc->data[pc->sz].tele);//printf("请输入地址:");//scanf("%s", pc->data[pc->sz].addr);////pc->sz++;//printf("增加成功\n");//}//动态增加联系人void AddContact(Contact* pc){assert(pc);//增容if (pc->sz == pc->capacity){PeoInfo* tmp = realloc(pc->data, (pc->capacity + DEFAAULT_INI) * sizeof(PeoInfo));if (tmp == NULL){perror("AddContact_realloc");return;}pc->data = tmp;pc->capacity += DEFAAULT_INI;printf("增容成功\n");}printf("请输入名字:");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].gender);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("增加成功\n");}

2.4 销毁通讯录

因为使用了动态内存开辟空间,所以最好在退出程序前释放掉所开辟的空间

void DestroyContact(Contact* pc){free(pc->data);pc->data = NULL;}

三. 模块化代码实现

3.1 test.c

#include"contact.h"void menu(){printf("-----------------------------------\n");printf("***********************************\n");printf("******1.Add 2.Del******\n");printf("******3.Select4.Modify ******\n");printf("******5.Show6.sort ******\n");printf("******0.exit ******\n");printf("***********************************\n");printf("-----------------------------------\n");}enum Option{EXIT,ADD,DEL,SELECT,MODIFY,SHOW,SORT};int main(){Contact con;//初始化通讯录InitContact(&con);int input = 0;do{ menu();printf("请选择:");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SELECT:SelectContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case SORT:SortContact(&con);break;case EXIT:printf("退出程序\n");DestroyContact(&con);break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;}

3.2 contact.h

#pragma once#include#include#include#include#define NAME_MAX 20#define GENDER_MAX 5#define TELE_MAX 12#define ADDR_MAX 30//#define MAX 1000#define DEFAULT_CAP 3#define DEFAAULT_INI 2typedef struct PeoInfo{char name[NAME_MAX];int age;char gender[GENDER_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 DelContact(Contact* pc);//打印通讯录void ShowContact(Contact* pc);//查找联系人void SelectContact(Contact* pc);//修改联系人信息void ModifyContact(Contact* pc);//以名字排序所有联系人void SortContact(Contact* pc);//销毁通讯录void DestroyContact(Contact* pc);

3.3 contact.c

#include"contact.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_CAP;pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact_calloc");return;}}//静态增加联系人//void AddContact(Contact* pc)//{//assert(pc);//if (pc->sz == MAX)//{//printf("通讯录已满,增加失败\n");//return;//}//printf("请输入名字:");//scanf("%s",pc->data[pc->sz].name );//printf("请输入年龄:");//scanf("%d", &(pc->data[pc->sz].age));//printf("请输入性别:");//scanf("%s", pc->data[pc->sz].gender);//printf("请输入电话:");//scanf("%s", pc->data[pc->sz].tele);//printf("请输入地址:");//scanf("%s", pc->data[pc->sz].addr);////pc->sz++;//printf("增加成功\n");//}//动态增加联系人void AddContact(Contact* pc){assert(pc);//增容if (pc->sz == pc->capacity){PeoInfo* tmp = realloc(pc->data, (pc->capacity + DEFAAULT_INI) * sizeof(PeoInfo));if (tmp == NULL){perror("AddContact_realloc");return;}pc->data = tmp;pc->capacity += DEFAAULT_INI;printf("增容成功\n");}printf("请输入名字:");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].gender);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("增加成功\n");}int FindOfName(char* name, Contact* pc){assert(name && pc);int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(name, (pc->data[i].name)))return i;}return -1;}//删除联系人void DelContact(Contact* pc){assert(pc);char name[NAME_MAX] = { 0 };if (pc->sz == 0){printf("通讯录为空,删除失败\n");return;}printf("请输入要删除的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要删除的人\n");return;}int i = 0;for (i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");}//打印通讯录void ShowContact(Contact* pc){assert(pc);if (pc->sz == 0){printf("通讯录为空,打印无意义\n");return;}int i = 0;printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[i].name, pc->data[i].age,pc->data[i].gender, pc->data[i].tele, pc->data[i].addr);}}//查找联系人void SelectContact(Contact* pc){char name[NAME_MAX] = { 0 };printf("请输入要查找的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要查找的人\n");return;}printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[ret].name, pc->data[ret].age,pc->data[ret].gender, pc->data[ret].tele, pc->data[ret].addr);}//修改联系人信息void ModifyContact(Contact* pc){assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要修改的人\n");return;}printf("请输入名字:");scanf("%s", pc->data[ret].name);printf("请输入年龄:");scanf("%d", &(pc->data[ret].age));printf("请输入性别:");scanf("%s", pc->data[ret].gender);printf("请输入电话:");scanf("%s", pc->data[ret].tele);printf("请输入地址:");scanf("%s", pc->data[ret].addr);}int cmp(const void* a, const void* b){return strcmp((char*)a, (char*)b);}//以名字排序所有联系人void SortContact(Contact* pc){assert(pc);qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);printf("排序成功\n");}//销毁通讯录void DestroyContact(Contact* pc){free(pc->data);pc->data = NULL;}

3.4 结果演示

因为在6个功能中,只修改了增加联系人信息这一个功能,其余5个功能并未修改,因此结果演示中只演示通讯录容量不够时增容的情况



好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞吗,感谢看到这里,我们下篇博客见❤️