动态通讯录程序
前面我们已经完整的学习完了通讯录程序代码 通讯录程序-CSDN博客
现在学完动态内存管理内容 动态内存管理-CSDN博客,将该程序中可为动态变化的部分修改为动态的版本
一、动态创建通讯录及初始化
前面我们创建的通讯录及初始化是这样的:
typedef struct Contact
{PeoInfo data[MAX];//存放人的信息int sz;//当前已经放的信息的个数
}Contact;
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;memset(pc->data,0,sizeof(pc->data));
}
既然是动态增加,那么就没有联系人满员的情况,因此通讯录没有最大值,我们将存放人的信息数组改为指向存放人的信息的空间地址,现在我们可以在此结构体上增加一个变量,代表当前通讯录的最大容量,当达到最大容量时,再动态的增加新的存放空间
假设通讯录的最大容量是3,当满员时一次增加2个存放人的信息的空间:
#define DEFAUT_ST 3
#define INC_SZ 2
修改创建的通讯录变为动态版本:
typedef struct Contact
{PeoInfo* data;//指向存放人的信息的空间int sz;//当前已经放的信息的个数 int capacity;//当前通讯录的最大容量
}Contact;
修改初始化的通讯录变为动态版本:
使用动态内存函数calloc(会把空间初始化为0,然后返回起始地址)
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;PeoInfo* ptr = (PeoInfo*)calloc(DEFAUT_SZ,sizeof(PeoInfo));if(ptr == NULL){perror("InitContact::calloc");return;}pc->data = ptr;pc->capacity = DEFAUT_SZ;
}
二、动态增加联系人
前面我们写的增加联系人函数:
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].sex);printf("请输入地址:>");scanf("%s",pc->data[pc->sz].addr);printf("请输入电话:>");scanf("%s",pc->data[pc->sz].tele);pc->sz++;
}
动态版本不需要再判断是否满员,只要有需要就会动态增加空间,因此我们需要确定的是什么时候需要增加空间——当当前已经存放的人的信息的个数等于最大容量时,就说明需要增加空间了,我们可以写一个函数 cheak_capacity 来判断及增容,使用动态内存函数 realloc(在原来容量的基础上增加指定数量空间) 来进行增容,最后想要确定是否真的增容可以添加一句提示词(增容成功)来验证
void cheak_capacity(Contact* pc)
{assert(pc);if(pc->sz == pc->capacity){//增加容量PeoInfo* ptr = (PeoInfo*)realloc(pc->data,(pc->capacity + INC_SZ) * sizeof(PeoInfo));if(ptr == NULL){perror("cheak_capacity::realloc");return;}pc->data = ptr;pc->capacity += INC_SZ;printf("***增容成功***\n");}
}
void AddContact(Contact* pc)
{assert(pc);cheak_capacity(pc); //增加联系人printf("请输入名字:>");scanf("%s",pc->data[pc->sz].name);printf("请输入年龄:>");scanf("%d",&(pc->data[pc->sz].age));printf("请输入性别:>");scanf("%s",pc->data[pc->sz].sex);printf("请输入地址:>");scanf("%s",pc->data[pc->sz].addr);printf("请输入电话:>");scanf("%s",pc->data[pc->sz].tele);pc->sz++;
}
三、销毁通讯录函数
我们学习了动态内存管理知道,calloc等函数在使用完后,需要我们进行手动释放及置空,因此,我们可以在最后增加一个销毁通讯录函数,来进行这些操作
void DestoryContact(Contact* pc)
{assert(pc);free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;pc = NULL;
}
四、完整代码
contact.h#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>#define MAX 100
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 30
#define TELE_MAX 12#define DEFAUT_SZ 3
#define INC_SZ 2//人的信息
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char addr[ADDR_MAX];char tele[TELE_MAX];
}PeoInfo;//动态版本
typedef struct Contact
{PeoInfo* data;//指向存放人的信息的空间int sz;//当前已经放的信息的个数int capacity;//当前通讯录的最大容量
}Contact;//初始化通讯录
void InitContact(Contact* pc);//增加联系人
void AddContact(Contact* pc);//显示通讯录中的信息
void ShowContact(const Contact* pc);//删除指定联系人
void DelContact(Contact* pc);//查找指定联系人
void SearchContact(const Contact* pc);//修改指定联系人
void ModifyContact(Contact* pc);//通过姓名排序
void SortContactByName(Contact* pc);//通过年龄排序
void SortContactByAge(Contact* pc);//销毁通讯录
void DestoryContact(Contact* pc);
tast.c#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"void menu()
{printf("******************************************\n");printf("****** 1. add 2. del ******\n");printf("****** 3. search 4. modify ******\n");printf("****** 5. show 0. exit ******\n");printf("****** 6.sortbyname 7.sortbyage******\n");printf("******************************************\n");}enum Option
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,sortbyname,sortbyage
};int main()
{int input = 0;int num = 0;//ͨ创建通讯录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:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case sortbyname:SortContactByName(&con);break;case sortbyage:SortContactByAge(&con);break;case EXIT:DestoryContact(&con);printf("退出通讯录\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}
contact.c#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"//动态版本
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;PeoInfo* ptr = (PeoInfo*)calloc(DEFAUT_SZ, sizeof(PeoInfo));if (ptr == NULL){perror("InitContact::calloc");return;}pc->data = ptr;pc->capacity = DEFAUT_SZ;
}void cheak_capacity(Contact* pc)
{assert(pc);if (pc->sz == pc->capacity){//增加容量PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr == NULL){perror("cheak_capacity::realloc");return;}pc->data = ptr;pc->capacity += INC_SZ;printf("***增容成功***\n");}
}//动态版本
void AddContact(Contact* pc)
{assert(pc);cheak_capacity(pc);//增加一个人的信息printf("请输入名字:>");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:>");scanf("%d", &pc->data[pc->sz].age);printf("请输入性别:>");scanf("%s", pc->data[pc->sz].sex);printf("请输入地址:>");scanf("%s", pc->data[pc->sz].addr);printf("请输入电话:>");scanf("%s", pc->data[pc->sz].tele);pc->sz++;
}void ShowContact(const Contact* pc)
{assert(pc);printf("-------------------------------显示结果-----------------------------------\n");int i = 0;printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字","年龄","性别","地址","电话");for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].addr, pc->data[i].tele);}printf("--------------------------------------------------------------------------\n");}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)
{assert(pc);char name[NAME_MAX] = { 0 };if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}//删除//找到要删除的人printf("请输入要删除的人的名字:>");scanf("%s", name);int ret = FindByName(pc, name);if (-1 == ret){printf("要删除的人不存在\n");return;}int i = 0;//删除for (i = ret; i < pc->sz - 1; i++)//这里-1是因为当i=99时,i+1就是100,即当要将下标为100的第101个元素搬到下标为99的第100个元素,越界访问{pc->data[i] = pc->data[i + 1];}pc->sz--;//已经删除掉一个人的信息,那么总的个数就要减掉一个printf("删除成功\n");
}void SearchContact(const Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要查找人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){printf("要查找的人不存在\n");return;}//打印信息printf("-------------------------------查找结果-----------------------------------\n");printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "名字", "年龄", "性别", "地址", "电话");printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].addr, pc->data[pos].tele);printf("--------------------------------------------------------------------------\n");
}void ModifyContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改的人的名字:>");scanf("%s", name);int pos = FindByName(pc, name);if (-1 == pos){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].addr);printf("请输入修改的电话:>");scanf("%s", pc->data[pos].tele);printf("修改成功\n");
}int cmpbyname(const void* p1, const void* p2)
{assert(p1 && p2);return strcmp(((PeoInfo*)p1)->name, ((PeoInfo*)p2)->name);
}
void SortContactByName(Contact* pc)
{assert(pc);if (pc->data == 0){printf("通讯录为空,无需排序\n");return;}qsort(pc->data, pc->sz, sizeof(PeoInfo), cmpbyname);printf("排序成功\n");
}int cmpbyage(const void* p1, const void* p2)
{assert(p1 && p2);return ((PeoInfo*)p1)->age - ((PeoInfo*)p2)->age;
}
void SortContactByAge(Contact* pc)
{assert(pc);if (pc->data == 0){printf("通讯录为空,无需排序\n");return;}qsort(pc->data, pc->sz, sizeof(PeoInfo), cmpbyage);printf("排序成功\n");
}void DestoryContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;pc = NULL;
}