哲♂学家带你用顺序表实现通讯录

news2025/1/19 14:38:33

实现通讯录能使我们进一步加深对顺序表的理解,接下来就由本哲♂学家带你手把手实现通信录。

其中需要用到顺序表的知识可以点击下面链接了解:http://t.csdnimg.cn/9SjGd话不多说,我们♂开始吧。

一、通讯录头文件声明

由于我们前面已经写过顺序表其头文件我们可以直接用这里只展示seqlist的头文件

seqlist.h:

#pragma once//防止头文件二次引用
typedef struct PersonInfo SLDataType;//方便后续该存储类型
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"contact.h"
typedef struct seqlist
{
	SLDataType* arr;//存放数据的数组
	int size;//有效元素个数
	int capacity;//空间的大小
}SL;
// 初始化和销毁
void SLInit(SL * ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);

//头部插入删除 / 尾部插入删除
void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);

//指定位置之前插入/删除数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
//找到指定位置的数据
int SLFind(SL* ps, SLDataType x);

contact.h:

#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100
//因为头文件不能相互包含,所以用前置声明
typedef struct SeqList contact;
//用户数据
typedef struct PersonInfo

{
	char name[NAME_MAX];//名字
	char sex[SEX_MAX];//性别
	int age;//年龄
	char tel[TEL_MAX];//电话
	char addr[ADDR_MAX];//地址
}PeoInfo;
//初始化通讯录

void InitContact(contact* con);//实际上是对顺序表初始化

//添加通讯录数据

void AddContact(contact* con);

//删除通讯录数据

void DelContact(contact* con);

//展示通讯录数据

void ShowContact(contact* con);

//查找通讯录数据

void FindContact(contact* con);

//修改通讯录数据

void ModifyContact(contact* con);

//销毁通讯录数据

void DestroyContact(contact* con);

值得注意的是因为头文件不能相互包含所以只能前置声明我们创建的SeqList结构体。

二、函数实现:

首先我们要明确通讯录实际上是顺序表,只不过其内容是结构,对通讯录的操作,实际上是对顺序表的操作。

1、初始化与销毁

前面我们知道,通讯录本质上是顺序表,所以对通讯录的初始化和销毁,实际上就是对顺序表的初始化和销毁:

//初始化通讯录
void InitContact(contact* con)//实际上是对顺序表初始化
{
	SLInit(con);
}
//销毁通讯录
void DestroyContact(contact* con)
{
	void SLDestroy(SL * ps);
}

2、添加通讯录信息

//添加通讯录信息
void ContactAdd(contact* con)
{
	//获取用户输入的内容:姓名+性别+年龄+电话+地址
	PeoInfo info;//创建顺序表的元素
	printf("请输入要添加的联系人姓名:\n");
	scanf("%s", info.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);
	//往通讯录中添加联系人数据,实际上就是尾部插入。
	SLPushBack(con, info);//SLPushBack中带有空间大小检查功能这不用考虑空间大小问题
}

实际上,我们只不过将顺序表的成员改成了结构体而已,所以要将结构体插入(一定要捋清楚这个关系)。 

3、删除通讯录信息

如果是一个普通的数组,我们只需要将要删除的下标穿过去就好了,但是这个是要删除结构体,我们可以通过访问结构体包含的名字成员对比,来找到元素下标删除数据:

//只是删除数据的辅助函数,不是找数据的函数
int FindByName(contact* con, char name[])
{
	for (int i = 0; i < con->size; i++)
	{
		if (0 == strcmp(con->arr[i].name, name))
		{
			//找到了
			return i;
		}
	}
	//没有找到
	return -1;
}
//删除通讯录数据
void DelContact(contact* con)
{
	printf("请输入要删除的名字:");
	char dename[NAME_MAX];
	scanf("%s", dename);
	int find = FindByName(con, dename);
	if (find < 0)
	{
		printf("要删除的联系人数据不存在!\n");
		return;//不存在直接跳出函数;
	}
	//要删除的联系人数据存在--->知道了要删除的联系人数据对应的下标
	SLErase(con, find);
	printf("删除成功!\n");
}

 

代码显示没有任何问题。 

4、展示通讯录数据

这个就直接上代码了,非常简单

void ShowContact(contact* con)
{
	//表头:姓名  性别 年龄 电话  地址
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	//遍历通讯录,按照格式打印每个联系人数据
	for (int i = 0; i < con->size; i++)
	{
		printf("%3s %3s %3d %3s %3s\n", //手动调整一下格式
			con->arr[i].name,
			con->arr[i].sex,
			con->arr[i].age,
			con->arr[i].tel,
			con->arr[i].addr
		);
	}
}

5、查找通讯录数据

整体思路和前面的删除数据的辅助函数十分类似,或者直接可以使用上面的辅助函数。直接上代码:

void FindContact(contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名\n");
	scanf("%s", name);

	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("要查找的联系人数据不存在!\n");
		return;
	}
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	printf("%3s %3s %3d %3s %3s\n",
		con->arr[find].name,
		con->arr[find].sex,
		con->arr[find].age,
		con->arr[find].tel,
		con->arr[find].addr
	);
}

同样的代码没有任何问题。

6、修改指定数据

与删除数据时整体思路一致,直接上代码:

void ModifyContact(contact* con)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名\n");
	scanf("%s", name);

	int find = FindByName(con, name);
	if (find < 0)
	{
		printf("要查找的联系人数据不存在!\n");
		return;
	}
	//直接修改不用创建临时变量
	printf("请输入要修改的联系人姓名:\n");
	scanf("%s", con->arr[find].name);
	printf("请输入要修改的联系人性别:\n");
	scanf("%s", con->arr[find].sex);
	printf("请输入要修改的联系人年龄:\n");
	scanf("%d", &con->arr[find].age);
	printf("请输入要修改的联系人电话:\n");
	scanf("%s", con->arr[find].tel);
	printf("请输入要修改的联系人住址:\n");
	scanf("%s", con->arr[find].addr);

}

代码没有任何问题 

7、关于永久保存问题

以上所写的信息在退出程序后是无法保存的,要永久保存我们得使用文件操作函数来达到这个目的。

1、信息导入:

//从文件中读取数据
void LoadContact(contact* con) 
{
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL) {
		perror("fopen error!\n");
		return;
	}
	//循环读取⽂件数据
	PeoInfo info;
	while (fread(&info, sizeof(PeoInfo), 1, pf))
	{
		SLPushBack(con, info);
	}
	printf("历史数据导入通讯录成功!\n");
}

值得注意的一点是fread导入的是二进制文件所以我们是无法修改文件达到导入信息的目的

2、信息保存

void SaveContact(contact* con) 
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL) {
		perror("fopen error!\n");
		return;
	}
	//将通讯录数据写⼊⽂件
	for (int i = 0; i < con->size; i++)
	{
		fwrite(con->arr + i, sizeof(PeoInfo), 1, pf);
	}
	printf("通讯录数据保存成功!\n");
}

8、控制台的实现

#include"seqlisr.h"
//#include"contact.h"
void menu()
{
	printf("******************通讯录******************\n");
	printf("*******1.增加联系人   2.删除联系人********\n");
	printf("*******3.修改联系人   4.查找联系人********\n");
	printf("*******5.展示联系人   6.保存数据  ********\n");
	printf("*******7.导入数据     0.   退出  *********\n");
	printf("******************************************\n");
}

int main()
{
	int op = -1;
	contact con;
	InitContact(&con);

	do {
		menu();
		printf("请选择您的操作:\n");
		scanf("%d", &op);

		//要根据对应的op执行不同的操作
		switch (op)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DestroyContact(&con);
			break;
		case 3:
			ModifyContact(&con);
			break;
		case 4:
			FindContact(&con);
			break;
		case 5:
			ShowContact(&con);
			break;
		case 6:
			SaveContact(&con);
			break;
		case 7:
			LoadContact(&con);
			break;
		case 0:
			printf("退出通讯录....\n");
			break;
		default:
			printf("输入错误,请重新选择您的操作!\n");
			break;
		}
	} while (op != 0);

	DelContact(&con);
	return 0;
}

第一次运行: 

 第二次运行:

发现数据被永久保存了。 

总结:

通讯录是非常典型的顺序表使用示例,其最后的永久保存数据更是需要我们使用文件函数,代码总量也是非常大足足有400多行,需要大家好好消化。期待下一次和你们一起van♂。

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

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

相关文章

随机生成Long全范围数

随机生成Long全范围数 前言实现思路主要代码分区随机生成过程案例&#xff1a;随机生成100个数 朴素的比较总结 前言 使用自带的Random.nextLong()函数生成Long型的长整数&#xff0c;范围比较小&#xff0c;如下图。100个随机数没看见10以内的数字。所以考虑实现随机化生成大…

基于注意力整合的超声图像分割信息在乳腺肿瘤分类中的应用

基于注意力整合的超声图像分割信息在乳腺肿瘤分类中的应用 摘要引言方法 Segmentation information with attention integration for classification of breast tumor in ultrasound image 摘要 乳腺癌是世界范围内女性最常见的癌症之一。基于超声成像的计算机辅助诊断&#x…

scp和rsync

引言 我们平时总会有在不同的设备之间传输文件的需要&#xff0c;好友同事间可以用微信、QQ、网盘等&#xff0c;还是比较方便安全的。而在linux的操作系统中&#xff0c;我们经常需要两台机器之间拷贝文件&#xff0c;或者由于业务需要备份文件&#xff0c;那就不得不用到scp和…

【React】基于JS 3D引擎库实现关系图(图graph)

主角&#xff1a;3D Force-Directed Graph 简介&#xff1a;一个使用ThreeJS/WebGL进行3D渲染的Graph图库 GitHub: https://github.com/vasturiano/3d-force-graph Ps: 较为复杂或节点巨大时&#xff0c;对GPU>CPU消耗较大&#xff0c;同量级节点对比下优于AntV G6和Echarts…

C语言之分支语句和循环语句

前言 一、什么是语句&#xff1f; 二、分支语句&#xff08;选择结构&#xff09; 2.1 if语句 2.2 switch语句 三、循环语句 3.1 while循环 3.2 break与continue语句 3.3 getchar()与putchar() 3.3.1 缓冲区 3.4 for循环 3.4.1 一些for循环的变种 3.5 do...while循…

java运行时内存

从jdk1.7以及以后&#xff0c;静态变量和常量池存在堆空间。

【TSP旅行商问题】改进的大邻域搜索算法LNS

课题名称&#xff1a;基于改进的大规模邻域搜索算法LNS求解TSP问题 版本时间&#xff1a;2024-04-01 程序运行&#xff1a;直接运行LNS_TSP.m 文件即可 代码获取方式&#xff1a; QQ&#xff1a;491052175 VX&#xff1a;Matlab_Lover 模型介绍&#xff1a; 第一步&…

[AutoSar]BSW_Memory_Stack_004 创建一个简单NV block并调试

目录 关键词平台说明背景一、需求二、配置2.1 NvMBlockDescriptors2.2 NvMFeeRef2.3 FeeBlockConfigurations 三、code3.1 声明和定义3.2 调试 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector &#xff0c; EB芯片厂商TI 英飞凌编…

SpringBoot -- 外部化配置

我们如果要对普通程序的jar包更改配置&#xff0c;那么我们需要对jar包解压&#xff0c;并在其中的配置文件中更改配置参数&#xff0c;然后再打包并重新运行。可以看到过程比较繁琐&#xff0c;SpringBoot也注意到了这个问题&#xff0c;其可以通过外部配置文件更新配置。 我…

钉钉事件订阅前缀树算法gin框架解析

当钉钉监测到发生一些事件&#xff0c;如下图 此处举例三个事件user_add_org、user_change_org、user_leave_org&#xff0c;传统的做法是&#xff0c;我们写三个if条件&#xff0c;类似下图 这样字符串匹配效率比较低&#xff0c;于是联想到gin框架中的路由匹配算法&#xff0…

利用Spark将Kafka数据流写入HDFS

利用Spark将Kafka数据流写入HDFS 在当今的大数据时代&#xff0c;实时数据处理和分析变得越来越重要。Apache Kafka作为一个分布式流处理平台&#xff0c;已经成为处理实时数据的事实标准。而Apache Spark则是一个强大的大数据处理框架&#xff0c;它提供了对数据进行复杂处理…

Linux操作系统之nfs网络文件系统

目录 一、NFS简介 1.2 安装配置NFS 一、NFS简介 nfs类似于windows文件共享 将linux的一个目录共享到网络中&#xff0c;网络中的其他所有主机都可以使用这个共享目录中的文件 samba 文件共享 可以在linux中通过samba共享一个目录&#xff0c;然后在linux中可以访问这个共享 …

55 npm run serve 和 npm run build 的分包策略

前言 这里我们来看一下 vue 这边 打包的时候的一些 拆分包的一些策略 我们经常会使用到 npm run build 进行服务的打包 然后 打包出来的情况, 可能如下, 可以看到 chunk-vendors 是进行了包的拆分, 我们这里就是 来看一下 这里 npm run build 的时候的, 一个分包的策略 测试…

【HTML】简单制作一个唱片动画效果

目录 前言 开始 HTML部分 CSS部分 效果图 总结 前言 无需多言&#xff0c;本文将详细介绍一段代码&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建两个文本文档&#xff0c;其中HTML的文件名改为[index.html]&#xff0c;CSS的…

Matlab|储能辅助电力系统调峰的容量需求研究

目录 1 主要内容 目标函数 约束条件 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序参考文献《储能辅助电力系统调峰的容量需求研究》&#xff0c;主要是对火电、风电和储能等电力设备主体进行优化调度&#xff0c;在调峰能力达不到时采用弃负荷&#xff0c;程序以…

第十四届省赛大学B组(C/C++)子串简写

原题链接&#xff1a;子串简写 程序猿圈子里正在流行一种很新的简写方法&#xff1a; 对于一个字符串&#xff0c;只保留首尾字符&#xff0c;将首尾字符之间的所有字符用这部分的长度代替。 例如 internationalization 简写成 i18n&#xff0c;Kubernetes 简写成 K8s&#…

【贪玩巴斯】Mac的M芯片(M1/2...)下载homebrew方法(24年最新且已验证可行)

1. 按照目前广为流传的方法&#xff08;M1会出现一些问题&#xff09;&#xff1a; 终端输入&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 使用国内镜像下载。 2. 输入后按照要求步骤执行即可&#xff…

docker-compose运行springinitializr用来创建springboot2

前言 spring initializr官方的地址是: https://start.spring.io/ &#xff0c;这是一个用来创建springboot脚手架的一个工具&#xff0c;但是目前这个工具已经更新到springboot3&#xff0c;而我还没学springboot3&#xff0c;目前还想继续创建springboot2&#xff0c;我就想能…

如何预防自己网站被流量劫持?HTTPS加密是否可行?

如何预防自己网站被流量劫持&#xff1f;HTTPS加密是否可行&#xff1f; 文章背景&#xff1a; 所谓的流量劫持&#xff0c;就是利用各种恶意软件修改浏览器、锁定主页或不停弹出新窗口&#xff0c;强制用户访问某些网站&#xff0c;从而造成用户流量损失的情形。 流量劫持是一…

前端三剑客 —— CSS (第一节)

目录 CSS 什么是CSS CSS的几种写法&#xff1a; 行内样式 内嵌样式 外链样式 import 加载顺序 CSS选择器*** 基本选择器 ID选择器 标签选择器 类选择器 通用选择器 包含选择器 上节内容中提到了 前端三剑客 —— HTML 超文本标记语言&#xff0c;这节内容 跟大家…