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

news2024/11/26 20:28:26

        前言本篇文章主要是利用顺序表作为底层, 实现一个通讯录。偏向于应用, 对于已经学习过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/1577537.html

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

相关文章

PMP证书究竟值不值得考?含金量如何?

PMP证书在项目管理领域还是很受关注&#xff0c;但其含金量和是否必须考取一直存在争议。在这里&#xff0c;我们来深入分析&#xff0c;看看PMP证书到底值不值得考&#xff0c;以及背后的原因。 首先&#xff0c;我们要关注的是PMP考试的通过率。根据网络和培训机构的数据&am…

基于Springboot框架四川成都某大学教室自习室预约系统设计与实现 研究背景和意义、国内外现状

二、国内外现状 在国内外&#xff0c;教室和自习室预约系统作为高校信息化建设的重要组成部分&#xff0c;已经得到了广泛的关注和应用。不同国家和地区的高校在预约系统的建设和应用方面呈现出不同的特点和趋势。 在国内方面&#xff0c;随着高校信息化建设的不断深入&#…

【CKA模拟题】边车容器Shared-Volume的具体用法

Useful Resources: Persistent Volumes Claim , Pod to Use a PV 题干 For this question, please set this context (In exam, diff cluster name) kubectl config use-context kubernetes-adminkubernetes An existing nginx pod, my-pod-cka and Persistent Volume Claim…

移动机器人运动规划 | 基于图搜索的Dijkstra 和 A*算法详解

Dijkstra 算法 Dijkstra 算法与BFS算法的区别就是 : 从容器中弹出接下来要访问的节点的规则不同 BFS 弹出: 层级最浅的原则&#xff0c;队列里最下方的元素 Dijkstra 弹出: 代价最小的节点g(n) g(n) :表示的是从开始节点到当前n节点的代价累加 Dijkstra在扩展的时候&#x…

【PyTorch][chapter 25][李宏毅深度学习][Transfer Learning-1]

前言&#xff1a; 迁移学习是一种机器学习的方法,指的是一个预训练的模型被重新用在另一个任务中。 比如已经有个模型A 实现了猫狗分类 模型B 要实现大象和老虎分类,可以利用训练好的模型A 的一些参数特征,简化当前的训练 过程. 目录&#xff1a; 简介 Model Fine-Tuning (…

【React】Ant Design社区扩展库之分割面板:react-resizable-panels

主角&#xff1a;react-resizable-panels 简介&#xff1a;来之Ant Design官方文档社区精选组件 1、效果 2、环境 react-resizable-panels: ^2.0.16next: 14.1.3react: ^18 3、安装 # npm npm install react-resizable-panels# yarn yarn add react-resizable-panels# pnpm …

【Web】纯萌新的CISCN刷题记录(1)

目录 [CISCN 2019华东南]Web11 [CISCN 2019华北Day2]Web1 [CISCN 2019初赛]Love Math [CISCN 2022 初赛]ezpop [CISCN 2019华东南]Double Secret [CISCN 2023 华北]ez_date [CISCN 2019华北Day1]Web1 [CISCN 2019华东南]Web4 [CISCN 2019华北Day1]Web2 [CISCN 2023 …

知识融合与消歧:完善知识图谱的关键步骤

知识融合与消歧&#xff1a;完善知识图谱的关键步骤 一、引言&#xff1a;知识融合与消歧的重要性 在今天的数据驱动时代&#xff0c;知识图谱已成为组织和理解海量信息的关键技术。它们使得复杂的数据关系可视化&#xff0c;为人工智能提供了丰富的知识基础。然而&#xff0c…

成都源聚达:抖音开店新手做什么靠谱

在数字化浪潮下&#xff0c;抖音成为创业者的新阵地。新手若想在这片热闹非凡的土地上开垦出自己的一片天地&#xff0c;首要策略是选择靠谱的商品或服务。靠谱的定义在于市场需求的稳定性与产品的可持续性&#xff0c;以及是否具备一定的创新性和差异化特征。 以李华为例&…

一种保护隐私的混合联邦学习方法-文章翻译

一种保护隐私的混合联邦学习方法 摘要 联邦学习促进了模型的协作培训,而无需共享原始数据。然而,最近的攻击表明,仅仅在培训过程中维护数据位置并不能提供足够的隐私保证。相反,我们需要一个联邦学习系统,该系统能够防止对训练期间交换的消息和最终训练的模型进行推理,…

货物摆放-C++题解

计算本题前先了解一下约数 约数&#xff0c;又称因数。整数a除以整数b(b≠0) 除得的商正好是整数而没有余数&#xff0c;我们就说a能被b整除&#xff0c;或b能整除a。a称为b的倍数&#xff0c;b称为a的约数 然后首先要求出n的所有因数&#xff0c;因为题目需要满足的条件是nLWH…

柯桥外语培训之【韩语干货】如何用韩语作简单自我介绍

안녕하세요! 意思是“您好”“你好”&#xff0c;这是最常用的问候语&#xff0c;正式场合可以使用“안녕하십니까?" 제 이름은 [你的名字]이고, [你的年龄] 살입니다. 意思是“我的名字是~&#xff0c;~岁了”&#xff0c;这是比较谦虚的自我介绍方式 介绍自己的名字…

Python第四次作业

周六&#xff1a; 1. 找出10000以内能被5或6整除&#xff0c;但不能被两者同时整除的数&#xff08;函数&#xff09; def find_number():for number in range(0,10000):if number % 5 0 or number % 6 0:if number % 5 ! number % 6:ls.append(number)print(ls)ls [] fin…

CSS 基础:设置背景的 5 个属性及简写 background 注意点

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web 开发工具合集 263篇…

谷歌浏览器用不了怎么办?

打开谷歌浏览器点击右上角的三个点 &#xff0c; 点击设置 在搜索引擎里面把这个改成百度 然后越狱登录你的谷歌账号就可以用了 我个人用的越狱软件是r2rayn &#xff0c; 浏览器上面可以搜索的 默认浏览器那里可以设置成谷歌

Vue - 你知道Vue2中对象动态新增属性,视图无法更新的原因吗

难度级别:中高级及以上 提问概率:55% 这道题面试官会这样描述,比如有这样一个场景,一个对象里有name属性,可以正常显示在页面中。但后续动态添加了一个age属性,通过调试打印发现对象里的age属性已经添加了上了,但试图中却没有展示出来,…

有了这款开源的电子签就再也不用重复造轮子了!

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一份大厂面试资料《史上最全大厂面试题》&#xff0c;Springboot、微服务、算法、数据结构、Zookeeper、Mybatis、Dubbo、linux、Kafka、Elasticsearch、数据库等等 …

LeetCode刷题之105. 从前序与中序遍历序列构造二叉树

文章目录 1.题目描述2. 分析2.1 前序遍历2.1.1 什么是前序遍历&#xff1f;2.1.2 前序遍历有什么特点&#xff1f; 2.2 中序遍历2.2.1 什么是中序遍历2.2.2 中序遍历有什么特点&#xff1f; 2.3 后序遍历2.3.1 什么是后序遍历&#xff1f;2.3.2 特点 2.4 总结 3. 解法 1.题目描…

职场成功的关键因素:如何成为一位优秀的职场人

在竞争激烈的职场环境中&#xff0c;如何脱颖而出&#xff0c;成为一位优秀的职场人&#xff0c;成为了许多职场人士关注的焦点。本文将探讨职场成功的关键因素&#xff0c;帮助您在职场中取得更好的发展。 一、专业技能 专业技能是职场成功的基础。具备扎实的专业技能&#xf…

D-ID介绍以及订阅教程

D-ID 是一家提供人工智能仿真人视频产品服务和开发的公司。 用户只需上传人像照片&#xff0c;输入要说的内容&#xff08;台词&#xff09;&#xff0c;D-ID 就能利用AI 语音机器人自动将用户输入的文字转换成音频&#xff0c;用户甚至还能直接上传录音文件&#xff0c;快速获…