动态通讯录(并不难都能拿下)

news2024/11/15 13:59:30

请添加图片描述

文章目录

  • 🚀前言
  • 🚀通讯录
    • 实现动态通讯录的初期准备
    • 模块化框架搭建
  • 🚀实现接口函数

🚀前言

铁子们好啊!今天咱们来整一个有意思的玩意——通讯录,相信大家对通讯录并不陌生,那接下来就跟着阿辉把它拿捏了😉

🚀通讯录

实现动态通讯录的初期准备

铁子们都知道通讯录是用来存放联系人信息的,首先我们得定义一个结构体来描述联系人的各项特征,比如:姓名、年龄、性别、电话号、地址等。

#define NAME_MAX 20 //姓名
#define SEX_MAX 5 //性别
#define TELE_MAX 12 //电话
#define ADDR_MAX 30 //地址
//联系人信息
typedef struct people
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char numb[TELE_MAX];
	char addr[ADDR_MAX];
}peo;//重定义

对于通讯录这种数据我们可以通过下面这样的结构体来实现:

//通讯录
typedef struct contact
{
	peo* data;
	int size;//记录管理联系人个数
	int capacity;//记录通讯录容量
}contact;

实际上,上述通讯录的本质是一个顺序表,怎么理解呢?给铁子们上图👇
请添加图片描述
有了数组的首元素地址data、数组的元素个数size以及数组空间的大小capacity,我们可以轻易的管理数组中的元素以及数组的大小
对于通讯录我们要实现六大功能的接口函数:增加联系人信息、删除联系人信息、查找联系人信息、修改联系人信息、打印通讯录以及对通讯录信息排序。

不过为了实现用户和计算机的交互我们首先要实现一个菜单来供用户选择:

void menu()
{
	printf("------------------------------\n");
	printf("----     1.添加联系人     ----\n");
	printf("----     2.删除联系人     ----\n");
	printf("----     3.查找联系人     ----\n");
	printf("----     4.修改联系人     ----\n");
	printf("----     5.打印通讯录     ----\n");
	printf("----     6.排序通讯录     ----\n");
	printf("----     0.退出通讯录     ----\n");
	printf("------------------------------\n");
}

模块化框架搭建

有了以上的准备我们可以搭建出通讯录的框架,同样这里我们使用模块化的方式进行设计
通讯录分为test.c、contact.c两个源文件和contact.h一个头文件:

  • test.c:主函数接口引入

  • contact.c:函数功能的实现

  • contact.h:头文件引入、函数声明、结构体声明

contact.h头文件

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define NAME_MAX 20 //姓名
#define SEX_MAX 5 //性别
#define TELE_MAX 12 //电话
#define ADDR_MAX 30 //地址
//联系人信息
typedef struct people
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char numb[TELE_MAX];
	char addr[ADDR_MAX];
}peo;
//通讯录
typedef struct contact
{
	peo* data;
	int size;//管理联系人
	int capacity;//记录通讯录容量
}contact;

//接口函数实现通讯录各项功能
//增加联系人
void AddCon(contact* p);
//删除联系人
void DeteleCon(contact* p);
//查找联系人
void SearchCon(contact* p);
//修改联系人
void ModifyCon(contact* p);
//打印通讯录
void PrintCon(contact* p);
//释放通讯录内存
void DistroyCon(contact* p);
//给联系人排序
void SortCon(contact* p);

test.c源文件

#include"contact.h"
enum Op//使用枚举维护代码的可读性
{
	Exit,//0
	Add,//1
	Delete,//2
	Search,//3
	Modify,//4
	Print,//5
	sort,//6
};

void menu()//打印菜单
{
	printf("------------------------------\n");
	printf("----     1.添加联系人     ----\n");
	printf("----     2.删除联系人     ----\n");
	printf("----     3.查找联系人     ----\n");
	printf("----     4.修改联系人     ----\n");
	printf("----     5.打印通讯录     ----\n");
	printf("----     6.排序通讯录     ----\n");
	printf("----     0.退出通讯录     ----\n");
	printf("------------------------------\n");
}
	
int main()
{
	//声明通讯录变量con并初始化通讯录
	contact con = { NULL, 0, 0 };
	int input = 0;
	do {
		menu();
		printf("请选择要使用的功能:>");
		scanf("%d", &input);
		switch (input)
		{
		case Add:
			AddCon(&con);
				break;
		case Delete:
			DeteleCon(&con);
			break;
		case Search:
			SearchCon(&con);
			break;
		case Modify:
			ModifyCon(&con);
			break;
		case Print:
			PrintCon(&con);
			break;
		case sort:
			SortCon(&con);
			break;
		case Exit:
			DistroyCon(&con);//退出程序时释放内存
			break;
		default:
			printf("输入错误,请重新输入!\n");
		}
	} while (input);

	return 0;
}

🚀实现接口函数

有了上述的框架,我们只需要在contact.c源文件中实现各项功能的接口函数通讯录就完成了
添加联系人接口:

void AddCon(contact* p)
{
	if (p == NULL)//先判断传过来的指针是否为空
		return;//为空直接返回
	if (p->capacity == p->size)//判断容量与数组元素个数是否相等,相等说明数组该扩容了
	{
		//如果进来初始化数组还未分配空间,先让capacity+1
		if (p->capacity == 0)  p->capacity++;
		//然后使用realloc开辟空间,后续数组空间不够直接增加一倍原本空间,一举两得
		peo* pd = (peo*)realloc(p->data, sizeof(peo) * p->capacity);
		if (pd == NULL)//空间开辟失败直接返回
			return;
		p->data = pd;//把开辟空间的首地址赋给data
		p->capacity *= 2;//开辟完空间capacity倍增
	}
	printf("请输入姓名:>");
	scanf("%s", p->data[p->size].name);
	printf("请输入年龄:>");
	scanf("%d", &(p->data[p->size].age));
	printf("请输入姓别:>");
	scanf("%s", p->data[p->size].sex);
	printf("请输入电话:>");
	scanf("%s", p->data[p->size].numb);
	printf("请输入地址:>");
	scanf("%s", p->data[p->size].addr);
	printf("添加成功!\n");
	p->size++;//联系人添加成功size自增
}

删除指定联系人接口:
先遍历数组找到要删除的元素,后续我们的查找修改联系人都需要遍历数组进行查找,这里我们封装好一个函数check通过对比名字来实现
查找函数:

//这个函数我们使用static修饰,使其只能在源文件contact.c中使用
static int check(contact* p,char a[])
{
	int i = 0;
	for (i = 0; i < p->size; i++)
	{
		if (strcmp(a, p->data[i].name) == 0)
			break;//找到后跳出循环
	}
	if (i >= p->size)//i如果超出size说明数组中没有改联系人
		return -1;//返回-1
	return i;//找到则返回该联系人下标
}

删除指定联系人接口:
如何实现,铁子们看图
请添加图片描述

void DeteleCon(contact* p)
{
	if (p == NULL)//判断穿入指针是否为空
		return;
	if (p->size == 0)//看数组中是否有元素
	{
		printf("空的我删个锤子啊!\n");
		return;
	}
	char str[20] = {0};//输入要删除的联系人的姓名
	printf("请输入要删除联系人的名字:>");
	scanf("%s", str);
	int ret = check(p, str);//查找要删除联系人的下标
	if (ret == -1)
	{
		printf("查无此人!\n");
		return;
	}
	//上述图片的功能,至删除元素起后一个元素覆盖前一个元素
	for (int i = ret; i < p->size - 1; i++)
	{
		p->data[i] = p->data[i + 1];
	}
	printf("已成功删除!\n");
	p->size--;//size自减
}

查找指定联系人接口:
这个很简单

void SearchCon(contact* p)
{
	if (p == NULL)
		return;
	if (p->size == 0)
	{
		printf("空的我查个锤子!\n");
		return;
	}
	char str[20] = { 0 };
	printf("请输入要查找的联系人的名字:>");
	scanf("%s", str);
	int ret = check(p, str);//查找要找的联系人的下标
	if (ret == -1)
	{
		printf("查无此人!\n");
		return;
	}
	//打印要找的联系人的信息
	printf("%-15s	%-5d	%-8s	%-12s	%-20s\n",
		p->data[ret].name,
		p->data[ret].age,
		p->data[ret].sex,
		p->data[ret].numb,
		p->data[ret].addr);
}

修改指定联系人接口:
这个也很简单,找到后修改

void ModifyCon(contact* p)
{
	if (p == NULL)
		return;
	if(p->size == 0)
	{
		printf("空的我改个锤子!\n");
		return;
	}
	char str[20] = { 0 };
	printf("请输入要修改的联系人的名字:>");
	scanf("%s", str);
	int ret = check(p, str);//查找要找的联系人的下标
	if (ret == -1)
	{
		printf("查无此人!\n");
		return;
	}
	//修改联系人内容
	printf("请输入姓名:>");
	scanf("%s", p->data[ret].name);
	printf("请输入年龄:>");
	scanf("%d", &(p->data[ret].age));
	printf("请输入姓别:>");
	scanf("%s", p->data[ret].sex);
	printf("请输入电话:>");
	scanf("%s", p->data[ret].numb);
	printf("请输入地址:>");
	scanf("%s", p->data[ret].addr);
	printf("修改成功!\n");
}

打印联系人接口:
打印就更简单了

void PrintCon(contact* p)
{
	if (p == NULL)
		return;
	//下面这一行是为了便于观察
	printf("%-15s	%-5s	%-8s	%-12s	%-20s\n", "名字", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < p->size; i++)//遍历数组打印
	{
		printf("%-15s	%-5d	%-8s	%-12s	%-20s\n",
			p->data[i].name,
			p->data[i].age,
			p->data[i].sex,
			p->data[i].numb,
			p->data[i].addr);
	}
}

排序联系人接口:

//比较器,利用名字字典序排列
int cmp(const void* p1,const void* p2)
{
	return strcmp(((peo*)p1)->name, ((peo*)p2)->name);
}
void SortCon(contact* p)
{
	if (p == NULL)
		return;
	if (p->size < 2)//元素小于两个不需要排序
		return;
	//利用库函数qsort排序,得自己定义比较器
	qsort(p->data, p->size, sizeof(p->data[0]), cmp);
	printf("排序完成!\n");
}

释放通讯录空间接口:

void DistroyCon(contact* p)
{
	free(p->data);//释放动态内存
	p->data = NULL;//指针置空
	//下面变量置0
	p->size = 0;
	p->capacity = 0;
	printf("内存释放!\n");
}

到这里动态通讯录也是实现完成了,并不是很难相信大家都能轻易拿下,希望这篇博客能让大家有所收获, 如果觉得阿辉写得不错的话,记得给个赞呗,你们的支持是我创作的最大动力🌹

请添加图片描述

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

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

相关文章

Linux--LAMP 平台部署及应用

5.1 LAMP平台概述 LAMP架构是目前成熟的企业网站应用模式之一&#xff0c;指的是协同工作的一整套系统和相关软件&#xff0c;能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词&#xff0c;具体包括Linux操作系统&#xff0c;Apache 网站服务器、MySQL数据库服务器&…

互联网加竞赛 python+opencv+机器学习车牌识别

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于机器学习的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;3分 该项目较为新颖&#xff0c;适…

EnlightenGAN论文阅读笔记

EnlightenGAN论文阅读笔记 论文是2019年IEEE的EnlightenGAN: Deep Light Enhancement without Paired Supervision.这篇论文是低光增强领域无监督学习的开山之作。 论文链接如下&#xff1a;arxiv.org/pdf/1906.06972.pdf 文章目录 EnlightenGAN论文阅读笔记出发点**出发点1**&…

linux应用程序直接return与exit的区别

在Linux应用程序中&#xff0c;可以使用return语句直接从main函数返回。这将导致程序终止并返回给操作系统。然而&#xff0c;有时候使用exit函数比直接使用return语句更有优势&#xff0c;以下是一些原因&#xff1a; 清理资源&#xff1a;exit函数可以确保在程序终止之前执行…

Aurora8B10B(二) 从手册和仿真学习Aurora8B10B

一. 简介 在上篇文章中&#xff0c;主要结合IP配置界面介绍了一下Aurora8B10B&#xff0c;这篇文章将结合文档来学习一下Aurora8B10B内部的一些细节 和 相关的时序吧。文档主要是参考的是这个 pg046-aurora-8b10b-en-us-11.1 二. Aurora8B10B内部细节 在手册上&#xff0c;对…

pytorch中数据预处理模块:transforms详解

1 tranforms概述 1.1 torchvision介绍 torchvision是pytorch的计算机视觉工具包&#xff0c;主要有以下三个模块&#xff1a; torchvision.transforms&#xff1a;提供了常用的一系列图像预处理方法&#xff0c;例如数据的标准化&#xff0c;中心化&#xff0c;旋转&#xff…

设计模式——外观模式(结构型)

引言 外观模式是一种结构型设计模式&#xff0c; 能为程序库、 框架或其他复杂类提供一个简单的接口。 ​ 问题 假设你必须在代码中使用某个复杂的库或框架中的众多对象。 正常情况下&#xff0c; 你需要负责所有对象的初始化工作、 管理其依赖关系并按正确的顺序执行方法等。…

记录 | 不限速下载vscode

在下载 vscode 的时候往往会遇到一个问题就是下载的贼慢 下面教不限速下载的方式 将下面红框内的内容进行替换 替换为&#xff1a; vscode.cdn.azure.cn然后你会发现下载速度就起飞了

开辟“护眼绿洲”,荣耀何以为师?

文 | 智能相对论 作者 | 佘凯文 俗话说&#xff0c;眼睛是心灵的窗户&#xff0c;可如今&#xff0c;人们对于这扇“窗户”的保护&#xff0c;似乎越来越不重视。 据人民日报今年发布的调查显示&#xff0c;中国眼病患病人数2.1亿&#xff0c;近视患者人数多达6亿&#xff0…

智能优化算法应用:基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.头脑风暴算法4.实验参数设定5.算法结果6.…

救命~这件国风旗袍女儿穿也太好看了吧

这款中式提花改良版旗袍 一眼就戳中了我的心巴 整件精美刺绣好看不大众 两侧网纱的加持增添仙气缥缈感 穿上厚实不显臃肿 袖口处拼接毛毛徒增可爱俏皮的感觉 穿上过年过节满满的焦点呀~

C语言学习----字符串数组和字符串指针

&#x1f308;在C Primer Plus 第六版中第11章的字符串和字符串函数讲的很好~ 对于字符串和字符串指针的用法又更深入了解了一些~ &#x1f42c; 本blog为 C Primer Plus 的记录~ ☘️对于字符串指针和数组更加深入了解~ &#x1f33a;省流&#xff1a;1️⃣字符串常量被储存在…

【第1期】SpringSecurity基于角色和权限的细粒度接口权限控制

SpringSecurity 细粒度权限控制 一、Role 和 Authority的区别 角色用来表示某一类权限的集合&#xff0c;权限粒度更小&#xff0c;方便细粒度控制 二、创建用户、角色、权限相关表&#xff1a; CREATE TABLE common_user (id bigint(20) NOT NULL COMMENT 主键id,login_na…

1.electron之纯原生js/jquery的桌面应用程序(基础篇)

如果可以实现记得点赞分享&#xff0c;谢谢老铁&#xff5e; Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 Electron 将 Chromium 和 Node.js 嵌入到了一个二进制文件中&#xff0c;因此它允许你仅需一个代码仓库&#xff0c;就可以撰写支持 Windows、…

linux离线安装libreoffice

安装步骤 1.安装JAVA环境jdk 2.下载离线安装包libreoffice 3.安装libreoffice 4.配置字体防止乱码 1.安装JAVA环境JDK 这个网上自己搜下&#xff0c;资料漫天飞 2.下载libreoffice离线安装包 下载地址 Download LibreOffice | LibreOffice - Free Office Suite - B…

Redis第1讲——入门简介

Java并发编程的总结和学习算是告一段落了&#xff0c;这段时间思来想去&#xff0c;还是决定把Redis再巩固和学习一下。毕竟Redis不论是在面试还是实际应用中都是极其重要的&#xff0c;在面试中诸如Redis的缓存问题、热key、大key、过期策略、持久化机制等&#xff1b;还有在实…

Windows11安装python模块transformers报错Long Path处理

Windows11安装python模块transformers报错&#xff0c;报错信息如下 ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory: C:\\Users\\27467\\AppData\\Local\\Packages\\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\\Local…

CSS文本样式(详解)

CSS文本样式 &#x1f367; 文本颜色&#x1f9c1;文本缩进&#x1f368;文本对齐&#x1f365;文本行高&#x1f95d;文本装饰 &#x1f367; 文本颜色 属性&#xff1a;color 作用&#xff1a;设置文本颜色 属性值&#xff1a; 颜色表示方式表示含义属性值颜色名称预定义的…

matplotlib如何在label中加入字符并换行【已解决】

最近在跑一个超参数的实验&#xff0c;但是发现x轴的刻度就很丑 显然&#xff0c;lr和theta在一行显得很冗余 这个是此时的label x_labels [$\t{lr0.05}\ \tθ10}$, 40, 60] 正常加换行符即可&#xff0c;但是要加上$$ x_labels [$\t{lr0.05}\ $\n$ \tθ10}$, 40, 60] 大…