当前位置: 首页 > 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…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中&#xff0c;性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期&#xff0c;开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发&#xff0c;但背后往往隐藏着系统资源调度不当…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...