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

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

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

相关文章

多线程重点知识(个人整理笔记)

目录 1. java 多线程 1.1. 什么是进程?什么是线程? 1.1.1. 进程 1.1.2. 线程 1.1.3. 多线程 2. 并行和并发有什么区别&#xff1f; 3. 守护线程是什么&#xff1f; 4. 创建线程有哪几种方式&#xff1f; 4.1. 线程的常见成员方法 5. 线程安全问题 5.1. synchronize…

深度探索Sketch:功能、历程、替代软件及技巧一览

Sketch 它是一个适合所有设计师的矢量绘图应用程序。矢量绘图也是设计网页、图标和界面的最佳方式。但除了矢量编辑的功能外&#xff0c;我们还增加了一些基本的位图工具&#xff0c;如模糊和颜色校正。 为什么选择Sketch Sketch 它是为图标设计和界面设计而生的。它是一个优…

2024年C语言最新经典面试题汇总(21-30)

C语言文章更新目录 C语言学习资源汇总&#xff0c;史上最全面总结&#xff0c;没有之一 C/C学习资源&#xff08;百度云盘链接&#xff09; 计算机二级资料&#xff08;过级专用&#xff09; C语言学习路线&#xff08;从入门到实战&#xff09; 编写C语言程序的7个步骤和编程…

Navicat中导出导入txt结合sql语句实现sqlserver转到Postgis空间数据库中

效果 1、sqlserver数据库中导出 sqlserver数据库字段 2、postgis中导入

C++ //练习 11.20 重写11.1节练习(第376页)的单词计数程序,使用insert代替下标操作。你认为哪个程序更容易编写和阅读?解释原因。

C Primer&#xff08;第5版&#xff09; 练习 11.20 练习 11.20 重写11.1节练习&#xff08;第376页&#xff09;的单词计数程序&#xff0c;使用insert代替下标操作。你认为哪个程序更容易编写和阅读&#xff1f;解释原因。 环境&#xff1a;Linux Ubuntu&#xff08;云服务…

Golang | Leetcode Golang题解之第9题回文数

题目&#xff1a; 题解&#xff1a; func isPalindrome(x int) bool {// 特殊情况&#xff1a;// 如上所述&#xff0c;当 x < 0 时&#xff0c;x 不是回文数。// 同样地&#xff0c;如果数字的最后一位是 0&#xff0c;为了使该数字为回文&#xff0c;// 则其第一位数字也…

京东API接口采集商品详情数据(测试入口如下)

京东API接口采集商品详情数据 请求示例&#xff0c;API接口接入Anzexi58 在当今数字化时代&#xff0c;电商平台的API接口成为了获取商品详情数据的重要途径之一。作为中国最大的自营式电商企业&#xff0c;京东提供了丰富的API接口供开发者使用&#xff0c;以便获取京东平台上…

计算机网络——38报文完整性

报文完整性 数字签名 数字签名类比于手写签名 发送方数字签署了文件&#xff0c;前提是他是文件的拥有者/创建者可验证性&#xff0c;不可伪造性&#xff0c;不可抵赖性 谁签署&#xff0c;接收方可以向他人证明是他&#xff0c;而不是其他人签署了这个文件签署了什么&#…

day02php环境和编译器—我耀学IT

一、环境介绍 1、web 环境 使用 PHP 需要先安装环境&#xff0c;安装环境比较麻烦&#xff0c;需要安装Web服务、PHP应用服务器、MySQL管理系统。 Web服务&#xff1a;apache 和 nginx PHP&#xff1a;多版本 MySQL&#xff1a;多版本 2、环境集成包 因为多环境、多版本、多系…

Java学习笔记23(面向对象三大特征)

1.5 多态 ​ *多态(polymorphic) ​ *方法或对象具有多种形态&#xff0c;是面向对象的第三大特征&#xff0c;多态是建立在封装和继承基础之上的 1.多态的具体体现 1.方法的多态 &#xff08;重写和重载体现了多态&#xff09; 2.对象的多态 ​ 1.一个对象的编译类型和…

三国游戏(贪心 排序)

三国游戏 利用贪心、排序、前缀和的计算方法&#xff0c;特别注意不要数据溢出了&#xff0c;sum 加long long s[i] x[i]-y[i]-z[i]输入: 3 1 2 2 2 3 2 1 0 7输出: 2#include <bits/stdc.h> using namespace std;const int N 1e5100;typedef long long ll;bool cm…

容器和K8s常见概念

【容器】 1、Open Container Initiative&#xff08;OCI&#xff09;&#xff1a;制定和推动容器格式和运行时的开放标准。容器运行时需要遵循此标准。主要的产出物包括&#xff1a; OCI Image Specification: 定义容器镜像格式的规范&#xff0c;统一描述容器镜像的内容和结…

git入门教程

Git 1. Git历史 同生活中的许多伟大事件一样&#xff0c;Git 诞生于一个极富纷争大举创新的年代。Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上&#xff08;1991&#xff0d;2002年间&#xff09;。到 2002…

PicGo日志报错 image not found in clipboard

PicGo: image not found in clipboard 文章目录 PicGo: image not found in clipboard问题描述问题尝试解决方案 问题描述 背景&#xff1a;在剪切板中的图片无法通过 PicGo 的剪切板图片进行上传。 读取PicGo 日志报错&#xff0c;显示图片没有在剪切板中找到。 $ ------Erro…

express接口请求的几种方式分析总结

导语 在用express做接口开发的时候&#xff0c;我们要处理post,get,put,delete等请求&#xff0c;以及jsonp的方式&#xff0c;这篇文章记录下结合ajax&#xff0c;实现处理这些请求方式的过程 实现过程 上代码&#xff0c;主要演示post,get及jsonp的请求 <!DOCTYPE htm…

(学习日记)2024.04.05:UCOSIII第三十三节:互斥量

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

51单片机入门_江协科技_17~18_OB记录的笔记

17. 定时器 17.1. 定时器介绍&#xff1a;51单片机的定时器属于单片机的内部资源&#xff0c;其电路的连接和运转均在单片机内部完成&#xff0c;无需占用CPU外围IO接口&#xff1b; 定时器作用&#xff1a; &#xff08;1&#xff09;用于计时系统&#xff0c;可实现软件计时&…

C语言题目:分段函数练习

题目描述 输入x &#xff0c;计算并输出下列分段函数 f(x) 的值。可以调用数学库函数&#xff1a;平方根函数sqrt(),绝对值函数fabs() 和幂函数 pow()。 保留2位小数 输入格式 x 输出格式 f(x) 样例输入 5 样例输出 15.00 代码分析 包含标准输入输出库和数学库: #incl…

Linux -- 字符设备驱动--LED的驱动开发(初级框架)

驱动框架一阶段 我们怎样去点亮一个 LED 呢&#xff1f;分为三步&#xff1a; 看原理图确定引脚&#xff0c;确定引脚输出什么电平才能点亮/熄灭 LED 看主芯片手册&#xff0c;确定寄存器操作方法&#xff1a;哪些寄存器&#xff1f;哪些位&#xff1f;地址是&#xff1f; 编…

webpack5如何关闭全屏错误

1、找到vue.config.js 2、在上面的devServer里面添加如下&#xff1a; client: {overlay: false, // 禁用全局错误提示},