循序表实战——基于循序表的通讯录
前言:本篇文章主要是利用顺序表作为底层, 实现一个通讯录。偏向于应用, 对于已经学习过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);}
}
以上, 就是顺序表实现通讯录的全部内容。 下面是我上传的本篇文章对应的源代码。想要的自行下载。
相关文章:
循序表实战——基于循序表的通讯录
前言:本篇文章主要是利用顺序表作为底层, 实现一个通讯录。偏向于应用, 对于已经学习过c的友友们可能没有难度了已经。没有学习过c的友友, 如果顺序表不会写, 或者说没有自己实现过, 请移步学习顺序表相关内…...
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 语言的位域(bit-field)是一种特殊的结构体成员,允许我们按位对成员进行定义,指定其占用的位数。 如果程序的结构中包含多个开关的变量,即变量值为 TRUE/FALSE,如下: struct {unsigned int w…...
【LeetCode热题100】【技巧】颜色分类
题目链接:75. 颜色分类 - 力扣(LeetCode) 只需排序三种,可以记录0和1的个数,然后直接原地赋值 class Solution { public:void sortColors(vector<int> &nums) {int zero 0, one 0;for (auto &num: n…...
笔记本电脑win7 Wireless-AC 7265连不上wifi6
1.背景介绍 旧路由器连接人数有限,老旧,信号不稳定更换了新路由器,如 TL-XDR5430易展版用户电脑连不上新的WIFI网络了,比较着急 核心问题:有效解决笔记本连接wifi上网问题,方法不限 2.环境信息 Windows…...
Linux gcc day5粘滞位
粘滞位 背景:一定时在一个公共目录(root创建)下。进行临时文件的操作 Linux系统中有很多人,我们需要在一个公共目录下,进行临时文件的操作(增删查改) 创建一个根目录下的dir(mytmp…...
单片机按键消抖常用的软硬件方法
一:什么是开关抖动? 当我们按下按钮或拨动开关或微动开关时,两个金属部件会接触以短路电源。但它们不会立即连接,而是金属部件在实际稳定连接之前连接和断开几次。释放按钮时也会发生同样的事情。这会导致误触发或多次触发&#…...
钉钉自建应用-下载excel(h5)
由于不同手机对于文件下载有不同的支持,而且文件路径也不一样,找起来十分的麻烦。所以,最好是找到一个都支持的方法。还好,钉钉官网提供了网盘,我们可把文件保存到钉钉自带的网盘,这样方便查找。 这里需要…...
用二八定律分析零售数据,不就更直观了吗?
20%的商品贡献了80%的销售金额,你会不会想知道这些商品的销售金额、毛利、销售金额累计占比、毛利累计占比,会不会想知道这些商品在各个门店的销售表现?看是否能进一步提高销售金额,提高毛利。这样的报表该怎么做?奥威…...
NetSuite Saved Search-当前库存快照查询报表(二)
之前第一篇文章我们说明了,如何利用Saved Search来制作一个能够显示批次物料与非批次物料的Lot信息以及On Hand在手数量的“当前库存快照查询报表”,但是当用户提出“我们能否再加上批次物料的效期”需求时,我们原有的Saved Search并不能达到…...
【JavaSE】接口 详解(上)
前言 本篇会讲到Java中接口内容,概念和注意点可能比较多,需要耐心多看几遍,我尽可能的使用经典的例子帮助大家理解~ 欢迎关注个人主页:逸狼 创造不易,可以点点赞吗~ 如有错误,欢迎指出~ 目录 前言 接口 语法…...
嵌入式C基础——循环队列 ringbuffer 讲解
本期主题: 讲解ARRAY_SIZE的作用以及定义,还有一个踩坑分析 往期链接: 数据结构系列——先进先出队列queue数据结构系列——栈 stackLinux内核链表零长度数组的使用inline的作用嵌入式C基础——ARRAY_SIZE使用以及踩坑分析 目录 1. Ringbuff…...
【动态规划-状态压缩dp】【蓝桥杯备考训练】:毕业旅行问题、蒙德里安的梦想、最短Hamilton路径、国际象棋、小国王【已更新完成】
目录 1、毕业旅行问题(今日头条2019笔试题) 2、蒙德里安的梦想(算法竞赛进阶指南) 3、最短Hamilton路径(《算法竞赛进阶指南》&模板) 4、国际象棋(第十二届蓝桥杯省赛第二场C A组/B组&#…...
全坚固笔记本丨工业笔记本丨三防笔记本相较于普通笔记本有哪些优势?
三防笔记本和普通笔记本在设计和性能方面存在显著差异,三防笔记本相较于普通笔记本具备以下优势: 三防笔记本通常采用耐磨、耐摔的材料,并具有坚固的外壳设计,能够承受恶劣环境和意外碰撞,有效保护内部组件不受损坏。相…...
机房搬迁方案
一、项目背景 随着XX公司业务的不断扩展,现有的机房设备已经无法满足日益增长的数据处理需求。同时,考虑到现有机房的设施老化及潜在的安全隐患,XX公司决定进行机房搬迁。本次搬迁旨在确保业务连续性、数据安全性以及新机房的高效运营。 二…...
推动科技创新润德生物邀您到场参观2024第13届生物发酵展
参展企业介绍 山东润德生物科技有限公司成立于2014年10月17日,是一家围绕生物制品的研发、生产、营销、国际贸易、技术服务为核心业务的国家高新技术企业,近年来荣获国家制造业单项冠军示范企业、国家级绿色工厂、国家知识产权优势企业、国家工业产品绿…...
如何在JavaScript中提高性能
在JavaScript中提高性能是一个涉及多个方面的任务,包括代码优化、数据结构选择、异步编程、避免全局查找、内存管理等。以下是一些关键的策略和技巧,可以帮助你提高JavaScript代码的性能: 1. 优化循环 使用for循环代替forEach,特…...
外观模式(面子模式)
外观模式 文章目录 外观模式什么是外观模式示例 什么是外观模式 外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用 Facade 外观类 知道哪些子系统类负责处理请求,将客…...
蓝桥杯考前复习三
1.约数个数 由乘法原理可以得出: 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…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
