我们在之前的博客中写过静态版的通讯录,我们今天来写一个动态版的,不需要规定它到底需要多大空间,只要还有内存,我们都可以存放的下!同时,函数实现原理,我在通讯录静态版的博客里做了详细的讲解,这里就不详细分析了,不了解原理的小伙伴们可以去C语言通讯录静态版了解一下!
目录
1.函数各部分功能
1.1初始化通讯录
1.2检测通讯录是否需要增容
1.3增加联系人
1.4删除联系人
1.5显示联系人
1.6按名字查找联系人
1.7查找指定联系人
1.8修改指定联系人的信息
1.9对所有联系人按姓名进行排序
1.10销毁通讯录,进行动态空间内存的释放
2.函数源码
2.1test.c测试代码
2.2contact.c函数各功能实现代码
2.3contact.h实现通讯录所需要的头文件代码
3.运行结果
我们在以前静态 的基础上不仅加入内存动态管理,还加入枚举,增强代码的可读性,同时我在代码难以理解的地方增加了详细的注释,相信大家可以理解!
1.函数各部分功能
1.1初始化通讯录
//初始化这个通讯录,初始化为对应的值 void InitContact(Contact* pc) { assert(pc); //为通讯录存放人的信息的结构体分配初始空间,并把里面数据直接 //初始化为0,calloc函数很合适 PeopInfo* str = (PeopInfo*)calloc(DEFAULT_SZ, sizeof(PeopInfo)); if (str == NULL) { perror("calloc"); return; } pc->data = str; pc->sz = 0; pc->capacity = DEFAULT_SZ; }
1.2检测通讯录是否需要增容
//空间增容函数 void check_capacity(Contact* pc) { assert(pc); if (pc->sz == pc->capacity) { //通讯录已满,进行增容 PeopInfo* str = (PeopInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeopInfo)); if (str == NULL) { perror("realloc"); return; } pc->data = str; pc->capacity += INC_SZ;//总容量增加 printf("空间增容成功,可以继续添加联系人\n"); } }
1.3增加联系人
//增加通讯录联系人 void AddContact(Contact* pc) { assert(pc); check_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].Tele); printf("请输入联系人家庭住址:>"); scanf("%s", pc->data[pc->sz].Addr); pc->sz++; }
1.4删除联系人
//删除指定联系人 void DelContact(Contact* pc) { assert(pc); char Name[NAME_MAX] = { 0 }; int i = 0; if (pc->sz == 0) { printf("通讯录为空,无法删除!\n"); return; } printf("请输入要删除的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { printf("要删除的联系人不存在!\n"); return; } for (i = pos; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除联系人成功!\n"); }
1.5显示联系人
//显示所有联系人 void ShowContact(const Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法显示!\n"); return; } int i = 0; printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n","姓名","年龄","性别","电话号码","家庭住址"); for (i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].Name, pc->data[i].Age, pc->data[i].Sex, pc->data[i].Tele, pc->data[i].Addr); } }
1.6按名字查找联系人
//通过名字查找 int FindByName(const Contact* pc, char* Name) { assert(pc); int i = 0; if (pc->sz == 0) { printf("通讯录为空,无法查找!"); return; } for (i = 0; i < pc->sz; i++) { if (strcmp(Name, pc->data[i].Name) == 0) return i; } return -1; }
1.7查找指定联系人
//查找指定联系人 void SehContact(const Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法查找!\n"); return; } char Name[NAME_MAX] = { 0 }; printf("请输入要查找的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { printf("要查找的联系人不存在!\n"); return; } printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话号码", "家庭住址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].Name, pc->data[pos].Age, pc->data[pos].Sex, pc->data[pos].Tele, pc->data[pos].Addr); }
1.8修改指定联系人的信息
//修改指点联系人的信息 void MofContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法修改!\n"); return; } char Name[NAME_MAX] = { 0 }; printf("请输入要修改的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { 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].Tele); printf("请输入联系人家庭住址:>"); scanf("%s", pc->data[pos].Addr); }
1.9对所有联系人按姓名进行排序
//对所有联系人按姓名进行排序 void SortContact(const Contact* pc) { assert(pc); int i = 0; int j = 0; for (i = 0; i < pc->sz; i++) { for (j = i; j < pc->sz; j++) { if (strcmp(pc->data[i].Name, pc->data[j].Name) > 0) { PeopInfo temp[] = { 0 }; temp[0] = pc->data[i]; pc->data[i] = pc->data[j]; pc->data[j] = temp[0]; } } } ShowContact(pc);//显示一下排列结果 }
1.10销毁通讯录,进行动态空间内存的释放
//销毁通讯录,释放动态内存空间 void DestoryContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; pc = NULL; printf("通讯录已销毁\n"); }
2.函数源码
2.1test.c测试代码
//创建一个动态空间内存通讯录,里面存放人的信息,包括姓名,年龄,性别 //电话号码和家庭住址 //结合枚举,必要时要增容 //它包括一下功能 //1.增加联系人 //2.删除指定联系人 //3.查找指定联系人 //4.修改指定联系人 //5.显示所有联系人 //6.对所有联系人进行排序(按姓名) //7.退出通讯录(这时要记得释放动态内存开辟的空间,避免内存泄漏 #include"contact.h"//引用自己创建的头文件,用双引号 //加入枚举,给下面Switch case语句一个提示,函数写到了通讯录的哪个功能 enum contact { exitContact, addContact, delContact, showContact, sehContact, mofContact, sortContact, }; void menu(void) { printf("*******************************************\n"); printf("********** 1.AddContact **********\n"); printf("********** 2.DelContact **********\n"); printf("********** 3.ShowContact **********\n"); printf("********** 4.SehContact **********\n"); printf("********** 5.MofContact **********\n"); printf("********** 6.SortContact **********\n"); printf("********** 0.ExitContact **********\n"); printf("*******************************************\n"); } int main() { int input = 0; Contact con; //初始化通讯录 InitContact(&con); //打印菜单 do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case addContact: AddContact(&con); break; case delContact: DelContact(&con); break; case showContact: ShowContact(&con); break; case sehContact: SehContact(&con); break; case mofContact: MofContact(&con); break; case sortContact: SortContact(&con); break; case exitContact: //销毁通讯录,进行动态空间的释放 DestoryContact(&con); break; default: printf("输入错误,请重新输入!\n"); break; } } while (input); return 0; }
2.2contact.c函数各功能实现代码
#include"contact.h" //空间增容函数 void check_capacity(Contact* pc) { assert(pc); if (pc->sz == pc->capacity) { //通讯录已满,进行增容 PeopInfo* str = (PeopInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeopInfo)); if (str == NULL) { perror("realloc"); return; } pc->data = str; pc->capacity += INC_SZ;//总容量增加 printf("空间增容成功,可以继续添加联系人\n"); } } //通过名字查找 int FindByName(const Contact* pc, char* Name) { assert(pc); int i = 0; if (pc->sz == 0) { printf("通讯录为空,无法查找!"); return; } for (i = 0; i < pc->sz; i++) { if (strcmp(Name, pc->data[i].Name) == 0) return i; } return -1; } //初始化这个通讯录,初始化为对应的值 void InitContact(Contact* pc) { assert(pc); //为通讯录存放人的信息的结构体分配初始空间,并把里面数据直接 //初始化为0,calloc函数很合适 PeopInfo* str = (PeopInfo*)calloc(DEFAULT_SZ, sizeof(PeopInfo)); if (str == NULL) { perror("calloc"); return; } pc->data = str; pc->sz = 0; pc->capacity = DEFAULT_SZ; } //增加通讯录联系人 void AddContact(Contact* pc) { assert(pc); check_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].Tele); printf("请输入联系人家庭住址:>"); scanf("%s", pc->data[pc->sz].Addr); pc->sz++; } //删除指定联系人 void DelContact(Contact* pc) { assert(pc); char Name[NAME_MAX] = { 0 }; int i = 0; if (pc->sz == 0) { printf("通讯录为空,无法删除!\n"); return; } printf("请输入要删除的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { printf("要删除的联系人不存在!\n"); return; } for (i = pos; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除联系人成功!\n"); } //显示所有联系人 void ShowContact(const Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法显示!\n"); return; } int i = 0; printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n","姓名","年龄","性别","电话号码","家庭住址"); for (i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[i].Name, pc->data[i].Age, pc->data[i].Sex, pc->data[i].Tele, pc->data[i].Addr); } } //查找指定联系人 void SehContact(const Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法查找!\n"); return; } char Name[NAME_MAX] = { 0 }; printf("请输入要查找的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { printf("要查找的联系人不存在!\n"); return; } printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话号码", "家庭住址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].Name, pc->data[pos].Age, pc->data[pos].Sex, pc->data[pos].Tele, pc->data[pos].Addr); } //修改指点联系人的信息 void MofContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法修改!\n"); return; } char Name[NAME_MAX] = { 0 }; printf("请输入要修改的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { 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].Tele); printf("请输入联系人家庭住址:>"); scanf("%s", pc->data[pos].Addr); } //对所有联系人按姓名进行排序 void SortContact(const Contact* pc) { assert(pc); int i = 0; int j = 0; for (i = 0; i < pc->sz; i++) { for (j = i; j < pc->sz; j++) { if (strcmp(pc->data[i].Name, pc->data[j].Name) > 0) { PeopInfo temp[] = { 0 }; temp[0] = pc->data[i]; pc->data[i] = pc->data[j]; pc->data[j] = temp[0]; } } } ShowContact(pc);//显示一下排列结果 } //销毁通讯录,释放动态内存空间 void DestoryContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; pc = NULL; printf("通讯录已销毁\n"); }
2.3contact.h实现通讯录所需要的头文件代码
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<assert.h> #include<errno.h> #define DEFAULT_SZ 3//初始通讯录内存放的联系人个数 #define INC_SZ 2//每次增容的空间 #define NAME_MAX 20 #define SEX_MAX 5 #define TELE_MAX 12 #define ADDR_MAX 30 //创建一个结构体,用来存放人的信息 typedef struct PeopInfo { char Name[NAME_MAX]; int Age; char Sex[SEX_MAX]; char Tele[TELE_MAX]; char Addr[ADDR_MAX]; }PeopInfo; //创建通讯录,里面包含人的信息,通讯录原本空间大小,以及当前通讯录 //存放了多少人 typedef struct Contact { PeopInfo* data;//不可以是数组了,如果是数组,这块空间就已经被开辟好了 //不能在进行动态开辟,后续使用时变为了不可修改的左值,建议用指针 int sz;//当前以存放人的信息的个数 int capacity;//目前通讯录空间的容量 }Contact; //空间增容函数 void check_capacity(Contact* pc); //初始化这个通讯录,初始化为对应的值 void InitContact(Contact* pc); //增加通讯录联系人 void AddContact(Contact* pc); //删除指定联系人 void DelContact(Contact* pc); //显示所有联系人 void ShowContact(const Contact* pc); //通过名字查找 int FindByName(const Contact* pc, char* Name); //查找指定联系人 void SehContact(const Contact* pc); //修改指点联系人的信息 void MofContact(Contact* pc); //对所有联系人按姓名进行排序 void SortContact(const Contact* pc); //销毁通讯录,释放动态内存空间 void DestoryContact(Contact* pc);
3.运行结果
这就是动态通讯录完整版,大家下期再见!!!