探索C语言数据结构:利用顺序表完成通讯录的实现

在好久之前我就已经学习过顺序表,但是在前几天再次温习顺序表的时候,我惊奇的发现顺序编表可以完成我们日常使用的通讯录的功能,那么今天就来好好通过博客总结一下通讯录如何完成吧。

常常会回顾努力的自己,所以要给自己的努力留下足迹。

为今天努力的自己打个卡,留个痕迹吧

                                                                                                        2024.04.20     小闭


顺序表

顺序表在好久之前就已经写过一篇博客了,如果没了解过顺序表的佬,可以先去了解一下唔。传送门:http://t.csdnimg.cn/DhcZ7icon-default.png?t=N7T8http://t.csdnimg.cn/DhcZ7

了解过顺序表的就可以跟着往下看看如何使用顺序表来实现通讯录,下面先给大家展示一下顺表的C语言代码,不然等下就对通讯录的一些知识点给搞迷糊了。

顺序表是我们对数据进行管理的一种简单结构,他的底层就是数组,这里我们对数组进行封装就形成了我们的通讯录。

顺序表的头文件 "SL.h"

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include"Contact.h"

typedef struct Contact Datetype;

struct SEQlist
{
	Datetype*  a;
	int size;
	int capacity;

};





typedef struct SEQlist SL;
void Init(SL* s);
void Print(SL* s);
void pushFront(SL* s, Datetype x);

void INti(SL* s);
void tCheckCapacity(SL* s);
void SeqListPushBack(SL* s, Datetype x);
void SeqListPopBack(SL* s);
void SeqListPushFront(SL* s, Datetype x);
void SeqListPopFront(SL s);
void SeqListDestory(SL* s);
void SeqListinsert(SL* s, int pos,Datetype x);
void SeqListdel(SL* s, int pos);

顺序表的“.c”文件SL.c 

#define _CRT_SECURE_NO_WARNINGS 1
#include "SL.h"

//void Print(SL* s)
//{
//	for (int i = 0; i < s->size; i++)
//	{
//		printf("%d ", s->a[i]);
//	}
//	printf("\n");
//}




void Init(SL* s)
{

	s->a = NULL;
	s->size = 0;         // 表示数组中存储了多少个数据
	s->capacity = 0;   数组实际能存数据的空间容量是多大 


}

void CheckCapacity(SL* s)
{
	// 如果没有空间或者空间不足,那么我们就扩容
	if (s->size == s->capacity)
	{
		int newcapacity = s->capacity == 0 ? 4 : s->capacity * 2;
		Datetype* tmp = (Datetype*)realloc(s->a, newcapacity * sizeof(Datetype));
		if (tmp == NULL)
		{
			printf("realloc 失败\n");
			exit(-1);
		}

		s->a = tmp;
		s->capacity = newcapacity;
	}
}


void SeqListPushBack(SL* s, Datetype x)
{
	CheckCapacity(s);

	s->a[s->size] = x;
	s->size++;
}

void SeqListPopBack(SL* s)
{

	// 暴力处理方式
	assert(s->size > 0);
	s->size--;
}


void SeqListPushFront(SL* s, Datetype x)
{
	CheckCapacity(s);

	// 挪动数据
	int end = s->size - 1;
	while (end >= 0)
	{
		s->a[end + 1] = s->a[end];
		--end;
	}
	s->a[0] = x;
	s->size++;
}

void SeqListPopFront(SL* s)
{
	assert(s->size > 0);

	// 挪动数据
	int begin = 1;
	while (begin < s->size)
	{
		s->a[begin - 1] = s->a[begin];
		++begin;
	}

	s->size--;
}


void SeqListDestory(SL* s)
{
	free(s->a);
	s->a = NULL;
	s->capacity = s->size = 0;
}


void SeqListinsert(SL* s,int pos, Datetype x)
{

	assert(s);
	assert(pos >= 0 && pos<=s->size);
	CheckCapacity(s);

	for (int i = s->size; i > pos; i--)
	{
		s->a[i] = s->a[i - 1];

	}
	s->a[pos] = x;
	s->size++;

}


void SeqListdel(SL* s, int pos)
{

	assert(s);
	assert(pos >= 0 && pos < s->size);

	for (int i = pos; i < s->size-1; i++)
	{
		s->a[i] = s->a[i + 1];
	}
	
	
	s->size--;

}

 上面的两段代码包含了顺序表的,格式化,销毁,头插,尾插,头删,尾删,指定位置插入。


通讯录的实现

首先我们要知道通讯录里有什么?我们当然知道里面有联系人的姓名,性别,年龄,电话,地址。

我们假设这个通讯录就储存这么些信息,那我们这些信息是不是我们所说的数据,前面我们往顺序表里储存的是整形数据那么现在我们数据类型改为这些信息不就好了,可能有人就会想这些信息有那么多,那我们的数据变量要一个一个建立出来吗?当然不是,代码要求的是简便,既然这些信息可能是不同数据类型,而且还不少,那么我们就可以用一个自定义类型-----结构体来作为数据类型的变量,然后结构体内部就可以储存这些信息,这样一来就简单多了。如下图所示:


有了大概的思路,然后就开始封装顺序表,然后就让它成为一个成熟的通讯录。

创建通讯录的信息结构体和通讯录节点

具体思路:首先我们在建立两个文件一个“Contact.c”,“Contact.h”文件,其中在“Contact.h”文件里定义好储存联系人信息的结构体和声明函数和头文件,

“Contact.h”

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#define MAX_NAME 18
#define MAX_TEL 18
#define MAX_GENDER  10
#define MAX_ADDR 100



typedef struct Contact
{
	char name[MAX_NAME];
	char gender[MAX_GENDER];
	int age;
	char tel[MAX_TEL];
	char addr[MAX_ADDR];

}con;

typedef struct SEQlist Ct;

//通讯录的初始化
void ContactInit(Ct* pf);

//通讯录的销毁
void ContactDestory(Ct* pf);

//通讯录数据的添加
void ContactAdd(Ct* pf);

//通讯录数据的删除
void ContactDel(Ct* pf,char arr[]);

//通讯录的展示
void ContactShow(Ct* pf);

//通讯录的查找
void ContactFind(Ct* pf,char arr[]);

 这里我们加了一个typedef struct SEQLIST Ct;是为了让人一眼看出这是通讯录而不是一个普通的顺序表,也让我们能够好理解一些。

以及在“Contact.c”文件里写下完成通讯录的一些基本功能的代码。

那么我们可以写的通讯录功能有哪些呢?

通讯录的格式化

void ContactInit(Ct* pf)
{
	Init(pf);

}
void Init(SL* s)
{

	s->a = NULL;
	s->size = 0;         // 表示数组中存储了多少个数据
	s->capacity = 0;   数组实际能存数据的空间容量是多大 


}

 

其实这里的格式化就是将顺序表给格式化,会先将结构体数组a给赋为NULL,然后将容量

(int capacity)和有效数据数目(int size)置为0 

通讯录的销毁

void ContactDestory(Ct* pf)
{

	SeqListDestory(pf);

}
void SeqListDestory(SL* s)
{
	free(s->a);
	s->a = NULL;
	s->capacity = s->size = 0;
}

 通讯录的销毁也是一样的,直接调用链表的销毁就好了

通讯录数据的添加

void ContactAdd(Ct* pf)
{

	assert(pf);
	struct Contact a;
	printf("请输入你要添加联系人的姓名\n");
	scanf("%s", a.name);

	printf("请输入你要添加联系人的性别\n");
	scanf("%s", a.gender);

	printf("请输入你要添加联系人的年龄\n");
	scanf("%d", &(a.age));

	printf("请输入你要添加联系人的电话\n");
	scanf("%s", a.tel);

	printf("请输入你要添加联系人的地址\n");
	scanf("%s", a.addr);

	//往联系人里添加数据
	 SeqListPushBack(pf, a);

}
void SeqListPushBack(SL* s, Datetype x)
{
	CheckCapacity(s);

	s->a[s->size] = x;
	s->size++;
}

 因为要添加数据,那我们首先就需要获取这个数据,这里我们运用scanf来进行获取数据放到我们用来储存数据的结构体(struct Contact)中,然后再运用链表的尾插功能,将数据添加到我们的顺序表中。

通讯录数据的删除

我们要删除通讯录里的联系人,首先就得核对通讯录里是否有我们操作者想要删除的人,所以这里我们在写一个函数来进行找人,如果找到此人则返回此人在数组a的下标。,没有则打印“未找到该联系人”,并返回-1;然后在ContactDel中进行一下判断是否为-1,如果不为-1,就执行链表中的指定位置删除

//找到某位联系人的位置
int Findname(Ct* pf,char arr[])
{
	assert(pf);
	int i = 0;
	for (i = 0; i < pf->size; i++)
	{
		if (strcmp(arr, pf->a[i].name) == 0)
		{
			return i;

		}

	}
	printf("未找到该联系人\n");


}
//删除联系人
void ContactDel(Ct* pf)
{
	assert(pf);
	int arr[MAX_NAME];
	scanf("%s", arr);
	printf("请输入你要删除的联系人: ");

	int find=Findname(pf,arr);
	if (find != -1)
	{
		SeqListdel(pf, find);
	}

	
}

 

void SeqListdel(SL* s, int pos)
{

	assert(s);
	assert(pos >= 0 && pos < s->size);

	for (int i = pos; i < s->size-1; i++)
	{
		s->a[i] = s->a[i + 1];
	}
	
	
	s->size--;

}

 

通讯录的查找

这里我们scanf输入想要查找的联系人,调用查找函数返回得到该联系人的下标,之后再打印出来即可。

//找到某位联系人的位置
int Findname(Ct* pf,char arr[])
{
	assert(pf);
	int i = 0;
	for (i = 0; i < pf->size; i++)
	{
		if (strcmp(arr, pf->a[i].name) == 0)
		{
			return i;

		}

	}
	printf("未找到该联系人\n");


}
void ContactFind(Ct* pf)
{
	assert(pf);
	char arr[MAX_NAME];
	printf("请输入你要查找的联系人: ");
	scanf("%s", arr);
	int find=Findname(pf,arr);

	if (find != -1)
	{
		printf("找到该联系人了,其信息如下:\n");
		printf("姓名    性别     年龄     电话       地址\n");
		printf("%s      %s       %d        %s         %s",
		pf->a[find].name, pf->a[find].gender, pf->a[find].age, pf->a[find].tel, pf->a[find].addr);

	}

 

通讯录的展示

这里就是遍历顺序表,将每个数据给打印出来,只要注意打印格式即可,想要美观可以调好打印的距离。


//通讯录的展示
void ContactShow(Ct* pf)
{

	assert(pf);
	int i = 0;

	for (i = 0; i < (pf->size); i++)
	{
		printf("姓名    性别     年龄     电话       地址\n");
		printf("%s      %s       %d        %s         %s\n",
			pf->a[i].name, pf->a[i].gender, pf->a[i].age, pf->a[i].tel, pf->a[i].addr);


	}


}


可能有人会问,我储存的数据程序一结束,数据就不见了,这还叫通讯录吗?这样确实显得这个通讯录有点鸡肋,所以我们现在就可以再写一个函数,将数据放到文本文件中进行储存

void SaveContact(Ct* 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->a + i, sizeof(PeoInfo), 1, pf);
 }
 printf("通讯录数据保存成功!\n");
}

当然这里是以二进制文件储存的。 

这些功能都是在“Contact.c”里来完成的。


常常会回顾努力的自己,所以要给自己的努力留下足迹。

为今天努力的自己打个卡,留个痕迹吧

                                                                                                        2024.04.20     小闭
 

                          

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaSE】浅谈Java异常

前言 本篇文章是对Java异常体系相关内容及部分注意事项的的讲解。 一. 认识异常 在每个人的生命历程中&#xff0c;或多或少都会遇到生病或受伤的情况&#xff0c;比如&#xff1a;皮肤擦伤、感冒、发烧、患上某些传染病等等。不管“病情”严重与否&#xff0c;这些都可以算…

数据链路层协议——以太网协议

目录 要解决的问题 以太网协议 以太网帧格式 MAC地址 MAC地址和IP地址 MTU MTU对IP协议的影响 MTU对UDP协议的影响 MTU对TCP协议的影响 ARP协议 ARP协议格式 ARP协议的工作流程 ARP缓存表 要解决的问题 上一篇我们也说了&#xff0c;数据从应用层一步步封装到了网…

leetcode:滑动窗口----3. 无重复字符的最长子串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长 子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为…

工业现场ModbusTCP转EtherNETIP网关引领生物现场领新浪潮

生物质发生器是一种能够产生、培养生物的设备。客户现场需要将生物发生器连接到罗克韦尔系统&#xff0c;但是二者协议无法直接通讯&#xff0c;需要通过开疆智能ModbusTCP转Ethernet/IP网关将两者进行通讯连接&#xff0c;生物质发生器以其独特的工作原理和优势&#xff0c;使…

【命名空间详解】c++入门

目录 命名空间的定义 1.命名空间的正常定义 2.命名空间还可以嵌套 3. 命名空间可以合并 命名空间的使用 1.加命名空间名称及作用域限定符 2.使用using将命名空间中某个成员引入 3.使用using namespace 命名空间名称 引入 输入&#xff0c;输出 输出 命名空间的定义 …

[阅读笔记21][RA-CM3]Retrieval-Augmented Multimodal Language Modeling

这篇论文是meta联合斯坦福在23年4月发表的论文&#xff0c;提出了一个使用外部知识检索增强的多模态模型。 这篇模型提出的RA-CM3模型是第一个能够检索并生成图像文本的多模态模型&#xff0c;在图像文本生成任务上优于现有的多模态模型&#xff0c;同时使用更少的训练量。 RA-…

在PostgreSQL中如何处理大对象(Large Objects),例如存储和检索二进制文件?

文章目录 存储二进制文件为大对象步骤 1&#xff1a;创建一个大对象步骤 2&#xff1a;写入数据到大对象 检索大对象为二进制文件步骤 1&#xff1a;打开大对象以进行读取步骤 2&#xff1a;从大对象读取数据 注意事项 PostgreSQL 提供了对大对象&#xff08;Large Objects&…

【多线程学习】深入探究阻塞队列与生产者消费者模型和线程池常见面试题

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

【vue】el-tree的新增/编辑/删除节点

1、概述 关于树形结构的新增同级节点&#xff0c;新增子级节点&#xff0c;修改节点名称&#xff0c;删除节点等四种操作&#xff0c;各种参数配置完全继承el-tree&#xff0c;本篇使用vue2 element-ui 2、效果图展示 3、调用方式 <template><Tree:data"tree…

上位机图像处理和嵌入式模块部署(树莓派4b和视觉slam十四讲)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 实际使用中&#xff0c;树莓派4b是非常好的一个基础平台。本身板子价格也不是很贵&#xff0c;建议大家多多使用。之前关于vslam&#xff0c;也就是…

CSS display属性

目录 概述&#xff1a; 设置display示例&#xff1a; none&#xff1a; block&#xff1a; inline&#xff1a; inline-block &#xff1a; 概述&#xff1a; 在CSS中我们可以使用display属性来控制元素的布局&#xff0c;我们可以通过display来设置元素的类型。 在不设置…

webpack源码分析——enhanced-resolve库之getType、normalize、join和cachedJoin函数

一、PathType 路径类型 const PathType Object.freeze({Empty: 0, // 空Normal: 1, // 默认值Relative: 2, // 相对路径AbsoluteWin: 3, // win 下的绝对路径AbsolutePosix: 4, // posix 下的绝对路径Internal: 5 // enhanced-resolve 内部自定义的一种类型&#xff0c;具体是…

Redis:报错Creating Server TCP listening socket *:6379: bind: No error

错误&#xff1a; window下启动redis服务报错&#xff1a; Creating Server TCP listening socket *:6379: bind: No error 原因&#xff1a; 端口6379已被绑定&#xff0c;应该是因为上次未关闭服务 解决&#xff1a; ①依次输入命令&#xff1a; redis-cli.exe &#xff08…

IntelliJ IDEA运行发布传统Java Web Application项目

接 重温8年前项目部署 要求&#xff0c;如何改用IntelliJ IDEA运行发布传统 Java Web Application项目呢&#xff0c;简述步骤如下&#xff1a; 一、下载源码 源码&#xff1a;https://github.com/wysheng/kindergarten 下载后的本地项目路径&#xff1a;/Users/songjianyon…

前后端跨域请求代码实战(vue3.4+springboot2.7.18)

前端代码 v3.4.21&#xff08;前端不是主业&#xff0c;所以就贴一贴代码&#xff0c;有疑问评论区见&#xff09;后端代码&#xff0c;springboot 2.7.18&#xff08;后端&#xff09; 文章内容&#xff1a; 一&#xff0c;后端代码 二&#xff0c;前端代码 三&#xff0c;后…

安全开发实战(1)--Cdn

目录 安全开发专栏 CDN介绍 1.信息收集阶段 1.1判断CDN是否存在 1.1.1, One 1.1.2,Two(改进) 1.1.3,进行整合 增加输入功能 1.1.4 批量读取监测存储(进行测试) 问题1: 问题2: 解决方案: 1.1.4 基本编写完成 命令框中: cdn存在.txt 总结 这里我是根据整个渗透测…

个人网页地址发布页面源码

源码介绍 个人网页地址发布页面源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 效果预览 源码下载 个人网页地址发布页面源码

利用搞笑电影,引爆中年圈,日入2000+,短视频最新变现玩法,适合0基础小白

大家好&#xff0c;今天要分享的项目是“通过搞笑电影吸引中年群体&#xff0c;实现日收入2000的短视频变现新策略&#xff0c;适合零基础新手”。该项目着眼于利用搞笑电影内容来吸引中年观众&#xff0c;这是一个相对未被充分开发的市场领域&#xff0c;竞争较少。与其他热门…

香港服务器_免备案服务器有哪些正规的?企业、建站方向

香港服务器&#xff0c;是最受欢迎的外贸、企业建站服务器&#xff0c;在个人建站领域&#xff0c;香港服务器、香港虚拟主机都是首选的网站服务器托管方案&#xff0c;不仅其具备免备案的特点&#xff0c;而且国内外地区访问速度都很快。那么&#xff0c;现今2024年个人和企业…

企业监管工具:为何如此重要?

随着通信技术的发展&#xff0c;员工使用微信等即时通讯工具来进行工作沟通已经成为了常态。为了帮助企业有效地监管员工的工作微信使用情况&#xff0c;微信管理系统应运而生。 下面就一起来看看&#xff0c;它都有哪些功能吧&#xff01; 1、历史消息&#xff1a;洞察员工聊…