【C语言】优化通讯录管理系统

大家好,我是苏貝,本篇博客带大家优化上一篇的通讯录,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


目录

  • 一. 前言
  • 二. 动态通讯录
    • 2.1 通讯录结构体
    • 2.2 初始化通讯录
    • 2.3 增加联系人
    • 2.4 销毁通讯录
  • 三. 模块化代码实现
    • 3.1 test.c
    • 3.2 contact.h
    • 3.3 contact.c
    • 3.4 结果演示

一. 前言

在上一篇博文 实现通讯录管理系统 的最后,我们了解了那段代码的问题:通讯录的大小是固定的100个元素,如果想要存放1000个人的信息,那么空间就不够了;如果信息太少,只想存10个人的信息,那么空间就大了。即使可以在源代码中修改#define定义的值解决,也不免有些麻烦。怎么解决?用动态内存管理!

本篇博文要实现通讯录管理系统,假设初始时只能存储3个人的信息,若超过三人,则通讯录容量+2,再存储联系人信息


二. 动态通讯录

我们从test.c文件中往下看,明白要修改的代码

2.1 通讯录结构体

在test.c文件中,我们先定义了通讯录变量。那么,通讯录类型是否需要修改呢?人的信息的结构体类型自然是不用修改的

typedef struct PeoInfo
{char name[NAME_MAX];int age;char gender[GENDER_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;

但是通讯录类型似乎需要修改。因为静态版本中规定了通讯录最大存储100个人的信息,而我们的优化是用malloc函数和realloc函数实现动态管理通讯录,所以从静态版本的data数组到动态版本的data指针,指向之后用malloc函数开辟的空间。除了要知道当前通讯录中存放的人的信息的个数,我们也要知道通讯录的容量。当存放的人的信息的个数==通讯录的容量时,我们就应该要增加容量了

//静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];
//	int sz;
//}Contact;//动态版本
typedef struct Contact
{PeoInfo *data;int sz;//当前通讯录中存放的人的信息的个数int capacity;//通讯录的容量
}Contact;

2.2 初始化通讯录

静态初始化时,是将sz的值赋值为0,再将data数组中的内容全部初始化为0。动态初始化时,sz也要被赋值为0,通讯录容量capacity要被赋值为3,3是#define定义的标识符常量。将malloc函数或者calloc函数开辟的空间的起始位置的地址传给指针变量data,因为需要将开辟的空间全初始化为0,所以使用calloc函数。最后要判断空间是否开辟成功,如果不成功就会返回NULL,所以要对指针变量data判断

//静态初始化通讯录
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}//动态初始化通讯录
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_CAP;//3pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact_calloc");return;}
}

2.3 增加联系人

静态通讯录中,增加联系人时要先判断通讯录是否满了,那我们动态通讯录中,也需要判断通讯录是否满了,如果满了,那就要增加通讯录的容量。用realloc函数修改开辟的内存空间的大小,每次增容时,容量增加2,2是#define定义的标识符常量。判断增容是否成功,如果指针变量tmp是NULL,开辟失败。如果不是,那将变量tmp赋值给指针变量data

//静态增加联系人
//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].gender);
//	printf("请输入电话:");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	pc->sz++;
//	printf("增加成功\n");
//}//动态增加联系人
void AddContact(Contact* pc)
{assert(pc);//增容if (pc->sz == pc->capacity){PeoInfo* tmp = realloc(pc->data, (pc->capacity + DEFAAULT_INI) * sizeof(PeoInfo));if (tmp == NULL){perror("AddContact_realloc");return;}pc->data = tmp;pc->capacity += DEFAAULT_INI;printf("增容成功\n");}printf("请输入名字:");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].gender);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("增加成功\n");
}

2.4 销毁通讯录

因为使用了动态内存开辟空间,所以最好在退出程序前释放掉所开辟的空间

void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;
}

三. 模块化代码实现

3.1 test.c

#include"contact.h"void menu()
{printf("-----------------------------------\n");printf("***********************************\n");printf("******  1.Add       2.Del    ******\n");printf("******  3.Select    4.Modify ******\n");printf("******  5.Show      6.sort   ******\n");printf("******  0.exit               ******\n");printf("***********************************\n");printf("-----------------------------------\n");
}enum Option
{EXIT,ADD,DEL,SELECT,MODIFY,SHOW,SORT
};int main()
{Contact con;//初始化通讯录InitContact(&con);int input = 0;do{ menu();printf("请选择:");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SELECT:SelectContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case SORT:SortContact(&con);break;case EXIT:printf("退出程序\n");DestroyContact(&con);break;default:printf("选择错误,请重新选择\n");break;}} while (input);return 0;
}

3.2 contact.h

#pragma once#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>#define NAME_MAX 20
#define GENDER_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30//#define MAX 1000#define DEFAULT_CAP 3
#define DEFAAULT_INI 2typedef struct PeoInfo
{char name[NAME_MAX];int age;char gender[GENDER_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;//静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];
//	int sz;
//}Contact;//动态版本
typedef struct Contact
{PeoInfo *data;int sz;//当前通讯录中存放的人的信息的个数int capacity;//通讯录的容量
}Contact;//初始化通讯录
void InitContact(Contact* pc);//增加联系人
void AddContact(Contact* pc);//删除联系人
void DelContact(Contact* pc);//打印通讯录
void ShowContact(Contact* pc);//查找联系人
void SelectContact(Contact* pc);//修改联系人信息
void ModifyContact(Contact* pc);//以名字排序所有联系人
void SortContact(Contact* pc);//销毁通讯录
void DestroyContact(Contact* pc);

3.3 contact.c

#include"contact.h"//静态初始化通讯录
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}//动态初始化通讯录
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_CAP;pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact_calloc");return;}
}//静态增加联系人
//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].gender);
//	printf("请输入电话:");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	pc->sz++;
//	printf("增加成功\n");
//}//动态增加联系人
void AddContact(Contact* pc)
{assert(pc);//增容if (pc->sz == pc->capacity){PeoInfo* tmp = realloc(pc->data, (pc->capacity + DEFAAULT_INI) * sizeof(PeoInfo));if (tmp == NULL){perror("AddContact_realloc");return;}pc->data = tmp;pc->capacity += DEFAAULT_INI;printf("增容成功\n");}printf("请输入名字:");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:");scanf("%s", pc->data[pc->sz].gender);printf("请输入电话:");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:");scanf("%s", pc->data[pc->sz].addr);pc->sz++;printf("增加成功\n");
}int FindOfName(char* name, Contact* pc)
{assert(name && pc);int i = 0;for (i = 0; i < pc->sz; i++){if (0 == strcmp(name, (pc->data[i].name)))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 = FindOfName(name, pc);if (ret == -1){printf("找不到要删除的人\n");return;}int i = 0;for (i = ret; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//打印通讯录
void ShowContact(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,打印无意义\n");return;}int i = 0;printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[i].name, pc->data[i].age,pc->data[i].gender, pc->data[i].tele, pc->data[i].addr);}
}//查找联系人
void SelectContact(Contact* pc)
{char name[NAME_MAX] = { 0 };printf("请输入要查找的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要查找的人\n");return;}printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[ret].name, pc->data[ret].age,pc->data[ret].gender, pc->data[ret].tele, pc->data[ret].addr);
}//修改联系人信息
void ModifyContact(Contact* pc)
{assert(pc);char name[NAME_MAX] = { 0 };printf("请输入要修改的人的名字:");scanf("%s", name);int ret = FindOfName(name, pc);if (ret == -1){printf("找不到要修改的人\n");return;}printf("请输入名字:");scanf("%s", pc->data[ret].name);printf("请输入年龄:");scanf("%d", &(pc->data[ret].age));printf("请输入性别:");scanf("%s", pc->data[ret].gender);printf("请输入电话:");scanf("%s", pc->data[ret].tele);printf("请输入地址:");scanf("%s", pc->data[ret].addr);
}int cmp(const void* a, const void* b)
{return strcmp((char*)a, (char*)b);
}//以名字排序所有联系人
void SortContact(Contact* pc)
{assert(pc);qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);printf("排序成功\n");
}//销毁通讯录
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;
}

3.4 结果演示

因为在6个功能中,只修改了增加联系人信息这一个功能,其余5个功能并未修改,因此结果演示中只演示通讯录容量不够时增容的情况
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

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

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

相关文章

Redis原理-IO模型和持久化

高性能IO模型 为什么单线程Redis能那么快 一方面&#xff0c;Redis 的大部分操作在内存上完成&#xff0c;再加上它采用了高效的数据结构&#xff0c;例如哈希表和跳表&#xff0c;这是它实现高性能的一个重要原因。另一方面&#xff0c;就是 Redis 采用了多路复用机制&#…

HTML简单实现v-if与v-for与v-model

Vue启动&#xff01;&#xff01; 首先VIewModel将View和Model连接一起&#xff0c;Model的数据改变View的数据也变 使用Visual Studio Code 启动Vue需要vue.js插件和导入CDN(包) vue.js插件&#xff1a;CTRL shift x 在搜索栏搜 索vue.js安装即可 CDN&#xff1a; http…

orb-slam3编译手册(Ubuntu20.04)

orb-slam3编译手册&#xff08;Ubuntu20.04&#xff09; 一、环境要求1.安装git2.安装g3.安装CMake4.安装vi编辑器 二、源代码下载三、依赖库下载1.Eigen安装2.Pangolin安装3.opencv安装4.安装Python & libssl-dev5.安装boost库 三、安装orb-slam3四、数据集下载及测试 写在…

k8s集群升级

目录 1. 部署cri-docker &#xff08;所有集群节点&#xff09; 2. 升级master节点 3. 升级worker节点 4. 部署containerd 1. 部署cri-docker &#xff08;所有集群节点&#xff09; k8s从1.24版本开始移除了dockershim&#xff0c;所以需要安装cri-docker插件才能使用docker …

MySQL6:索引使用原则,联合索引,联合主键/复合主键,覆盖索引、什么是回表?索引条件下推,索引的创建与使用,索引的创建与使用,索引失效

MySQL6&#xff1a;索引使用原则&#xff0c;联合索引&#xff0c;联合主键/复合主键&#xff0c;覆盖索引、什么是回表&#xff1f;索引条件下推&#xff0c;索引的创建与使用&#xff0c;索引的创建与使用&#xff0c;索引失效 索引使用原则列的离散(sdn)度 联合索引创建联合…

Harbor私有镜像仓库搭建

本文基于&#xff1a;https://zhuanlan.zhihu.com/p/143779176 1.环境准备 IP&#xff1a;192.168.10.136/24 操作系统:centos7 2.安装Docker、Docker-compose 2.1安装Docker-CE $ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.re…

数据库简史:多主数据库架构的由来和华为参天引擎的机遇

注&#xff1a;本文发表后&#xff0c;收到了很多后台反馈&#xff0c;其中关于大型机的早期成就不容省略。微调重发本文&#xff0c;纯属个人观点&#xff0c;错谬之处&#xff0c;仍然期待指正。 2023年10月13日&#xff0c;在北京举办的“2023金融业数据库技术大会"上&…

redis6.0源码分析:跳表skiplist

文章目录 前言什么是跳表跳表&#xff08;redis实现&#xff09;的空间复杂度相关定义 跳表&#xff08;redis实现&#xff09;相关操作创建跳表插入节点查找节点删除节点 前言 太长不看版 跳跃表是有序集合zset的底层实现之一&#xff0c; 除此之外它在 Redis 中没有其他应用。…

电力巡检/电力抢修行业解决方案:AI+视频技术助力解决巡检监管难题

一、行业背景 随着国民经济的蓬勃发展&#xff0c;工业用电和居民用电需求迅速增加&#xff0c;电厂、变电站、输电线路高负荷运转&#xff0c;一旦某个节点发生故障&#xff0c;对生产、生活造成巨大的影响。目前电力行业生产现场人员、设备较多&#xff0c;而生产监督员有限…

基于vue小红书平台用户数据分析与可视化

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

【马蹄集】—— 搜索专题

搜索专题 目录 MT2238 数的增殖MT2239 二维矩阵中的最长下降序列MT2240 传染病MT2241 循环空间BD202303 第五维度 MT2238 数的增殖 难度&#xff1a;黄金    时间限制&#xff1a;1秒    占用内存&#xff1a;128M 题目描述 给定一个数 n ( n < 1000 ) n (n<1000) n…

Java I/O (输入/输出)

1.流的概念 流是一种有序的数据序列&#xff0c;根据操作类型&#xff0c;可以分为输入流和输出流两种。I/O流&#xff08;输入输出&#xff09;提供了一条通道程序&#xff0c;可以使用这条通道把源中的字节序列送到目的地。 1.1 输入流&#xff1a; 程序从指向源的输入流中读…

51单片机汽车胎压大气气压测量仪仿真设计_数码管显示(代码+仿真+设计报告+讲解)

51单片机汽车胎压大气气压测量仪仿真设计_数码管显示 (代码仿真设计报告讲解) 仿真原版本&#xff1a;proteus 7.8 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0018 目录 51单片机汽车胎压大气气压测量仪仿真设计_数码管显示功…

技术分享| anyRTC低延时直播优化

直播系统就是把活动现场的音频或视频信号经数字压缩后&#xff0c;传送到直播多媒体服务器(CDN)上&#xff0c;在互联网上供广大网友或授权特定人群收听或收看。而随着技术的日益更新&#xff0c;人民对于直播的互动性&#xff0c;实时性要求更高了&#xff0c;传统的直播少则几…

React-表单受控绑定和获取Dom元素

一、表单受控组件 1.声明一个react状态 说明&#xff1a;useState const [value,setValue]useState("") 2.核心绑定流程 2.1绑定react状态 <div><input value{value}type"text"></input> 2.2绑定onChange事件 说明&#xff1a;e.…

队列(Queue)概念+通过单、双链表来模拟队列+环形队列+OJ面试题(用队列实现栈、用栈实现队列、设计环形队列)

文章目录 队列(Queue)一、 概念1.尾进头出 二、模拟队列1.单链表实现队列1.1 设置结点1.2 入队offer1.3出队 poll1.4 empty方法&#xff0c;peek方法&#xff0c;getUsedSize方法 2.双链表实现队列2.1 创建结点2.2 入队列2.3 出队列2.4 peek、size、isEmpty方法 三、环形队列1.…

vivo自研AI大模型即将问世,智能手机行业加速迈向AI时代

当前&#xff0c;以大模型为代表的人工智能技术已发展为新一轮科技革命和产业变革的重要驱动力量&#xff0c;被视作推动经济社会发展的关键增长极。 AI大模型潮起&#xff0c;千行百业走向百舸争流的AI创新应用期&#xff0c;前沿信息技术向手机、PC、车机等消费级终端加速渗…

AJAX原理及介绍

文章目录 AJAX&#xff08;Asynchronous Javascript And Xml&#xff09;传统请求及缺点AJAX概述XMLHttpRequest对象AJAX GET请求AJAX GET请求的缓存问题AJAX POST请求基于JSON的数据交换基于XML的数据交换AJAX乱码问题AJAX的异步与同步AJAX代码封装AJAX实现省市联动AJAX跨域问…

[Unity][VR]透视开发系列3-Passthrough应用的真机测试方法

【视频讲解】 视频讲解地址请关注我的B站。 专栏后期会有一些不公开的高阶实战内容或是更细节的指导内容。 B站地址: https://www.bilibili.com/video/BV1Zg4y1w7fZ/ 我还有一些免费和收费课程在网易云课堂(大徐VR课堂): https://study.163.com/provider/480000002282025/…

nodejs+vue食力派网上订餐系统-计算机毕业设计

采用当前流行的B/S模式以及3层架构的设计思想通过 技术来开发此系统的目的是建立一个配合网络环境的食力派网上订餐系统&#xff0c;这样可以有效地解决食力派网上订餐管理信息混乱的局面。 本设计旨在提高顾客就餐效率、优化餐厅管理、提高订单准确性和客户的满意度。本系统采…