动态顺序表实现通讯录

系列文章目录

【数据结构】顺序表


文章目录

  • 系列文章目录
  • 前言
  • 一、通讯录的功能要求
  • 二、通讯录的代码实现
    • 1. 新建文件
    • 2. 创建通讯录的结构体
    • 3. 对顺序表文件进行修改
    • 4. 通讯录具体功能实现
      • 4.1. 通讯录的初始化和销毁
      • 4.2. 增加联系人信息(尾插)
      • 4.3. 查找指定联系人(通过姓名查找)
      • 4.4. 删除指定联系人
      • 4.5. 修改指定联系人
      • 4.6. 显示联系人信息
  • 三、完整代码
  • 四、效果展示
  • 总结


前言

回顾上文,我们初步了解了顺序表,顺序表的本质就是数组,但相比于单纯的数组,顺序表多出了一些功能——增删查改。那么顺序表究竟有什么用呢?接下来为大家使用顺序表实现一个简易的通讯录。(使用动态顺序表实现)


正文开始

一、通讯录的功能要求

  1. 至少能够存储100个人的通讯信息
  2. 能够保存用户信息:名字、性别、年龄、电话、地址等
  3. 增加联系人信息
  4. 删除指定联系人
  5. 查找指定联系人
  6. 修改指定联系人
  7. 显示联系人信息

二、通讯录的代码实现

1. 新建文件

顺序表作为一种数据结构,只是一个工具,当我们要使用它去实现具体的东西时还需要对其进行包装。所以,我们这里在原来顺序表的基础上新建了两个文件——Contact.h和Contact.c。
在这里插入图片描述
Contact.h中存放通讯录所需的函数的声明和结构体的声明。
Contact.c中存放通讯录中函数的定义。

2. 创建通讯录的结构体

接下来我们就需要在Contact.h中创建一个通讯录的结构体,要包含的信息有:名字、性别、年龄、电话、地址。所以我们的顺序表中的元素的类型要是结构体,该结构体有5个成员。

#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 20typedef struct personinform
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}perinfo;

由于我们要实现通讯录,我们的顺序表的结构体的结构体名要更改为Contact,且要在该头文件中就要实现,因为后面有对应函数的声明,所以我们要在Contact.h中使用前置声明。

typedef struct Sepline Contact; // 只有前置声明才能更改顺序表的结构体名。

3. 对顺序表文件进行修改

我们在Contact.h中把套在顺序表上的外壳写完,我们还要对原来的顺序表进行小幅度修改,使其与我们要实现的功能匹配。
首先就要包含Contact.h这个头文件,然后将typedef后的int改为perinfo

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
typedef perinfo SLtype;
//动态顺序表
typedef struct Sepline
{SLtype* arr;int size;//有效数字大小int capacity;//动态内存大小
}SL;

最后,我们要将顺序表的函数实现进行修改,原本是实现int的,现在要改为实现结构体形式。

void SLshow(SL* sl)
{printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");for (int i = 0; i < sl->size; i++)printf("%3s  %3s  %3d  %3s  %3s\n", sl->arr[i].name, sl->arr[i].gender,sl->arr[i].age,sl->arr[i].tel,sl->arr[i].addr);
}

顺序表的修改和查找,我选择删除重新实现,要修改与重写没什么区别。

4. 通讯录具体功能实现

4.1. 通讯录的初始化和销毁

//初始化
void Con_init(Contact* con);//销毁
void Con_des(Contact* con);
void Con_init(Contact* con)
{SLinit(con);
}void Con_des(Contact* con)
{SLdestory(con);
}

这就是使用了顺序表后的情况,在具体实现函数时只需要套用之前的函数就可以了。

4.2. 增加联系人信息(尾插)

//插入(后插)
void Con_insert(Contact* con);
void Con_insert(Contact* con)
{perinfo x = { 0 };printf("请输入联系人姓名:");scanf("%s", x.name);printf("请输入联系人性别:");scanf("%s", x.gender);printf("请输入联系人年龄:");scanf("%d", &x.age);printf("请输入联系人电话:");scanf("%s", x.tel);printf("请输入联系人地址:");scanf("%s", x.addr);SL_in_back(con, x);
}

4.3. 查找指定联系人(通过姓名查找)

int Con_find_name(Contact* con, char name[]);
int Con_find_name(Contact* con, char name[])
{for (int i = 0; i < con->size; i++){if (0 == strcmp(name, con->arr[i].name))return i;}return -1;
}

4.4. 删除指定联系人

//指定删除
void Con_del(Contact* con);
void Con_del(Contact* con)
{char name[20];printf("请输入需要删除的联系人:");scanf("%s", name);int find = Con_find_name(con, name);if (find != -1){SLindel(con, find);printf("删除成功\n");}else{printf("需要删除的联系人不存在\n");}
}

4.5. 修改指定联系人

//修改
void Con_fix_name(Contact* con);
void Con_fix_name(Contact* con)
{char name[20];printf("请输入需要修改的联系人姓名:");scanf("%s", name);int find = Con_find_name(con, name);perinfo x = { 0 };printf("请输入修改后的姓名:");scanf("%s", x.name);printf("请输入修改后的性别:");scanf("%s", x.gender);printf("请输入修改后的年龄:");scanf("%d", &x.age);printf("请输入修改后的电话:");scanf("%s", x.tel);printf("请输入修改后的地址:");scanf("%s", x.addr);con->arr[find] = x;
}

4.6. 显示联系人信息

//展示
void Con_show(Contact* con);
void Con_show(Contact* con)
{SLshow(con);
}

这些通讯录的函数的实现基本都通过调用了顺序表的函数,大大减少了我们需要写的代码量,而且还不用考虑数据是如何增加,删除等。当然,前提是顺序表的函数没有写错。

三、完整代码

Contact.h

#pragma once#define NAME_MAX 20
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 20typedef struct personinform
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}perinfo;typedef struct Sepline Contact; // 只有前置声明才能更改顺序表的结构体名。//初始化
void Con_init(Contact* con);//销毁
void Con_des(Contact* con);//插入(后插)
void Con_insert(Contact* con);//指定删除
void Con_del(Contact* con);//展示
void Con_show(Contact* con);//查找
int Con_find_name(Contact* con, char name[]);//修改
void Con_fix_name(Contact* con);

Sepline.h

#pragma once
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "Contact.h"
typedef perinfo SLtype;
//动态顺序表
typedef struct Sepline
{SLtype* arr;int size;//有效数字大小int capacity;//动态内存大小
}SL;//顺序表初始化
void SLinit(SL* sl);//顺序表销毁
void SLdestory(SL* sl);//后插
void SL_in_back(SL* sl, SLtype x);//前插
void SL_in_front(SL* sl, SLtype x);//后删
void SL_out_back(SL* sl);//前删
void SL_out_front(SL* sl);//展示
void SLshow(SL* sl);//查找
int SLfind(SL* sl, SLtype n);//修改
void SLfix(SL* sl, int n);//指定位置增加
void SLinsert(SL* sl, int n, SLtype x);//指定位置删除
void SLindel(SL* sl, int n);//扩展空间
void SLapply(SL* sl);

Contact.c

#define _CRT_SECURE_NO_WARNINGS 1#include "Sepline.h"
#include "Contact.h"void Con_init(Contact* con)
{SLinit(con);
}void Con_des(Contact* con)
{SLdestory(con);
}void Con_insert(Contact* con)
{perinfo x = { 0 };printf("请输入联系人姓名:");scanf("%s", x.name);printf("请输入联系人性别:");scanf("%s", x.gender);printf("请输入联系人年龄:");scanf("%d", &x.age);printf("请输入联系人电话:");scanf("%s", x.tel);printf("请输入联系人地址:");scanf("%s", x.addr);SL_in_back(con, x);
}int Con_find_name(Contact* con, char name[])
{for (int i = 0; i < con->size; i++){if (0 == strcmp(name, con->arr[i].name))return i;}return -1;
}void Con_del(Contact* con)
{char name[20];printf("请输入需要删除的联系人:");scanf("%s", name);int find = Con_find_name(con, name);if (find != -1){SLindel(con, find);printf("删除成功\n");}else{printf("需要删除的联系人不存在\n");}
}void Con_show(Contact* con)
{SLshow(con);
}void Con_fix_name(Contact* con)
{char name[20];printf("请输入需要修改的联系人姓名:");scanf("%s", name);int find = Con_find_name(con, name);perinfo x = { 0 };printf("请输入修改后的姓名:");scanf("%s", x.name);printf("请输入修改后的性别:");scanf("%s", x.gender);printf("请输入修改后的年龄:");scanf("%d", &x.age);printf("请输入修改后的电话:");scanf("%s", x.tel);printf("请输入修改后的地址:");scanf("%s", x.addr);con->arr[find] = x;
}

Sepline.c

#define _CRT_SECURE_NO_WARNINGS 1#include"Sepline.h"
void SLinit(SL* sl)
{sl->arr = NULL;sl->size = sl->capacity = 0;
}void SLdestory(SL* sl)
{free(sl->arr);sl->arr = NULL;sl->size = sl->capacity = 0;
}void SLapply(SL* sl)
{if (sl->size == sl->capacity){sl->capacity = sl->capacity == 0 ? 4 : 2 * sl->capacity;SLtype* tmp = (SLtype*)realloc(sl->arr, sl->capacity * sizeof(SLtype));if (tmp == NULL){perror("realloc");exit(1);}sl->arr = tmp;tmp = NULL;}
}void SL_in_back(SL* sl, SLtype x)
{assert(sl);SLapply(sl);sl->arr[sl->size++] = x;
}void SL_in_front(SL* sl, SLtype x)
{assert(sl);SLapply(sl);for (int i = sl->size; i > 0; i--){sl->arr[i] = sl->arr[i - 1];}sl->arr[0] = x;sl->size++;
}void SL_out_back(SL* sl)
{assert(sl);assert(sl->size);sl->size--;
}void SLshow(SL* sl)
{printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");for (int i = 0; i < sl->size; i++)printf("%3s  %3s  %3d  %3s  %3s\n", sl->arr[i].name, sl->arr[i].gender,sl->arr[i].age,sl->arr[i].tel,sl->arr[i].addr);
}void SL_out_front(SL* sl)
{assert(sl);assert(sl->size);for (int i = 0; i < sl->size - 1; i++)sl->arr[i] = sl->arr[i + 1];sl->size--;
}//int SLfind(SL* sl, SLtype n)
//{
//	assert(sl);
//	//assert(n >= 0 && n < sl->size);
//	for (int i = 0; i < sl->size; i++)
//	{
//		if (n == sl->arr[i])
//			return i;
//	}
//	return -1;
//}//void SLfix(SL* sl, int n)
//{
//	assert(sl);
//	assert(n >= 0 && n < sl->size);
//	int num = 0;
//	printf("请输入修改后的数:");
//	scanf("%d", &num);
//	sl->arr[n] = num;
//}void SLinsert(SL* sl, int n, SLtype x)
{assert(sl);assert(n >= 0 && n <= sl->size);SLapply(sl);for (int i = sl->size; i > n; i--){sl->arr[i] = sl->arr[i - 1];}sl->arr[n] = x;sl->size++;
}void SLindel(SL* sl, int n)
{assert(sl);assert(n >= 0 && n < sl->size);for (int i = n; i < sl->size - 1; i++){sl->arr[i] = sl->arr[i + 1];}sl->size--;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "Sepline.h"
#include "Contact.h"void menu()
{printf("\n");printf("***********通讯录**********\n");printf("**** 1. 增加   2. 删除 ****\n");printf("**** 3. 查找   4. 展示 ****\n");printf("**** 5. 修改   0. 退出 ****\n");printf("***************************\n");
}
void test()
{Contact con;char name[20];int choose = 0;Con_init(&con);do{menu();printf("请输入你要进行的操作(输入前面数字):");scanf("%d", &choose);switch (choose){case 1: Con_insert(&con);break;case 2: Con_del(&con);break;case 3:printf("请输入你要查找的联系人姓名:");scanf("%s", name);int find = Con_find_name(&con, name);if (find < 0)printf("没找到\n");elseprintf("找到了,在第%d个\n", find);break;case 4: Con_show(&con);break;case 5: Con_fix_name(&con);break;case 0: printf("退出应用\n");break;default: printf("请输入0~6之间的数\n");break;}} while (choose);Con_des(&con);
}int main()
{test();return 0;
}

四、效果展示

增加联系人
在这里插入图片描述
修改联系人
在这里插入图片描述
删除联系人
在这里插入图片描述
展示联系人
在这里插入图片描述
查找联系人
在这里插入图片描述


总结

通讯录的实现实际十分简单,我们只要能熟练掌握顺序表的功能的实现,再在顺序表上套一个外壳就变成了通讯录。我们这个通讯录还有点小问题——无法一直保存数据。如果想要一直保存可以使用文件来操作,将每次修改的数据保存到一个文件里,每次进入程序先从该文件中读取数据,结束时将数据传回文件中。大家可以试着实现以下。
这里是我的解决方法:
test.c

void test()
{FILE* pf = fopen("Contact.txt", "r");Contact con;char name[20];int choose = 0;Con_init(&con);Con_insert_file(&con, pf);do{menu();printf("请输入你要进行的操作(输入前面数字):");scanf("%d", &choose);switch (choose){case 1: Con_insert(&con);break;case 2: Con_del(&con);break;case 3: printf("请输入你要查找的联系人姓名:");scanf("%s", name);int find = Con_find_name(&con, name);if (find < 0)printf("没找到\n");elseprintf("找到了,在第%d个\n", find);break;case 4: Con_show(&con);break;case 5: Con_fix_name(&con);break;case 0: printf("退出应用\n");break;default: printf("请输入0~6之间的数\n");break;}} while(choose);fclose(pf);pf = NULL;pf = fopen("Contact.txt", "w");for (int i = 0; i < con.size; i++){fprintf(pf, "%s %s %d %s %s\n",con.arr[i].name,con.arr[i].gender,con.arr[i].age,con.arr[i].tel,con.arr[i].addr);}fclose(pf);pf = NULL;Con_des(&con);
}

Contact.c

void Con_insert_file(Contact* con, FILE* pf)
{int ret = 0;int i = 0;while (ret != EOF){SLapply(con);ret = fscanf(pf, "%s %s %d %s %s",con->arr[i].name,con->arr[i].gender,&con->arr[i].age,con->arr[i].tel,con->arr[i].addr);if (ret != EOF){con->size++;i++;}}
}

Contact.h

//文件插入
void Con_insert_file(Contact* con, FILE* pf);

感谢观看!!!

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

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

相关文章

SpringBoot + 虚拟线程,性能炸裂!

一、什么是虚拟线程 虚拟线程是Java19开始增加的一个特性&#xff0c;和Golang的携程类似&#xff0c;一个其它语言早就提供的、且如此实用且好用的功能&#xff0c;作为一个Java开发者&#xff0c;早就已经望眼欲穿了。 二、虚拟线程和普通线程的区别 “虚拟”线程&#xf…

一些硬件知识(十二)

X电容是接在火线和零线之间&#xff0c;Y电容是接在火零线和地之间。X电容滤除差模干扰&#xff0c;Y电容滤除共模干扰&#xff1a; 高频干扰信号经过X电容后幅度没有变化&#xff0c;相位相差180度&#xff1a; DW01电池管理芯片&#xff1a; M1、M2&#xff1a;这两个为N沟道…

【关于C/C++中的scanf不能使用问题】

方法1&#xff1a;scanf_s 方法2&#xff1a;看见后面的日志了吗 CRT……&#xff1f;在第一行加上#define 日志 方法3&#xff1a;#pragma warning&#xff08;disable&#xff1a;4996&#xff09; 4996是我们的报错序号

开发笔记:vue3+ts+vant 卡片数据分页,下拉加载,卡片左滑可删除

效果&#xff1a; 实现 使用vantui组件 van-swipe-cell van-card &#xff08;商品卡片&#xff09; 核心代码 const currentPage ref(1) const pageSize ref(4) const totalSize ref(10) const loading ref(false) const finished ref(false) const refreshing ref(…

Git新仓库创建流程

平时需要创建新仓库,老要去查代码特别烦&#xff0c;在此写下流程方便备用. 1.创建新的云仓库 无论使用GitHub还是Gitee,首先要创建一个云仓库&#xff0c;这里就直接用国内的gitee做演示了&#xff0c;githup老挂加速器太烦&#xff0c;偷个懒. 我这里创建的是一个空仓库&…

Nginx主配置文件---Nginx.conf

nginx主配置文件的模块介绍 全局块&#xff1a; 全局块是配置文件从开始到 events 块之间的部分&#xff0c;其中指令的作用域是 Nginx 服务器全局。主要指令包括&#xff1a; user&#xff1a;指定可以运行 Nginx 服务的用户和用户组&#xff0c;只能在全局块配置。例如&…

软考《信息系统运行管理员》-2.2 信息系统运维的组织

2.2 信息系统运维的组织 信息系统运维的任务 数据资源管理 数据收集、数据校验、数据录入、数据处理 软件资源管理 采购、保存、相关文档保管、分发、安装、支持、评价、培训 硬件资源管理 检查、维护、故障处理、更新、修复、扩充 系统安全管理 可用性、完整性、保密性、可控…

USB PD+TYPE -C快充电源中MOSFET选型,USB PD应用市场包含智能手机,平板电脑,笔记本电脑,游戏本,移动硬盘,数码相机,电动工具等传统领域

USB PD全称为USB Power Delivery&#xff0c;是由USB-IF组织制定的一种快速充电协议&#xff0c;也是目前市场非常看好的一种协议&#xff0c;可以支持输出功率高达100W&#xff1b;Type-C是一种接口规范&#xff0c;能够支持传输更大的电流。USB PD应用市场不仅包含智能手机&a…

虚拟纪念展馆建设的重大意义:重新定义纪念活动的未来

一、什么是虚拟纪念展馆&#xff1f; 虚拟纪念展馆是一种利用3D、VR等技术在线展示历史事件、人物或文化遗产的数字化空间。这些展馆通过虚拟现实、增强现实和3D建模等技术手段&#xff0c;创建出身临其境的体验&#xff0c;使参观者可以在互联网上以互动方式探索和学习。 二、…

【FPGA 学习与实践】<初阶> 项目周计划

第1-2周&#xff1a;基础项目 - 4位加法器和计数器 目标&#xff1a;掌握Verilog基本语法和模块设计。 第1周&#xff1a; 学习Verilog的基本语法和结构&#xff08;模块、端口、数据类型&#xff09;。设计并实现一个4位加法器。编写测试平台&#xff08;Testbench&#xff0…

提升效率就靠它们啦

Hey小伙伴们&#xff5e;&#x1f44b; 知道你们都在忙碌的工作中寻求高效的秘诀&#xff0c;今天就给大家安利五款超实用的国产工作App&#xff0c;让你的工作生活更加得心应手哦&#xff01;&#x1f4bc;✨ 1️⃣【亿可达】 作为一款自动化工具&#xff0c;亿可达被誉为国内…

firewalld(5)--direct

简介 direct 是 firewalld 服务的一个功能&#xff0c;它允许用户以更直接的方式配置防火墙规则&#xff0c;绕过通常的 firewalld 区域&#xff08;zone&#xff09;和服务的抽象层。然而&#xff0c;这个功能已经被弃用&#xff08;deprecated&#xff09;&#xff0c;并将…

萌啦跨境工具箱有什么作用,萌啦跨境工具箱OZON营销神器

萌啦OZON数据平台&#xff0c;作为专为OZON平台商家打造的数据分析工具&#xff0c;集成了多种强大功能&#xff0c;旨在帮助商家在激烈的市场竞争中获得数据驱动的优势&#xff0c;实现精准运营与高效增长。那么萌啦跨境工具箱有什么作用&#xff1f;接下来介绍萌啦跨境工具箱…

全面升级厨房安全,电焰灶引领新时代

煤气是许多家庭日常使用的能源&#xff0c;目前的普及率还是比较高的&#xff0c;但平时因煤气泄漏而引发的事故也很多&#xff0c;只需要查看最近一个月因液化气泄漏引起的爆炸事件屡见不鲜。打开新闻&#xff0c;我们总能时不时看到煤气爆炸的事故&#xff0c;幸运的能够逢凶…

ubuntu 安装并启用 samba

环境&#xff1a;ubuntu server 24.04 步骤如下&#xff1a; sudo apt update sudo apt install samba修改配置文件&#xff1a; sudo vi /etc/samba/smb.conf新增内容&#xff1a; [username]path /home/[username]available yesvalid users [username]read only nobrow…

[Information Sciences 2023]用于假新闻检测的相似性感知多模态提示学习

推荐的一个视频&#xff1a;p-tuning P-tunning直接使用连续空间搜索 做法就是直接将在自然语言中存在的词直接替换成可以直接训练的输入向量。本身的Pretrained LLMs 可以Fine-Tuning也可以不做。 这篇论文也解释了为什么很少在其他领域结合知识图谱的原因&#xff1a;就是因…

Android SQLite 数据库存学习与总结

Android 系统内置了一个名为 SQLite 数据库。那么 SQLite 是一种什么样的数据库&#xff0c;它有那些特点&#xff0c;应该怎么操作它&#xff1f;下面&#xff0c;让我们就来认识一下它吧。 1、概念&#xff1a; SQLite 是一种轻量级的关系型数据库&#xff0c;它不仅支持标准…

elementPlus自定义el-select下拉样式

如何在f12元素选择器上找到下拉div呢&#xff1f; 给el-select添加 :popper-append-to-body"false" 即可&#xff0c;这样就可以将下拉框添加到body元素中去&#xff0c;否则当我们失去焦点&#xff0c;下拉就消失了&#xff0c;在元素中找不到el-select。剩下就可以…

怎么压缩图片大小?6种无需牺牲质量的图片压缩方法

经常处理图片的小伙伴都知道&#xff0c;高质量的图片往往会占据电脑大量的存储空间&#xff0c;导致图片传输及存储的不便。因此&#xff0c;掌握如何压缩图片大小变得尤为重要。本文将详细介绍图片压缩的几种方法&#xff0c;帮助你高效地减小图片文件大小&#xff0c;让你的…

【.Net】Web项目部署腾讯云

文章目录 总述前置准备docker-compose部署普通部署 参考 总述 前置准备 云服务添加端口 另有linux本身防火墙请参考&#xff1a; 【Linux】防火墙命令 需安装.Net SDK和Asp .Net Runtime 注意&#xff1a; 1、sdk也要不只是runtime 2、是Asp .Net Runtime不是.Net Runtime …