顺序表实战——基于顺序表的通讯录

news2025/2/24 0:39:28

        前言本篇文章主要是利用顺序表作为底层, 实现一个通讯录。偏向于应用, 对于已经学习过c++的友友们可能没有难度了已经。没有学习过c++的友友, 如果顺序表不会写, 或者说没有自己实现过, 请移步学习顺序表相关内容。 本节不会带领友友们再造一个轮子, 我们会直接使用现成的顺序表, 也就是我在这篇文章中实现的版本:顺序表知识点——顺序表的增删查改-CSDN博客

创建文件

        先建立好文件:

        我们要基于顺序表实现一个通讯录, 所以我们要拿出我们的顺序表, 也就是顺序表的.h和.c文件。

         其次我们要建立一个通讯录的.h文件和一个通讯录.c文件。 

        其中通讯录的.h文件用来定义联系人自定义类型的结构体, 以及声明函数接口,.c文件则用来实现函数的接口。

定义联系人结构体

        定义结构体, 我们要知道我们的联系人的成员变量应该有什么。 

        首先, 联系人一定要有姓名;其次, 联系人要有性别和电话。 而且, 我们可以加上一个地址,还有年龄。 那么基本的联系人的结构体里面的成员变量我们就考虑清楚了。 现在我们来进行定义结构体

#define NAME_MAX 20//最大的名字长度
#define GENDER_MAX 10//最大的性别长度
#define ADRESS_MAX 30//最大的地址长度
#define TEL_MAX 12//电话的长度是11, 最后一个留给字符零
///             .h                
//性别姓名, 年龄地址
typedef struct personInfo
{
	char name[NAME_MAX];
	char gender[GENDER_MAX];
	int age;
	char tel[TEL_MAX];
	char adress[ADRESS_MAX];
}PInfo;

//以上, 就是我们定义的结构体 

准备工作

         定义好我们的结构体之后, 我们就可以做一些准备工作:主要是将我们的顺序表中的存储的数据改为我们自定义的联系人类型。 这里面会有函数的改动, 因为如果改变存储类型, 有些函数接口的操作就不好操作了。 

        第一步:先将我们的存储类型改为联系人类型:

        打开我们的顺序表的头文件, 现在就可以发现, 我们之前实现的顺序表结构的优越性。 我们只要将红框框位置的int改为联系人类型, 那么这个顺序表存储的类型就改变了。 这样极大的降低了我们的维护成本。当然,改成联系人类型之前需要包含以下我们通讯录的头文件。

改完之后就是这样的:

         第二步:我们要在我们的通讯录的头文件里面先写好要实现的接口。主要就是增删查改。

在写接口时, 要注意, 我们进行通讯录的增删查改的时候, 都是我们自己从键盘向流中输入数据, 而不是从内存中读取数据。 所以像插入操作,我们就不需要给一个要插入的参数了。

#define NAME_MAX 20
#define GENDER_MAX 10
#define ADRESS_MAX 30
#define TEL_MAX 12
///             .h                
//性别姓名, 年龄地址
typedef struct personInfo
{
	char name[NAME_MAX];
	char gender[GENDER_MAX];
	int age;
	char tel[TEL_MAX];
	char adress[ADRESS_MAX];
}PInfo;


//结构体重定义加声明
typedef struct SeqList Contact;

//通讯录的初始化
void ContactInit(Contact* con);

//通讯录的销毁
void ContactDes(Contact* con);

//通讯录的增加
void ContactPush(Contact* con);

//通讯录的删除
void ContactErase(Contact* con);

//通讯录查找
void ContactFind(Contact* con);

//通讯录全展示
void ContactShow(Contact* con);

//通讯录修改联系人
void ContactModify(Contact* con);

这里要注意的是红框框这个重定义:

         这个重定义的本质是 声明 + 重定义。这样写算是略写, 原本的写法应该是这样的:

struct SeqList;//先声明顺序表。

typedef struct SeqList Contact;//再对顺序表进行重定义。

        注意, 为什么要声明顺序表?因为我们想要对顺序表进行重定义, 重定义成Contact, 也就是通讯录。 但是如果不包含顺序表的头文件, 或者声明以下顺序表, 编译器就不认识它。 那么这个时候能做的就是两种操作:一个是声明以下顺序表, 一个是包含以下顺序表的头文件。

        但是我们往上看, 我们在上面已经在顺序表的头文件里包含了通讯录的头文件, 现在如果又将顺序表的头文件包含在通讯录中就会有一个重复包含的问题。 所以, 包含是行不通的,这里只能进行声明。 

        然后就是检查函数接口:检查顺序表的函数接口。 要知道, 我们之前的顺序表的函数接口都是按照存储的值是整形的方式来的。 那肯定是不行的。 不过检查函数接口不需要我们自己检查, 可以让编译器帮我们检查。

        编译一下, 看看哪个接口报错, 直接把哪个接口注释掉就好了

经过编译器检查, 这里只有一个查找的函数接口报错了, 问题原因是我们自定义的类型无法进行 == 运算符的操作。 (这里很明显了, 在c语言中, 自定义类型一般是无法使用操作符的。但是c++可以, c++中有运算符重载, 可以令自定义类型使用操作符。)

        把这一个接口注释掉。

        然后就不报错了。 

        最后一个操作就是我们的大框架, 大框架还是我们那几个老几样: 菜单 + 输入 + 开关 + 循环。 如图:


#include"SeqList.h"
#include"Contact.h"

void menu() 
{
	printf("*************************************************\n");
	printf("*********           1、Add                *******\n");
	printf("*********           2、erase              *******\n");
	printf("*********           3、modify             *******\n");
	printf("*********           4、Show               *******\n");
	printf("*********           5、Find               *******\n");
	printf("*********           0、exit               *******\n");
	printf("*************************************************\n");
}

int main() 
{
	int input = 0;
	Contact con;


	do 
	{
		menu();
		
		printf("请输入你的选择\n");
		scanf("%d", &input);
		switch (input) 
		{
		case 1 :

			break;
		case 2:

			break;
		case 3:

			break;
		case 4:

			break;
		case 5:

			break;
		case 0:
			printf("已退出");

			break;
		default:
			printf("输入非法");
			break;
		}

	} while (input);

	return 0;
}

这些准备工作做好之后,就差函数接口的实现了。 其实框架已经做好了, 可以运行一下看一下效果: 

接口实现 

初始化

         最重要的就是通讯录的初始化。 

        通讯录的初始化, 其实就是顺序表的初始化。 因为我们的通讯录就是顺序表。 知识名字被typedef了一下。

        所以, 通讯录的初始化, 我们直接调用顺序表的初始化就可以,它其实就是套了一层壳。 

//通讯录的初始化
void ContactInit(Contact* con) 
{
	SeqListInit(con);
}

 销毁

        同理, 通讯录的销毁也就是顺序表的销毁。 直接套一层壳:


//通讯录的销毁
void ContactDes(Contact* con) 
{
	SeqListDestory(con);
}

插入数据 

        插入数据其实本质上也是顺序表的插入。 但是我们不能直接使用顺序表的插入套壳了。 因为我们的通讯录需要自己输入数据。 而不是从内存中读数据。

        他们两个的接口就差一个参数

//通讯录的增加
void ContactPush(Contact* con);
//顺序表尾插函数接口
void SeqListPushback(SQL* ps, SQDataType x);

所以, 这里我们需要先实例化一个联系人对象。 再给这个对象赋值。 然后将这个对象传给顺序表的尾插接口:


//通讯录的增加
void ContactPush(Contact* con) 
{
	PInfo Inpo;//实例化联系人对象

    //对这个对象进行赋值
	printf("请输入你要添加的联系人姓名:>");
	scanf("%s", Inpo.name);
	
	printf("请输入你要添加的联系人性别:>");
	scanf("%s", Inpo.gender);

	printf("请输入你要添加的联系人年龄:>");
	scanf("%d", &Inpo.age);

	printf("请输入你要添加的联系人电话:>");
	scanf("%s", Inpo.tel);

	printf("请输入你要添加的联系人地址:>");
	scanf("%s", Inpo.adress);

	//添加数据, 插入
	SeqListPushback(con, Inpo);
	
}

删除 

        删除数据的前提是我们要删除哪个数据。 这涉及到了查找。 比如要删除姓名叫”张三“的数据。 后者删除手机号是"…………"的数据。这里涉及到了查找。 所以我这里先创建一个查找接口。 这个查找是利用姓名查找。

        这个接口的key, 也就是姓名,可以从外面传进来。 也可以再内部处理。 这里我选择再外面传进来。

//查找返回下标
int BynameIndex(Contact* con, char* name) 
{
	for (int i = 0; i < con->size; i++) 
	{
		if (strcmp(name, con->data[i].name) == 0)
		{
			return i;
		}
	}
	return -1;
}

         然后进行删除就可以了, 同样, 既然知道了下标。删除也是调用顺序表的删除操作。 


//通讯录的删除
void ContactErase(Contact* con) 
{
	char name[NAME_MAX];
	printf("请输入你要删除联系人的姓名:>\n");
	scanf("%s", name);


	int find = BynameIndex(con, name);
	if (find >= 0) 
	{
		SeqListPop(con, find);
	}
	else 
	{
		printf("没有该联系人!\n");
		return;
	}
}

 查找

        查找在上面已经实现过了。 只需要将要查找的信息打印一下就好了


//查找通讯录的数据
void ContactFind(Contact* con)
{
	char name[NAME_MAX];
	printf("请输入你要查找联系人的姓名:>");
	scanf("%s", name);
	int find = BynameIndex(con, name);
	if (find >= 0) 
	{
		printf("%s\t%s\t%d\t%s\t%s\n",
				con->data[find].name,
				con->data[find].gender,
				con->data[find].age,
				con->data[find].tel,
				con->data[find].adress);
	}
	else 
	{
		printf("没有该联系人!\n");
		return;
	}
}

 修改

        同理, 查找。 先确认要修改的联系人姓名, 然后再进行修改。 这里也涉及到了查找的问题。


void ContactModify(Contact* con) 
{
	char name[NAME_MAX];
	printf("请输入你要查找联系人的姓名:>");
	scanf("%s", name);
	int find = BynameIndex(con, name);
	
	if (find >= 0) 
	{
		printf("请输入你要修改的联系人姓名:>");
		scanf("%s", con->data[find].name);

		printf("请输入你要修改的联系人性别:>");
		scanf("%s", con->data[find].gender);

		printf("请输入你要修改的联系人年龄:>");
		scanf("%d", &con->data[find].age);

		printf("请输入你要修改的联系人电话:>");
		scanf("%s", con->data[find].tel);

		printf("请输入你要修改的联系人地址:>");
		scanf("%s", con->data[find].adress);
	}
	else 
	{
		printf("无联系人\n");
		return;
	}

全部联系人展示 

        全部展示就是只需要将顺序表中的每个数据的每个成员依次打印, 一个循环即可:


//通讯录全展示
void ContactShow(Contact* con)
{
	for (int i = 0; i < con->size; i++) 
	{
		printf("%s\t%s\t%d\t%s\t%s\n",
			con->data[i].name,
			con->data[i].gender,
			con->data[i].age,
			con->data[i].tel,
			con->data[i].adress);
	}
}

以上, 就是顺序表实现通讯录的全部内容。 下面是我上传的本篇文章对应的源代码。想要的自行下载。 

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

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

相关文章

代码随想录算法训练营Day14|二叉树理论基础和递归遍历

代码随想录卡哥视频 理论基础 需要了解 二叉树的种类&#xff0c;存储方式&#xff0c;遍历方式 以及二叉树的定义 文章讲解&#xff1a;代码随想录 递归遍历 &#xff08;必须掌握&#xff09; 二叉树的三种递归遍历掌握其规律后&#xff0c;其实很简单 题目链接/文章讲解/…

vue快速入门(十四)reduce求和

注释很详细&#xff0c;直接上代码 上一篇 新增内容 非嵌套情况求和嵌套情况求和 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initia…

详解Spring event如何优雅实现系统业务解耦、实现原理及使用注意项

1.概述 在我们平时的项目业务系统开发过程中&#xff0c;一个需求功能的业务逻辑经常出现主线业务和副线业务之分。比如&#xff0c;在当下移动端电商app进行注册账号操作&#xff0c;注册成功之后会发送短信、邮箱、站内信等通知&#xff0c;发放红包活动抵用券&#xff0c;推…

注意力机制篇 | YOLOv8改进之清华开源ACmix:自注意力和CNN的融合 | 性能速度全面提升

前言:Hello大家好,我是小哥谈。混合模型ACmix将自注意力机制和卷积神经网络进行整合,使其同时具有自注意力机制和卷积神经网络的优点。这是清华大学、华为和北京人工智能研究院共同发布在2022年CVPR中的论文。ACmix结合了自注意力机制和卷积神经网络的优势,以提高模型的性能…

Java+BS +saas云HIS系统源码SpringBoot+itext + POI + ureport2数字化医院系统源码

JavaBS saas云HIS系统源码SpringBootitext POI ureport2数字化医院系统源码 医院云HIS系统是一种运用云计算、大数据、物联网等新兴信息技术的业务和技术平台。它按照现代医疗卫生管理要求&#xff0c;在特定区域内以数字化形式收集、存储、传递和处理医疗卫生行业的数据。通…

ios包上架系列 二、Xcode打应用市场ipa包

打包的时候一定要断开网络&#xff0c;上线包名只能在打包机配置 检查是否是正式环境&#xff0c;先在模拟器上运行 1、版本名称和本号号记得在这里更改&#xff0c;否则不生效 原因 &#xff1a;info.list <string>$(FLUTTER_BUILD_NAME)</string><key>CFB…

深入剖析UDP反射放大攻击原理及其有效防护策略

引言 随着互联网的飞速发展和业务复杂性的提升&#xff0c;网络安全问题日益凸显&#xff0c;其中分布式拒绝服务&#xff08;DDoS&#xff09;攻击成为危害最为严重的一类网络威胁之一。UDP反射放大攻击作为一种高效的DDoS手段&#xff0c;因其攻击成本低廉、威力巨大&#x…

【教学类-51-01】20240411动物皮毛图片的彩色打印PDF制作(一页两张图片,2个表格)

作品展示 背景需求&#xff1a; 为了便于快速做出A4两份图片的效果&#xff0c;设计以下代码&#xff0c;进行图片的PDF合成打印 代码参考&#xff1a; 【教学类-50-06】20240410“数一数”4类星号图片制作PDF学具-CSDN博客文章浏览阅读531次&#xff0c;点赞8次&#xff0c;收…

机器学习和深度学习--李宏毅(笔记与个人理解)Day11-12

Day11 when gradient is small…… 怎么知道是局部小 还是鞍点&#xff1f; using Math 这里巧妙的说明了hessan矩阵可以决定一个二次函数的凹凸性 也就是 θ \theta θ 是min 还是max&#xff0c;最后那个有些有些 哈 是一个saddle&#xff1b; 然后这里只要看hessan矩阵是不…

vue快速入门(十三)v-model的使用

注释很详细&#xff0c;直接上代码 上一篇 新增内容 数据双向绑定数据清空方法 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-…

免重装系统,直接把家庭版升级为专业版!

前言 前段时间有小伙伴找小白重装系统。一般在重装系统之前&#xff0c;我都会问对方&#xff1a;为什么要重装系统&#xff1f; 结果她和我说&#xff1a;家庭版不好用&#xff0c;想要重装成专业版。感觉专业版更好一些&#xff0c;听起来好像也更厉害一些。 嗯……这个理由…

科技论文和会议录制高质量Presentation Video视频方法

一、背景 机器人领域&#xff0c;许多高质量的期刊和会议&#xff08;如IEEE旗下的TRO&#xff0c;RAL&#xff0c;IROS&#xff0c;ICRA等&#xff09;在你的论文收录后&#xff0c;需要上传一个Presentation Video材料&#xff0c;且对设备兼容性和视频质量有较高要求&#…

4.11作业

服务器端 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> //服务器端类 #include<QMessageBox> //消息对话框 #include<QTcpSocket> //客户端类 #include<QList> //链表容器QT_BEGIN_NAMESPACE namespace Ui { cla…

训练营第二十天(二叉树 part06)

训练营第二十天&#xff08;二叉树 part06&#xff09; 654.最大二叉树 力扣题目地址(opens new window) 题目 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出…

蓝桥杯第十三届c++大学B组详解

目录 1.九进制转十进制 2.顺子日期 3.刷题统计 4.修剪灌木 5.x进制的减法 6.统计子矩阵 7.积木画 8.扫雷 9.李白打酒 10.砍竹子 1.九进制转换十进制 题目解析&#xff1a;就是将2022的每一位拿出来乘以9的n-1次方的和就是最终答案。次方是从0开始的到n-1. #include &…

OpenLayers6实战,OpenLayers实现鼠标拖拽方式绘制平行四边形

专栏目录: OpenLayers实战进阶专栏目录 前言 本章介绍如何使用OpenLayers在地图上使用实现鼠标拖拽方式绘制平行四边形。 二、依赖和使用 "ol": "^6.15.1"使用npm安装依赖npm install ol@6.15.1使用Yarn安装依赖yarn add olvue中如何使用: vue项目…

Unity单个物体绑定多个相机在轨道上移动,录制不同角度视频

环境搭建 下载Cinemachine插件安装 打开包管理器 下载cinemachine插件 创建轨道 使用dolly track 创建轨道 右侧可以删减关键点&#xff0c;注意调整y坐标 创建cart 把前面的轨道拖到path中&#xff0c;注意这里的speed要设定不为0才会动 设置VItual Camera 根据需…

win11 怎么去除桌面上的了解此图片

如上图,更新win11后换上了壁纸,却发现这么个鬼玩意儿,还没有删除选项 因为这个了解此图片,是win11个性化壁纸的功能 当你使用win11的壁纸选项是windows聚焦后,桌面就会出现这个 取消这个就行 选择纯色或者图片 就没有了,我干干净净的桌面

DAS-MIL

DAS-MIL论文笔记 题目&#xff1a;DAS-MIL: Distilling Across Scales for MIL Classification of Histological WSIs 摘要 近年来&#xff0c;采用多实例学习 &#xff08;MIL&#xff09; 对全玻片图像 &#xff08;WSI&#xff09; 进行分类的情况有所增加。事实上&#…

速锐得解码荣威新I5燃油版OBD数据助力驾校现代化数字教学

在当今这个信息化飞速发展的时代&#xff0c;技术的进步不仅改变了我们的生活方式&#xff0c;也深刻影响了各行各业的运作模式。驾驶教育行业亦是如此&#xff0c;其中&#xff0c;OBD&#xff08;On-Board Diagnostics&#xff0c;车载自动诊断系统&#xff09;数据的应用&am…