动态顺序表实现通讯录

系列文章目录

【数据结构】顺序表


文章目录

  • 系列文章目录
  • 前言
  • 一、通讯录的功能要求
  • 二、通讯录的代码实现
    • 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;偷个懒. 我这里创建的是一个空仓库&…

java- Lambda表达式的实际应用

### 12. Lambda 表达式的实际应用 为了更好地理解和应用 Lambda 表达式&#xff0c;我们可以通过一些实际案例来展示其用法和优势。 #### 12.1 使用 Lambda 表达式进行事件处理 在 GUI 编程中&#xff0c;事件处理是一个常见的任务。使用 Lambda 表达式可以简化事件处理代码…

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;并将…

详解位运算(、|、^、^、>>、<<)

十六进制与二进制对应关系 十六进制和二进制之间的转换非常直接&#xff0c;每个十六进制数字直接对应四个二进制位&#xff0c;并且十六进制相对二进制要更加简洁&#xff0c;因此通常书写位操作的代码时会选择使用十六进制来表示数值。 为了方便快速阅读涉及位运算的源码&a…

深入探索Scala的类型推断机制

引言 Scala是一种静态类型编程语言&#xff0c;以其强大的类型推断系统而闻名。类型推断允许开发者在很多情况下省略显式的类型声明&#xff0c;从而编写更简洁、更少出错的代码。本文将深入探讨Scala的类型推断是如何实现的&#xff0c;以及它如何帮助提高开发效率和代码可读…

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

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

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

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

代码随想录算法训练营day70 | 108. 冗余连接、109. 冗余连接II

本次题目都来自卡码网 108. 冗余连接 无向图&#xff0c;返回一条可以删去的边&#xff0c;使得结果图是一个有着N个节点的树&#xff08;即&#xff1a;只有一个根节点&#xff09;。 从前向后遍历每一条边&#xff08;因为优先让前面的边连上&#xff09;&#xff0c;边的…

【2024LLM应用-数据预处理】之如何从PDF,PPT等非结构化数据提取有效信息(结构化数据JSON)?

&#x1f970;大家知道吗,之前在给AI大模型"喂数据"的时候,我们往往需要把非结构化数据(比如PDF、PPT、Excel等)自己手动转成结构化的格式,这可真是太累人儿了。&#x1f975; 幸好现在有了Unstructured这个神级库,它内置的数据提取函数可以帮我们快速高效地完成这个…

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…