我们在之前的博客中写过静态版的通讯录,我们今天来写一个动态版的,不需要规定它到底需要多大空间,只要还有内存,我们都可以存放的下!同时,函数实现原理,我在通讯录静态版的博客里做了详细的讲解,这里就不详细分析了,不了解原理的小伙伴们可以去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.运行结果
这就是动态通讯录完整版,大家下期再见!!!