1、动态版需求
- 假设通讯录初始化后,能存放3个人的信息
- 当我们空间存放满的时候,我们增加2个信息
- 以此类推每次不够就增加2个,例如3+2+2+2+……
2、不同于静态版之处
(1)创建通讯录
- 先回顾下静态版的创建通讯录:
typedef struct Contact { PeoInfo data[MAX]; //存放添加进来人的信息 int sz; //记录当前通讯录中有效信息的个数 }Contact;
当前结构体一次就为我们开辟1000个信息的一块空间,该空间为data,接下来创建sz表示记录有效元素个数,data和sz合起来放在Contact结构体里头,于是可创建con这样的通讯录
而现在希望开辟的空间是动态开辟的,比如我申请3个人的信息,这块空间需要把它的起始地址存起来,可以把这块空间的起始地址返回来放到指针里头,由指针来维护这块空间,假设维护这块空间的指针叫data指针,还得有一个变量记录当前通讯录已经放进去几个人的信息,还是用变量sz表示,此时还要有一个变量来记录当前通讯录的最大容量,用capacity来表示。当sz+到3=capacity时就要考虑增容的问题了
接下来就可以进行改造了:
//创建通讯录 typedef struct Contact { PeoInfo *data; //指向动态申请的空间,用来存放联系人的信息 int sz; //记录当前通讯录中有效信息的个数 int capacity; //记录当前通讯录的最大容量 }Contact;
Contact con;//通讯录
(2)初始化通讯录
- 基本要求:
- 给data申请一块连续的空间在堆上
- sz=0
- capacity初始化为当前最大的容量
- 先回顾下静态版的初始化:
//初始化通讯录 void InitContact(Contact* pc) { pc->sz = 0; memset(pc->data, 0, sizeof(pc->data)); }
- 再来实现动态版初始化:
- contact.h 文件:
1. #define DEFAULT_SZ 3 2. #define INC_SZ 2
- contact.c 文件:
//初始化通讯录 void InitContact(Contact* pc) { pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo)); if (pc->data == NULL) { perror("InitContact"); return; } pc->sz = 0; //初始化后默认是0,一个元素都没 pc->capacity = DEFAULT_SZ; }
- 初始化后:
(3)增加联系人信息
- 先回顾下静态版的增加联系人:
void AddContact(Contact* 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].tele); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("增加成功\n"); }
- 再实现动态版的:
//动态版本-添加联系人 void AddContact(Contact* pc) { //考虑增容 if (pc->sz == pc->capacity) { PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo)); if (ptr != NULL) { pc->data = ptr; pc->capacity += INC_SZ; printf("增容成功\n"); } else { perror("AddConract"); 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].tele); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("增加成功\n"); }
(4)退出通讯录
- contact.h 文件:
void DestoryContact(Contact* pc);
- contact.c 文件:
//销毁通讯录 void DestoryContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; }
3、完整代码
(1)test.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. sort 6. print *********\n"); printf("******* 0. exit *********\n"); printf("*******************************************\n"); } enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SORT, PRINT }; int main() { int input = 0; //创建通讯录 Contact con;//通讯录 //初始化通讯录 //给data申请一块连续的空间在堆上 //sz=0 //capacity初始化为当前最大的容量 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 SORT: //排序 SortContact(&con); break; case PRINT: //打印 PrintContact(&con); break; case EXIT: //退出 //销毁通讯录 DestoryContact(&con); printf("退出通讯录\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0; }
(2)contact.h 文件
#pragma once #include<stdio.h> #include<string.h> #include<stdlib.h> #define MAX_NAME 20 #define MAI_SEX 10 #define MAX_TELE 12 #define MAX_ADDR 30 #define MAX 1000 #define DEFAULT_SZ 3 #define INC_SZ 2 //存放每个人的信息 typedef struct PeoInfo { char name[MAX_NAME]; char sex[MAI_SEX]; int age; char tele[MAX_TELE]; char addr[MAX_ADDR]; }PeoInfo; //创建通讯录 typedef struct Contact { PeoInfo *data; //指向动态申请的空间,用来存放联系人的信息 int sz; //记录当前通讯录中有效信息的个数 int capacity; //记录当前通讯录的最大容量 }Contact; //初始化通讯录 void InitContact(Contact* pc); //增加联系人 void AddContact(Contact* pc); //打印联系人信息 void PrintContact(const Contact* pc); //删除联系人信息 void DelContact(Contact* pc); //查找指定联系人 void SearchContact(Contact* pc); //修改指定联系人 void ModifyContact(Contact* pc); //排序联系人 void SortContact(Contact* ps); //销毁通讯录 void DestoryContact(Contact* pc);
(3)contact.c 文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"contact.h" //动态版本-初始化通讯录 void InitContact(Contact* pc) { pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo)); if (pc->data == NULL) { perror("InitContact"); return; } pc->sz = 0; //初始化后默认是0,一个元素都没 pc->capacity = DEFAULT_SZ; } //动态版本-添加联系人 void AddContact(Contact* pc) { //考虑增容 if (pc->sz == pc->capacity) { PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo)); if (ptr != NULL) { pc->data = ptr; pc->capacity += INC_SZ; printf("增容成功\n"); } else { perror("AddConract"); 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].tele); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("增加成功\n"); } //打印联系人信息 void PrintContact(const Contact* pc) { if (pc->sz == 0) { printf("通讯录为空!\n"); return; } int i = 0; //打印标题 printf("%-12s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 for (i = 0; i < pc->sz; i++) { printf("%-12s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr ); } } //查找要删除的联系人 static int FindByName(Contact* pc, char name[]) { 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[MAX_NAME] = { 0 }; if (pc->sz == 0) { printf("通讯录为空,无需删除\n"); return; } printf("请输入要删除人的名字:>"); scanf("%s", name); //1、得先查找要删除的人 //有/没有 int pos = FindByName(pc, name); if (pos == -1) { printf("要删除的人不存在\n"); return; } //2、删除 int i = 0; for (i = pos; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除成功\n"); } //查找指定联系人 void SearchContact(Contact* pc) { char name[MAX_NAME] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } else { int i = 0; //打印标题 printf("%-12s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 printf("%-12s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } } //修改指定联系人 void ModifyContact(Contact* pc) { char name[MAX_NAME] = { 0 }; printf("请输入要修改人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要修改的人不存在\n"); return; } else { 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].tele); printf("请输入地址:>"); scanf("%s", pc->data[pos].addr); printf("修改成功\n"); } } //通过姓名排序 int CmpByName(const void* e1, const void* e2) { return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name); } //通过年龄排序 int CmpByAge(const void* e1, const void* e2) { return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age; } //排序通讯录中联系人的先后顺序 void SortContact(Contact* ps) { int input = 0; printf("1、姓名\t2、年龄\n"); printf("请选择你要排序的方式:>"); scanf("%d", &input); switch (input) { case 1: qsort(ps->data, ps->sz, sizeof(PeoInfo), CmpByName);//排序 printf("排序成功\n"); break; case 2: qsort(ps->data, ps->sz, sizeof(PeoInfo), CmpByAge);//排序 printf("排序成功\n"); break; default: printf("请输入有效数字\n"); } } //销毁通讯录 void DestoryContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; }
- 运行结果如下: