C语言之动态内存管理实现通讯录(完整版)

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


这就是动态通讯录完整版,大家下期再见!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/130960.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

操作系统学习笔记(学习中)

计算机系统概述 1.操作系统概念 管理系统软/硬件资源&#xff0c;为程序提供服务 2.发展与分类 3.操作系统的运行环境 运行机制 指令&#xff1a;&#xff08;二进制机器指令&#xff09;&#xff0c;CPU能识别&#xff0c;执行的最基本命令 应用程序&#xff1a;程序员写…

Splunk 创建特色 dashboard 报表

1: 背景: 对原有的dashboard 进行增加点东西,特别是文字部分: 比如: 增加:“this is a guidline for how to use performance". 这段话,就不能写在title, 那样,这段文字,会出现在dashboard 的PDF 文件的分割线的上面,不符合要求。 2: 解决问题: 正确的做法是…

Qt学习:图形视图框架的使用

文章目录 前言一、场景、视图和图形项的介绍二、图形视图框架的坐标系统三、图形视图框架的事件处理四、示例完整代码五、QtCreator官方示例总结 前言 近期重温了一下Qt中的图形视图框架&#xff0c;这里将所学习的内容进行记录总结。这个框架提供了一个基于图形项的模型视图编…

Java配置47-Spring Eureka 未授权访问漏洞修复

文章目录 1. 背景2. 方法2.1 Eureka Server 添加安全组件2.2 Eureka Server 添加参数2.3 重启 Eureka Server2.4 Eureka Server 升级版本2.5 Eureka Client 配置2.6 Eureka Server 添加代码2.7 其他问题 1. 背景 项目组使用的 Spring Boot 比较老&#xff0c;是 1.5.4.RELEASE…

Linux生成静态库

GCC 什么是GCC GCC 是 GNU 编译器集合&#xff08;GNU Compiler Collection&#xff09;的缩写。它是一个开源的编程语言编译器&#xff0c;支持多种编程语言&#xff0c;包括 C、C、Objective-C、Fortran、Ada 和 Go 等。GCC 最初由理查德斯托曼&#xff08;Richard Stallman…

2022最新版-李宏毅机器学习深度学习课程-P32 Transformer

一、 seq2seq 1. 含义 输入一个序列&#xff0c;机器输出另一个序列&#xff0c;输出序列长度由机器决定。 文本翻译&#xff1a;文本至文本&#xff1b;  语音识别&#xff1a;语音至文本&#xff1b;  语音合成&#xff1a;文本至语音&#xff1b;  聊天机器人&#…

WPF布局控件之DockPanel布局

前言&#xff1a;博主文章仅用于学习、研究和交流目的&#xff0c;不足和错误之处在所难免&#xff0c;希望大家能够批评指出&#xff0c;博主核实后马上更改。 概述&#xff1a; DockPanel 位置子控件基于子 Dock 属性&#xff0c;你有 4 个选项停靠&#xff0c;左 (默认) &…

HarmonyOS 数据管理与应用数据持久化(二)

通过键值型数据库实现数据持久化 场景介绍 键值型数据库存储键值对形式的数据&#xff0c;当需要存储的数据没有复杂的关系模型&#xff0c;比如存储商品名称及对应价格、员工工号及今日是否已出勤等&#xff0c;由于数据复杂度低&#xff0c;更容易兼容不同数据库版本和设备…

Gradle笔记 一 Gradle的安装与入门

文章目录 Gradle 入门Gradle 简介学习Gradle 的原因&#xff1a; 常见的项目构建工具Gradle 安装Gradle 安装说明安装JDK 下载并解压到指定目录配置环境变量检测是否安装成功 Gradle 项目目录结构Gradle 创建第一个项目Gradle 中的常用指令修改maven 下载源Wrapper 包装器使用教…

项目管理之如何估算项目工作成本

在项目管理中&#xff0c;如何估算项目工作成本是一个关键问题。为了解决这个问题&#xff0c;我们可以采用自上而下的成本限额估算法和自下而上的成本汇总估算法。这两种方法各有优缺点&#xff0c;但都可以帮助我们准确地估算项目工作成本。 自上而下的成本限额估算法 自上…

InnoDB中Buffer Pool详解

1. 概念及特点 Buffer Pool 是 MySQL 中 InnoDB 存储引擎用来缓存表数据和索引数据的内存区域。这个内存区域被用来存储磁盘上的数据页的副本&#xff0c;这样常用的数据可以在内存中快速被访问&#xff0c;而不必每次都从磁盘中读取。 以下是 Buffer Pool 的一些重要特点&a…

串口通信(6)应用定时器中断+串口中断实现接收一串数据

本文为博主 日月同辉&#xff0c;与我共生&#xff0c;csdn原创首发。希望看完后能对你有所帮助&#xff0c;不足之处请指正&#xff01;一起交流学习&#xff0c;共同进步&#xff01; > 发布人&#xff1a;日月同辉,与我共生_单片机-CSDN博客 > 欢迎你为独创博主日月同…

I/O多路转接之select

承接上文&#xff1a;I/O模型之非阻塞IO-CSDN博客 简介 select函数原型介绍使用 一个select简单的服务器的代码书写 select的缺点 初识select 系统提供select函数来实现多路复用输入/输出模型 select系统调用是用来让我们的程序监视多个文件描述符的状态变化的; 程序会停在s…

unittest 通过TextTestRunner(failfast=True),失败或错误时停止执行case

failfast是unittest.TextTestRunner的一个参数&#xff0c;它用于控制测试运行过程中遇到第一个失败或错误的测试方法后是否立即停止执行。 当failfast设置为True时&#xff0c;一旦发现第一个失败或错误的测试方法&#xff0c;测试运行就会立即停止&#xff0c;并输出相应的失…

sql基础+考点+题

查询&#xff1a;select from 筛选&#xff1a;where and和or 排序&#xff1a;order by&#xff08;降序排列需要指定DESC关键字&#xff09; join&#xff1a;left join 、right join 和inner join 分组聚合&#xff1a;group by ---搭配count , sum , avg 过滤&#x…

安全防御——二、ENSP防火墙实验学习

安全防御 一、防火墙接口以及模式配置1、untrust区域2、trust区域3、DMZ区域4、接口对演示 二、防火墙的策略1、定义与原理2、防火墙策略配置2.1 安全策略工作流程2.2 查询和创建会话 3、实验策略配置3.1 trust-to-untrust3.2 trust-to-dmz3.3 untrust-to-dmz 三、防火墙的区域…

消息中间件-RabbitMQ介绍

一、基础知识 1. 什么是RabbitMQ RabbitMQ是2007年发布&#xff0c;是一个在AMQP(高级消息队列协议)基础上完成的&#xff0c;简称MQ全称为Message Queue, 消息队列&#xff08;MQ&#xff09;是一种应用程序对应用程序的通信方法&#xff0c;由Erlang&#xff08;专门针对于大…

SPSS单因素方差分析

前言&#xff1a; 本专栏参考教材为《SPSS22.0从入门到精通》&#xff0c;由于软件版本原因&#xff0c;部分内容有所改变&#xff0c;为适应软件版本的变化&#xff0c;特此创作此专栏便于大家学习。本专栏使用软件为&#xff1a;SPSS25.0 本专栏所有的数据文件请点击此链接下…

Python基础入门例程39-NP39 字符串之间的比较(运算符)

最近的博文&#xff1a; Python基础入门例程38-NP38 牛牛的逻辑运算&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程37-NP37 不低于与不超过&#xff08;运算符&#xff09;-CSDN博客 Python基础入门例程36-NP36 谁的数字大&#xff08;运算符&#xff09;-CSD…

航模模拟器训练

固定翼吃灰很久忘记咋么操作 故这里发帖防止忘记 准备物品 航模遥控器 aux线 即两端都是耳机插头的线 解密狗 电脑 phoenixRC 航模模拟软件(【飞舜极创】凤凰5.0飞行模拟器 安装和设置方法_哔哩哔哩_bilibili) 链接&#xff1a;https://pan.baidu.com/s/1XL4ZWhMR7MQMxDPC7B…