当前位置: 首页 > news >正文

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

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

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

相关文章:

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

前言&#xff1a;本篇文章主要是利用顺序表作为底层&#xff0c; 实现一个通讯录。偏向于应用&#xff0c; 对于已经学习过c的友友们可能没有难度了已经。没有学习过c的友友&#xff0c; 如果顺序表不会写&#xff0c; 或者说没有自己实现过&#xff0c; 请移步学习顺序表相关内…...

Java编程规范及最佳实践

文章目录 一、命名规范二、代码风格规范三、注释规范四、推荐的编程实践五、类和接口六、异常处理七、可见性八、并发九、代码复用十、代码组织和模块化十一、Java集合框架十二、输入验证十三、资源管理十四、文档和注释十五、测试和代码质量十六、代码可读性十七、性能优化十八…...

90天玩转Python—07—基础知识篇:Python中运算符详解

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…...

C语言 位域

C 语言的位域&#xff08;bit-field&#xff09;是一种特殊的结构体成员&#xff0c;允许我们按位对成员进行定义&#xff0c;指定其占用的位数。 如果程序的结构中包含多个开关的变量&#xff0c;即变量值为 TRUE/FALSE&#xff0c;如下&#xff1a; struct {unsigned int w…...

【LeetCode热题100】【技巧】颜色分类

题目链接&#xff1a;75. 颜色分类 - 力扣&#xff08;LeetCode&#xff09; 只需排序三种&#xff0c;可以记录0和1的个数&#xff0c;然后直接原地赋值 class Solution { public:void sortColors(vector<int> &nums) {int zero 0, one 0;for (auto &num: n…...

笔记本电脑win7 Wireless-AC 7265连不上wifi6

1.背景介绍 旧路由器连接人数有限&#xff0c;老旧&#xff0c;信号不稳定更换了新路由器&#xff0c;如 TL-XDR5430易展版用户电脑连不上新的WIFI网络了&#xff0c;比较着急 核心问题&#xff1a;有效解决笔记本连接wifi上网问题&#xff0c;方法不限 2.环境信息 Windows…...

Linux gcc day5粘滞位

粘滞位 背景&#xff1a;一定时在一个公共目录&#xff08;root创建&#xff09;下。进行临时文件的操作 Linux系统中有很多人&#xff0c;我们需要在一个公共目录下&#xff0c;进行临时文件的操作&#xff08;增删查改&#xff09; 创建一个根目录下的dir&#xff08;mytmp…...

单片机按键消抖常用的软硬件方法

一&#xff1a;什么是开关抖动&#xff1f; 当我们按下按钮或拨动开关或微动开关时&#xff0c;两个金属部件会接触以短路电源。但它们不会立即连接&#xff0c;而是金属部件在实际稳定连接之前连接和断开几次。释放按钮时也会发生同样的事情。这会导致误触发或多次触发&#…...

钉钉自建应用-下载excel(h5)

由于不同手机对于文件下载有不同的支持&#xff0c;而且文件路径也不一样&#xff0c;找起来十分的麻烦。所以&#xff0c;最好是找到一个都支持的方法。还好&#xff0c;钉钉官网提供了网盘&#xff0c;我们可把文件保存到钉钉自带的网盘&#xff0c;这样方便查找。 这里需要…...

用二八定律分析零售数据,不就更直观了吗?

20%的商品贡献了80%的销售金额&#xff0c;你会不会想知道这些商品的销售金额、毛利、销售金额累计占比、毛利累计占比&#xff0c;会不会想知道这些商品在各个门店的销售表现&#xff1f;看是否能进一步提高销售金额&#xff0c;提高毛利。这样的报表该怎么做&#xff1f;奥威…...

NetSuite Saved Search-当前库存快照查询报表(二)

之前第一篇文章我们说明了&#xff0c;如何利用Saved Search来制作一个能够显示批次物料与非批次物料的Lot信息以及On Hand在手数量的“当前库存快照查询报表”&#xff0c;但是当用户提出“我们能否再加上批次物料的效期”需求时&#xff0c;我们原有的Saved Search并不能达到…...

【JavaSE】接口 详解(上)

前言 本篇会讲到Java中接口内容&#xff0c;概念和注意点可能比较多&#xff0c;需要耐心多看几遍&#xff0c;我尽可能的使用经典的例子帮助大家理解~ 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 前言 接口 语法…...

嵌入式C基础——循环队列 ringbuffer 讲解

本期主题&#xff1a; 讲解ARRAY_SIZE的作用以及定义&#xff0c;还有一个踩坑分析 往期链接&#xff1a; 数据结构系列——先进先出队列queue数据结构系列——栈 stackLinux内核链表零长度数组的使用inline的作用嵌入式C基础——ARRAY_SIZE使用以及踩坑分析 目录 1. Ringbuff…...

【动态规划-状态压缩dp】【蓝桥杯备考训练】:毕业旅行问题、蒙德里安的梦想、最短Hamilton路径、国际象棋、小国王【已更新完成】

目录 1、毕业旅行问题&#xff08;今日头条2019笔试题&#xff09; 2、蒙德里安的梦想&#xff08;算法竞赛进阶指南&#xff09; 3、最短Hamilton路径&#xff08;《算法竞赛进阶指南》&模板&#xff09; 4、国际象棋&#xff08;第十二届蓝桥杯省赛第二场C A组/B组&#…...

全坚固笔记本丨工业笔记本丨三防笔记本相较于普通笔记本有哪些优势?

三防笔记本和普通笔记本在设计和性能方面存在显著差异&#xff0c;三防笔记本相较于普通笔记本具备以下优势&#xff1a; 三防笔记本通常采用耐磨、耐摔的材料&#xff0c;并具有坚固的外壳设计&#xff0c;能够承受恶劣环境和意外碰撞&#xff0c;有效保护内部组件不受损坏。相…...

机房搬迁方案

一、项目背景 随着XX公司业务的不断扩展&#xff0c;现有的机房设备已经无法满足日益增长的数据处理需求。同时&#xff0c;考虑到现有机房的设施老化及潜在的安全隐患&#xff0c;XX公司决定进行机房搬迁。本次搬迁旨在确保业务连续性、数据安全性以及新机房的高效运营。 二…...

推动科技创新润德生物邀您到场参观2024第13届生物发酵展

参展企业介绍 山东润德生物科技有限公司成立于2014年10月17日&#xff0c;是一家围绕生物制品的研发、生产、营销、国际贸易、技术服务为核心业务的国家高新技术企业&#xff0c;近年来荣获国家制造业单项冠军示范企业、国家级绿色工厂、国家知识产权优势企业、国家工业产品绿…...

如何在JavaScript中提高性能

在JavaScript中提高性能是一个涉及多个方面的任务&#xff0c;包括代码优化、数据结构选择、异步编程、避免全局查找、内存管理等。以下是一些关键的策略和技巧&#xff0c;可以帮助你提高JavaScript代码的性能&#xff1a; 1. 优化循环 使用for循环代替forEach&#xff0c;特…...

外观模式(面子模式)

外观模式 文章目录 外观模式什么是外观模式示例 什么是外观模式 外观模式(Facade),为子系统中的一组接口提供一个一致的界面&#xff0c;此模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用 Facade 外观类 知道哪些子系统类负责处理请求&#xff0c;将客…...

蓝桥杯考前复习三

1.约数个数 由乘法原理可以得出&#xff1a; import java.util.*; public class Main{static int mod (int)1e9 7;public static void main(String[] args){Map<Integer,Integer> map new HashMap<>(); //创建一个哈希表Scanner scan new Scanner(System.in);i…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...