【顺序表的应用-通讯录的实现】

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、顺序表的应用

1. 基于动态顺序表实现通讯录

1、功能要求

2、代码实现

二、通讯录的代码实现

1.通讯录的底层结构(顺序表)

(1)思路展示

(2)底层代码实现(顺序表)

2.通讯录上层代码实现(通讯录结构)

(1).思路展示

(2).上层代码实现(通讯录)

3.通讯录代码运行展示

总结


前言

世上有两种耀眼的光芒,一种是正在升起的太阳,一种是正在努力学习编程的你!一个爱学编程的人。各位看官,我衷心的希望这篇博客能对你们有所帮助,同时也希望各位看官能对我的文章给与点评,希望我们能够携手共同促进进步,在编程的道路上越走越远!


提示:以下是本篇文章正文内容,下面案例可供参考

一、顺序表的应用

1. 基于动态顺序表实现通讯录

C语言基础要求:结构体、动态内存管理、顺序表、文件操作

1、功能要求

1)至少能够存储100个人的通讯信息

2)能够保存用户信息:名字、性别、年龄、电话、地址等

3)增加联系人信息

4)删除指定联系人

5)查找制定联系人

6)修改指定联系人

7)显示联系人信息

2、代码实现

【思考1】用静态顺序表和动态顺序表分别如何实现

【思考2】如何保证程序结束后,历史通讯录信息不会丢失

二、通讯录的代码实现

1.通讯录的底层结构(顺序表)

(1)思路展示

通讯录底层是顺序表来实现(相当于:通讯录 == 顺序表)

顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口

(2)底层代码实现(顺序表)

Seqlist.h(顺序表的头文件:目录)

#pragma once#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include "Contact.h"
//动态顺序表
//类型重命名(要加分号)
//如果我们要转换类型的话,就可以直接替换int
//typedef int SLDataType;
typedef struct ContactInfo SLDataType;//结构体的类型重命名要加struct
//我们把顺序表的数据类型改成联系人的结构体类型
typedef struct Seqlist
{SLDataType* a;//动态顺序表中底层结构中数组中的起始地址(a:指针变量,用来存放下面代码开辟空间的起始地址)int size;  //顺序表中有效的数据个数 = 最后一个数据的下一个位置(因为位置的话,有下标0)int capacity;  //顺序表中当前的空间大小
}SL;//对结构体类型初始化
//sl是结构体类型创建的变量
void SLInit(SL* ps);//销毁顺序表
void SLDestroy(SL* ps);//头部/尾部 插入或删除
void SLPushBack(SL* ps, SLDataType x);
//我们在顺序表中尾部插入一个SLDataType类型的数据x
void SLPushFront(SL* ps, SLDataType x);//头部插入void SLPopBack(SL* ps);//尾部删除
void SLPopFront(SL* ps);//头部删除//打印数据
void SLprint(SL* ps);//当把顺序表都初始化为0,而没有尾插和头插的话,就直接进行尾删,代码会报错
//判断顺序表是否为空
bool SLIsEmpty(SL* ps);//在任意位置插入数据
//在指定的位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
//删除指定位置的数据
void SLErase(SL* ps, int pos);//在数据表中查找数据
bool SLFind(SL* ps, SLDataType x);

Seqlist.c(顺序表的源文件:函数的具体实现)

#define _CRT_SECURE_NO_WARNINGS 1//接口:我们后续提供给其他用户使用的函数或方法
#include "Seplist.h"
void SLInit(SL* ps)
{ps->a = NULL;ps->size = ps->capacity = 0;
}//销毁顺序表
void SLDestroy(SL* ps)
{//动态内存开辟了空间才能free()释放if (ps->a != NULL)free(ps->a);ps->a = NULL;ps->size = ps->capacity = 0;
}//判断当前顺序表的空间是否足够
void SLCheckCapacity(SL* ps)
{if (ps->size == ps->capacity){//结构体变量指向的有效数据个数==顺序表当前空间的大小,就得扩容//realloc()函数的第二个参数:顺序表当前空间的大小 * 2倍 * SLDataType的类型//首先得判断一下顺序表中当前空间的大小是否为0,因为为0的话,0*任何数都是0int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc");return;}ps->a = tmp;ps->capacity = newcapacity;//顺序表当前空间的大小赋值给capacity,一个空间大小是SLDataType类型的}
}//头部/尾部 插入或删除
void SLPushBack(SL* ps, SLDataType x)
{assert(ps != NULL);//1:空间足够,直接尾插//2:空间不够,扩容//直接调用扩容函数SLCheckCapacity(ps);//直接插入数据ps->a[ps->size] = x;ps->size++;
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{assert(ps != NULL);//判断空间是否足够的函数//空间不够,扩容SLCheckCapacity(ps);//空间足够,历史数据向后移一位for (size_t i = ps->size; i > 0; i--){ps->a[i] = ps->a[i - 1];}ps->a[0] = x;//第0个位置直接插入xps->size++;//既要增加数据,也要增加空间
}void SLPopBack(SL* ps)//尾部删除
{assert(ps != NULL);assert(!SLIsEmpty(ps));//SLIsEmpty(ps):如果为真,就进入函数,那么顺序表就为空//SLIsEmpty(ps):为真,加!就为假,那么断言执行,否则就不执行ps->size--;
}
void SLPopFront(SL* ps)//头部删除
{assert(ps);assert(!SLIsEmpty(ps));//让后面的数据往前挪动一位for (size_t i = 0; i < ps->size - 1; i++){//如果数组下标为ps->size的话,就越界了//因为size为有效数据的个数 = 最后一个数据的下一个位置(有下标为0)ps->a[i] = ps->a[i + 1];}ps->size--;
}//打印数据
void SLprint(SL* ps)
{for (size_t i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}//判断顺序表是否为空
bool SLIsEmpty(SL* ps)
{assert(ps != NULL);return ps->size == 0;//如果当前没有一个有效的数据,就为空
}//在任意位置插入数据
//在指定的位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{//pos的位置对于计算机看来是下标的意思assert(ps);//不要忘了对pos加以限制assert(pos >= 0 && pos <= ps->size);//怕有人会在-100之类的位置插入数据//扩容SLCheckCapacity(ps);//把pos位置及以后的数据往后挪动一位//循环条件里的i的初始值是size还是size-1都是可以的,但不同的初始值对应不同的结束条件for (size_t i = ps->size; i > pos; i--){//最后一个进来的值是pos+1ps->a[i] = ps->a[i - 1];}ps->a[pos] = x;ps->size++;
}
//删除指定位置的数据
void SLErase(SL* ps, int pos)
{assert(ps);assert(!SLIsEmpty(ps));//要对pos进行限制assert(pos >= 0 && pos < ps->size);for (int i = pos; i < ps->size - 1; i++){//最后一次进来的数据是ps->size-2(ps->size的话,就越界了)ps->a[i] = ps->a[i + 1];//ps->a[size-2] = ps->a[size-1]}ps->size--;
}

test1.c(顺序表源文件:顺序表的测试)

#define _CRT_SECURE_NO_WARNINGS 1#include "seqlist.h"void SLtest()
{SL sl;//定义一个顺序表,sl就是没有初始化//SLInit(sl);//我们把sl传递给一个初始化的方法进行初始化SLInit(&sl);//我们想要把sl初始化的话,要把地址传过去,因为形参是实参的一份临时拷贝//顺序表的具体操作//尾插SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);//1 2 3 4SLprint(&sl);//头插SLPushFront(&sl, 5);//5 1 2 3 4 SLPushFront(&sl, 6);//6 5 1 2 3 4SLPushFront(&sl, 7);//7 6 5 1 2 3 4SLprint(&sl);//尾删SLPopBack(&sl);SLprint(&sl);SLPopBack(&sl);SLprint(&sl);//销毁顺序表SLDestroy(&sl);
}
void SLtest02()
{SL sl;SLInit(&sl);SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLprint(&sl);//头删SLPopFront(&sl);SLprint(&sl);SLPopFront(&sl);SLprint(&sl);	SLPopFront(&sl);SLprint(&sl);//到这里顺序表已经没有数据了SLPopFront(&sl);SLprint(&sl);//在任意位置插入数据//在指定的位置之前插入数据SLInsert(&sl, sl.size, 11);SLprint(&sl);//删除指定位置的数据SLErase(&sl, 0);SLprint(&sl);//在数据表中查找数据bool Findret = SLFind(&sl, 3);if (Findret == 3){printf("找到了!\n");}else{printf("找不到!\n");}//销毁顺序表SLDestroy(&sl);
}int main()
{//测试顺序表是否被初始化SLtest();SLtest02();return 0;
}

2.通讯录上层代码实现(通讯录结构)

(1).思路展示

1:因为通讯录底层是顺序表来实现(相当于:通讯录 == 顺序表)

2:所以通讯录首先要创建保存联系人数据的结构体,通讯录的信息类型创建好后,我们可以一键替换到顺序表中,其次再定义通讯录所需的函数实现即可

3:基于前面,我们已经知道,通讯录是基于动态顺序表实现的,所以在实现通讯录功能函数时,只需要在通讯录上层代码的源文件中,加上顺序表的头文件就可以调运顺序表已经实现好的函数来实现通讯录了。

(2).上层代码实现(通讯录)

Contact.h(通讯录的头文件:创建并保存联系人信息的头文件来替换动态顺序表的数据类型,起通讯录所需函数的声明)

#pragma once//创建保存联系人数据的结构
#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 15
#define ADDR_MAX 100
//通讯录的信息类型创建好后,我们可以一键替换到顺序表中
//通讯录联系人的信息
typedef struct ContactInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];//电话号码char addr[ADDR_MAX];
}CInfo;
//CInfo:是结构体类型重命名,但是只在Contact.h(本文件)内使用,出了文件,别的文件都不认识//通讯录底层是顺序表来实现(相当于:通讯录 == 顺序表)
//给顺序表起个新名字
typedef struct Seqlist contact;
//为什么Contact.h文件中不包含#include "Seqlist.h"的头文件呢?
//因为我们的Contact.h头文件只是用了"Seqlist.h"的头文件的表面内容,并没有具体使用函数以及一些这个头文件的数据 //通讯录的创建和销毁
void ContactInit(contact* pcon);
void ContactDestroy(contact* pcon);//添加联系人(我们可以从终端,也就是屏幕获取,用scanf()函数,所以可以不用传参数)
void ContactAdd(contact* pcon);
//删除联系人
void ContactDel(contact* pcon);
//修改联系人
void ContactModify(contact* pcon);
//查看(展示)通讯录
void ContactShow(contact* pcon);
//查找指定联系人
void ContactFind(contact* pcon);

contact.c(通讯录的源文件:实现通讯录所需的函数功能)

#define _CRT_SECURE_NO_WARNINGS 1
//通讯录的实现文件
#include "Contact.h"
#include "Seplist.h"//通讯录初始化
void ContactInit(contact* pcon)
{SLInit(pcon);}
//通讯录销毁
void ContactDestroy(contact* pcon)
{SLDestroy(pcon);
}//添加联系人(我们可以从终端,也就是屏幕获取,用scanf()函数,所以可以不用传参数)
void ContactAdd(contact* pcon)
{//接下来要获取的信息都是CInfo结构体里要求的数据CInfo info;//结构体创建变量,用变量来获取终端输入的信息printf("请输入联系人姓名:\n");scanf("%s", info.name);//把输入的名字存放到变量的name结构体成员里printf("请输入联系人的性别:\n");scanf("%s", info.sex);printf("请输入联系人的年龄:\n");scanf("%d", &info.age);printf("请输入联系人的电话:\n");scanf("%s", info.tel);printf("请输入联系人的住址:\n");scanf("%s", info.addr);//联系人数据都获取到了,并保存在结构体info中//往通讯录(顺序表)中插入数据SLPushBack(pcon, info);//尾插 1:通讯录结构体传过去,2:联系人结构体保存的数据传过去
}//查找这个联系人到底在不在
int FindByName(contact* pcon,char name[])
{for (int i = 0; i < pcon->size; i++){if (strcmp(pcon->a[i], name) == 0)return i;//返回的是通讯录中数组的下标}return -1;
}//删除联系人
void ContactDel(contact* pcon)
{//直接强制要求用户使用联系人姓名来查找printf("请输入要删除的用户名称:\n");char name[NAME_MAX];scanf("%s", name);int Findidex = FindByName(pcon, name);if (Findidex < 0){printf("要删除的联系人不存在!\n");return;//这个函数就到此位置了}//找到了,要删除findidex位置的数据SLErase(pcon, Findidex);
}
//修改联系人
void ContactModify(contact* pcon)
{printf("请输入要修改的联系人名称:\n");char name[NAME_MAX];scanf("%s", name);//获取到通讯录(顺序表)下标的位置int find = FindByName(pcon, name);if (find < 0){printf("要修改的用户名称不存在!\n");return;//结束当前的方法运行//exit(1);//直接就把程序退出了,是粗暴的行为}printf("请输入新的用户名称:\n");scanf("%s", pcon->a[find].name);printf("请输入新的用户性别:\n");scanf("%s", pcon->a[find].sex);printf("请输入新的用户年龄:\n");scanf("%d", &pcon->a[find].age);printf("请输入新的用户电话:\n");scanf("%s", pcon->a[find].tel);printf("请输入新的用户住址:\n");scanf("%s", pcon->a[find].addr);printf("修改成功!\n");}
//查看(展示)通讯录
void ContactShow(contact* pcon)
{//打印通讯录所有的数据//先打印表头文字printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");for (int i = 0; i < pcon->size; i++){printf("%s %s %d %s %s\n",pcon->a[i].name,pcon->a[i].sex,pcon->a[i].age,pcon->a[i].tel,pcon->a[i].addr);}
}
//查找指定联系人
void ContactFind(contact* pcon)
{printf("请输入要查找的用户名称:\n");char name[NAME_MAX];scanf("%s", name);int find = FindByName(pcon, name);if (find < 0){printf("该联系人不存在!\n");return;}//存在的话,打印当前的联系人printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");printf("%s %s %d %s %s",pcon->a[find].name,pcon->a[find].sex,pcon->a[find].age,pcon->a[find].tel,pcon->a[find].addr);
}

test.c(通讯录的头文件:用来测试程序运行)

#define _CRT_SECURE_NO_WARNINGS 1
#include "Seplist.h"
#include "Contact.h"//void contact01()
//{
//	contact con;
//	ContactInit(&con);
//	//往通讯录中插入数据
//	ContactAdd(&con);
//	//ContactAdd(&con);
//	//展示通讯录
//	ContactShow(&con);
//	//ContactDel(&con);
//	//ContactShow(&con);
//	//修改联系人
//	ContactModify(&con);
//	ContactShow(&con);
//	//查找指定联系人
//	ContactFind(&con);
//
//	ContactDestroy(&con);
//}void menu()
{printf("****************   通讯录    ******************\n");printf("**********1.添加联系人   2.删除联系人**********\n");printf("**********3.修改联系人   4.查找联系人**********\n");printf("**********5.查找通讯录   0.退  出   ***********\n");printf("***********************************************\n");
}
int main()
{int input = 0;//定义一个通讯录contact con;ContactInit(&con);do{menu();printf("请选择您的操作!\n");scanf("%d", &input);switch(input){case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactModify(&con);break;case 4:ContactFind(&con);break;case 5:ContactShow(&con);break;case 0:printf("goodbye~\n");break;default:printf("输入错误,请重新输入!\n");break;}} while (input != 0);ContactDestroy(&con);//contact01();return 0;
}

3.通讯录代码运行展示


总结

好了,本篇博客到这里就结束了,如果有更好的观点,请及时留言,我会认真观看并学习。
不积硅步,无以至千里;不积小流,无以成江海。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/205891.html

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

相关文章

t检验(连续变量)和卡方检验(分类变量)

目录 情形 不同种类的萼片差异 数据类型查看&#xff1a; 差异分析&#xff1a; 不同萼片的种类差异 数据准备 二分类卡方检验 绘图 情形 &#xff1a;当有两列数据进行分析比较时&#xff0c;一列为连续变量&#xff0c;一列数据为分类变量。 rm(list ls()) libra…

(01)vite 从启动服务器开始

文章目录 前言在浏览器中使用es模块初始化环境vite依赖预构建解决了什么问题创建vite.config.js配置vite为什么vite.config.js可以用esmodule规范 前言 Vite&#xff08;发音为"veet"&#xff09;是一种现代化的前端构建工具&#xff0c;旨在提供快速的开发体验。它…

如何最大化客户生命周期价值?APMDR 模型在袋鼠云的落地实践

相信大家都认可一个观点&#xff1a;不论是 To B 还是 To C&#xff0c;用户是企业的核心资源&#xff0c;是互联网产品中最重要的价值之一。因此&#xff0c;深入挖掘用户价值成为现在大部分企业运营的关键。 之前我们为大家介绍过如何利用 RFM 模型让企业聚焦于更有价值的用…

双12电视盒子推荐:测评员解析目前电视盒子哪个最好

电视盒子不需要每月缴费&#xff0c;只需联网就可以收看海量视频资源&#xff0c;游戏、网课、投屏等功能让电视盒子的使用场景更丰富&#xff0c;我每年都会进行数十次电视盒子测评&#xff0c;本期要分享的是双十二电视盒子推荐&#xff0c;全面解析目前电视盒子哪个最好。 一…

NC65 修改元数据字段长度

NC65 修改元数据字段长度&#xff0c;执行下面sql&#xff0c;执行完后需要重启NC服务才生效。 --属性 update md_property set attrlength 200 where name fphm and classidece96dd8-bdf8-4db3-a112-9d2f636d388f ;--列 update md_column set columnlength 200 where tab…

系列六、ThreadLocal内存泄漏案例

一、内存泄漏 vs 内存溢出 内存泄漏&#xff1a;内存泄漏是指程序中已经动态分配的堆内存由于某种原因程序未释放或者无法释放&#xff0c;造成系统内存的浪费&#xff0c;导致程序运行速度减慢甚至导致系统崩溃等严重后果&#xff0c;内存泄漏最终 会导致内…

docker报错standard init linux.go:228 exec user process caused: exec format error

1、报错 使用Dockerfile自己做的服务镜像&#xff0c;docker run时启动失败&#xff0c;报错如下&#xff1a; standard init linux.go:228 exec user process caused: exec format error2、原因一 当前服务器的CPU架构和构建镜像时的CPU架构不兼容。比如做镜像是在arm机器下…

微服务学习|Feign:快速入门、自定义配置、性能优化、最佳实践

RestTemplate方式调用存在的问题 先来看我们以前利用RestTemplate发起远程调用的代码 存在下面的问题 代码可读性差&#xff0c;编程体验不统一 参数复杂URL难以维护 Feign的介绍 Feign是一个声明式的http客户端&#xff0c;官方地址: https://github.com/OpenFeign/feign …

Java-Object类

Object类 所有类都直接或间接的继承自Object类&#xff0c;Object类是所有Java类的根基类。 也就意味着所有的Java对象都拥有Object类的属性和方法。 如果在类的声明中未使用extends关键字指明其父类&#xff0c;则默认继承Object类。 toString()方法 【1】Object类的toStr…

最新AIGC创作系统ChatGPT网站源码,Midjourney绘画系统,支持最新GPT-4-Turbo模型,支持DALL-E3文生图

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

天天谈体验,为什么客户还是给差评?

相比于线上场景&#xff0c;线下门店在数字化上更加复杂困难。不过&#xff0c;线下空间自有其得天独厚的优势条件——客户可以在这里最大程度获取对产品乃至品牌调性的亲身体验。 线上商城或直播中的产品效果图是否与实物一致&#xff1f;品牌许诺的产品功能价值是否真的能实现…

ubuntu下docker环境使用GPU配置

本文主要讲述整个命令流程&#xff0c;具体讲解请看官网nvidia-容器工具包和一篇总结得很详细的博文docker使用GPU总结 docker的版本必须安装19.0版本以上的&#xff0c;这里也只讲19.0版本以上的使用方法 首先设置一下网络信息 curl -fsSL https://nvidia.github.io/libnvi…