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

news2024/11/25 13:46:38

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


目录

  • 一. 前言
  • 二. 动态通讯录
    • 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;//3
	pc->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 2

typedef 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.coloradmin.cn/o/1147243.html

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

相关文章

【需要理解】80 单词搜索

单词搜索 题解1 回溯&#xff08;需要改变起点&#xff09; 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内…

数据结构——线性表①(顺序表)

一、线性表定义 线性表是一种数据结构&#xff0c;它是由n个具有相同数据类型的数据元素a1,a2,…,an组成的有限序列。 其中&#xff0c;除第一个元素a1外&#xff0c;每一个元素有且只有一个直接前驱元素&#xff0c;除了最后一个元素an外&#xff0c;每一个元素有且只有一个…

IDEA 如何运行 SpringBoot 项目

步骤一&#xff1a;配置 Maven 第一步&#xff1a;用 IDEA 打开项目&#xff0c;准备配置 maven 环境 &#xff0c;当然如果本地没有提前配置好 maven&#xff0c;就用 IDEA 默认的配置即可 配置 maven 步骤 情况 1&#xff1a;如果本地没有配置过 maven&#xff0c;可以保持如…

【Spring】IOC容器与Bean的常用属性配置

文章目录 1.前言2.IOC容器2.1 BeanFactory 容器2.2 ApplicationContext 容器 3.Bean的常用属性配置4. 总结 1.前言 在之前的文章-IOC的快速入门中讲过Bean这个概念. 本来就来介绍容器与Bean的常用属性配置 在Spring框架中&#xff0c;Bean指的是被Spring加载生成出来的对象。 …

ubuntu 18.04 编译安装flexpart 10.4(2023年) —— 筑梦之路

2023年10月29日 环境说明 操作系统版本&#xff1a;ubuntu 18.04 python版本&#xff1a;3.6.9 gcc版本&#xff1a;7.5.0 编译安装路径&#xff1a;/usr/local cmake: 3.10.2 所需要的源码包我已经打包放到我的资源。 2021年1月份已经写过一篇Ubuntu 编译安装的帖子F…

Android OpenGL ES 2.0入门实践

本文既然是入门实践&#xff0c;就先从简单的2D图形开始&#xff0c;首先&#xff0c;参考两篇官方文档搭建个框架&#xff0c;便于写OpenGL ES相关的代码&#xff1a;构建 OpenGL ES 环境、OpenGL ES 2.0 及更高版本中的投影和相机视图。 先上代码&#xff0c;代码效果如下图…

MQ——进阶

文章目录 消息可靠性生产者消息确认消息持久化消费者确认演示none模式演示auto模式 失败重试机制本地重试失败策略 死信交换机初始死信交换机TTL延迟队列安装DelayExchange插件使用DelayExchange 惰性队列消息堆积问题惰性队列 MQ集群集群分类普通集群镜像模式镜像模式的配置 仲…

私有云:【6】VCenter安装SqlServer

私有云&#xff1a;【6】VCenter安装SqlServer 1、VCenter安装SqlServer1.1、通过模板创建虚拟机1.2、安装sqlserver服务 2、搭建sqlserver群集2.1、安装群集功能2.2、在ad域服务器创建共享文件夹&#xff0c;供集群选举使用 3、创建故障转移群集【只需安装一台即可】3.1、创建…

操作系统 --- 存储器管理

一、简答题 1.存储器管理的基本任务&#xff0c;是为多道程序的并发执行提供良好的存储器环境。请问好的存储器环境”应包含哪几个方面&#xff1f; 答&#xff1a; 2.内存保护是否可以完全由软件实现&#xff1f;为什么&#xff1f; 答&#xff1a;内存保护的主要任务是确保每…

LeetCode热题100——双指针

双指针 1.移动零2.盛最多水的容器3.三数之和 1.移动零 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 // 题解&#xff1a;使用双指针&#xff0c;其中快指针指向非零元素&#xff0c;慢指针指向首个零元素下…

msvcp120.dll怎么修复,五种方法教你如何修复msvcp120.dll文件

在运行软件时&#xff0c;我们常常会遇到一些错误提示&#xff0c;其中之一就是“由于找不到msvcp120.dll无法继续执行代码”。这个错误通常发生在使用Microsoft Visual C 2013编译的程序运行时。本文将介绍5种修复这个问题的方法&#xff0c;帮助各位解决这个困扰。 方法一、使…

如何使用批量重命名的方法替换重复文件名内容

在文件管理过程中&#xff0c;我们有时会遇到文件名中包含相同部分内容的情况&#xff0c;这不仅会使文件显得混乱&#xff0c;而且还会给文件检索和使用带来不便。为了解决这个问题&#xff0c;我们可以使用云炫文件管理器批量重命名进行批量替换。下面是如何使用这种方法进行…

RT-Thread入门

1、初识RT-Thread RT-Thread&#xff0c;全称是Real Time-Thread&#xff0c;即嵌入式实时多线程操作系统。其基本属性之一是支持多任务&#xff0c;但是允许多任务同时运行&#xff0c;但是并不是意味着处理器在同一时刻真的执行了多个任务。实际上&#xff0c;一个处理器核心…

mac 安装homebrew ,golang

mac 安装homebrew ,golang 安装homebrew安装golang选择 apple arm 版本安装配置环境变量 安装homebrew /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"回车执行指令后&#xff0c;根据提示操作。具体包括以下提示操作&am…

深度学习(4)---生成式对抗网络(GAN)

文章目录 一、原理讲述1.1 概念讲解1.2 生成模型和判别模型 二、训练过程2.1 训练原理2.2 损失函数 三、应用 一、原理讲述 1.1 概念讲解 1. 生成式对抗网络&#xff08;Generative Adversarial Network&#xff0c;GAN&#xff09;是一种深度学习模型&#xff0c;是近年来复杂…

vue vant van-uploader使用compressorjs解决拍照上传的图片被旋转 90 度方法,图片压缩上传

vue vant van-uploader使用compressorjs解决拍照上传的图片被旋转 90 度方法&#xff0c;图片压缩上传_van-uploader 拍照上传服务器后图片翻转-CSDN博客文章浏览阅读3.2k次&#xff0c;点赞4次&#xff0c;收藏6次。van-uploader使用compressorjs解决拍照上传的图片被旋转 90 …

游戏找不到x3daudio1_7.dll无法继续执行的解决方法,快速解决dll问题

x3daudio1_7.dll是一个音频处理库&#xff0c;主要用于实现三维音频渲染。它包含了微软的XAudio2音频API&#xff0c;该API被许多游戏和应用程序用于实现高质量的音频效果。这个库文件主要处理音频的空间定位、响度均衡以及多通道音频输出等功能。在游戏中&#xff0c;它可以为…

08 MIT线性代数-求解Ax=b:可解性与结构Complete Solution of Ax=b

1. 可解的条件 Solvability conditions on b 检验Axb是否可解的方法是对增广矩阵进行行消元。如果矩阵A的行被完全消去的话&#xff0c;则对应的b的分量也要得0 两条关于b的限制条件(等价) 1. if a comb. of rows of A gives zero row, then same comb. of enties of b must …

笔记46:ResNeXt 网络详解

本地笔记地址&#xff1a;D:\work_file\DeepLearning_Learning\03_个人笔记\2.图像处理任务\ResNeXt网络学习 a a a a a a a a a a a a a a

【论文阅读VLDB23】Online Schema Evolution is (Almost) Free for Snapshot Databases

Online Schema Evolution is (Almost) Free for Snapshot Databases 对snapshot DB来说可以几乎在线进行schema的演变。 ABSTRACT 在现有数据库系统中&#xff0c;对在线和事务模式演变的支持仍然具有挑战性。之前处理这种schema 演变基本是patches补丁的方式来做&#xff0…