当前位置: 首页 > news >正文

基于动态顺序表实现通讯录项目

 本文中,我们将使用顺序表的结构来完成通讯录的实现。

我们都知道,顺序表实际上就是一个数组。而使用顺序表来实现通讯录,其内核是将顺序表中存放的数据类型改为结构体,将联系人的信息存放到结构体中,通过对顺序表的操作来访问通讯录。

所以我们可以将通讯录理解为套壳的顺序表。

一、功能

(1)能够保存联系人的姓名、年龄、性别、电话、住址

(2)添加联系人信息

(3)删除联系人信息

(4)修改联系人信息

(5)查找联系人信息

(6)查看通讯录中所有联系人信息

(7)清空通讯录

(8)每次加载通讯录时自动载入历史通讯录,退出通讯录后自动保存通讯录信息

二、代码实现

实现通讯录我们要创建6个文件来实现不同的部分

  • SeqList.h:顺序表定义、头文件引用和顺序表接口函数的声明
  • SeqList.c:顺序表接口函数的实现
  • Contact.h:信息结构体的定义和通讯录函数的声明
  • Contact.c:通讯录函数的实现
  • test.c:界面设计和通讯录主函数实现
  • contact.txt:在同目录下创建,用来保存通讯录数据实现读档存档

(1) SeqList.h 

在实现通讯录函数的时候我们可以套用顺序表的接口函数减少工作量,但是并不是所有顺序表的函数都会用到。下面展示SeqList.h的代码:

#pragma once#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <Windows.h>
#include "Contact.h"typedef Info SLDataType; //顺序表元素种类为存放个人信息的结构体typedef struct SeqList
{SLDataType* a;size_t size;size_t capicity;
} SeqList;// 顺序表初始化
void SeqListInit(SeqList* psl);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);

(2) SeqList.c 

SeqList.c的代码如下:

#include "SeqList.h"void SeqListDestory(SeqList* psl)
{assert(psl);free(psl->a);psl->a = NULL;psl->capicity = 0;psl->size = 0;
}void SeqListInit(SeqList* psl)
{assert(psl);psl->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);if (psl->a == NULL){perror("malloc fail");return;}psl->size = 0;psl->capicity = 4;
}void CheckCapacity(SeqList* psl)
{assert(psl);if (psl->size == psl->capicity){SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType) * psl->capicity * 2);if (tmp == NULL){perror("realloc fail");return;}psl->a = tmp;psl->capicity *= 2;}
}void SeqListPushBack(SeqList* psl, SLDataType x)
{assert(psl);CheckCapacity(psl);psl->a[psl->size++] = x;
}void SeqListErase(SeqList* psl, size_t pos)
{assert(psl);assert(0 <= pos && pos < psl->size);while (pos < psl->size - 1){psl->a[pos] = psl->a[pos + 1];pos++;}psl->size--;
}

因为二者在前面的顺序表学习中已经写过了,所以直接cv即可

(3) test.c

在实现通讯录函数之前,我们先把通讯录界面和主函数搞定

创建好test.c后,先包含一下头文件

#include "SeqList.h"

再设计一下界面

#include "SeqList.h"void Menu()
{printf("****************通讯录******************\n");printf("****** 1.添加联系人  2.删除联系人 ******\n");printf("****** 3.修改联系人  4.查找联系人 ******\n");printf("****** 5.查看通讯录  6.清空通讯录 ******\n");printf("****** 0.退出通讯录               ******\n");printf("****************************************\n");
}

主函数如下:

int main()
{contact con;InitContact(&con); //初始化通讯录LoadContact(&con); //加载历史通讯录int option = -1;do {Menu();printf("请选择:\n");scanf("%d", &option);system("cls"); //适当的清屏看起来更简洁switch (option){case 1://添加联系人AddContact(&con);break;case 2://删除联系人DelContact(&con);break;case 3://修改联系人ModifyContact(&con);break;case 4://查找联系人FindContact(&con);break;case 5://查看通讯录ShowContact(&con);break;case 6://清空通讯录ClearContact(&con);break;case 0://退出通讯录printf("通讯录退出中...\n");break;default:printf("非法操作,请重新输入\n");break;}} while (option);SaveContact(&con); //保存通讯录DestoryContact(&con); //销毁通讯录return 0;
}

(4) Contact.h

界面和主函数都搞定后,我们开始完成通讯录函数并逐个填空到主函数中

下面是Contact.h的代码

#pragma once#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 11
#define ADDR_MAX 100struct SqeList; 
//因为这里不能声明SeqList.h,不然会造成嵌套声明,所以就单独声明一下顺序表typedef struct SeqList contact;
//要实现的是通讯录,所以得把顺序表换个名,但换汤不换药typedef struct PersonInfo
{char name[NAME_MAX];      //姓名int age;                  //年龄char gender[GENDER_MAX];  //性别char telephone[TEL_MAX];  //电话char address[ADDR_MAX];   //住址
}Info;void InitContact(contact* pcon);//初始化通讯录void DestoryContact(contact* pcon);//销毁通讯录int FindByName(contact* pcon, char* name);//通过姓名查找联系人void AddContact(contact* pcon);//添加联系人void DelContact(contact* pcon);//删除联系人void ModifyContact(contact* pcon);//修改联系人信息void FindContact(contact* pcon);//查找联系人void ShowContact(contact* pcon);//展示联系人列表void ClearContact(contact* pcon);//清空通讯录void SaveContact(contact* pcon);//保存通讯录void LoadContact(contact* pcon);//载入历史通讯录

(5) Contact.c

接下来我们展示Contact.c的完整代码

#include "SeqList.h"void InitContact(contact* pcon)//初始化通讯录
{SeqListInit(pcon);
}void DestoryContact(contact* pcon)//销毁通讯录
{SeqListDestory(pcon);
}int FindByName(contact* pcon, char* name)//通过姓名查找联系人
{for (size_t i = 0; i < pcon->size; i++){if (strcmp(name, pcon->a[i].name) == 0){return i;}}return -1;
}void AddContact(contact* pcon)//添加联系人
{CheckCapacity(pcon);printf("请输入姓名:\n");scanf("%s", pcon->a[pcon->size].name);printf("请输入年龄:\n");scanf("%d", &(pcon->a[pcon->size].age));printf("请输入性别:\n");scanf("%s", pcon->a[pcon->size].gender);printf("请输入电话:\n");scanf("%s", pcon->a[pcon->size].telephone);printf("请输入住址:\n");scanf("%s", pcon->a[pcon->size].address);pcon->size++;system("cls");printf("添加成功!\n");
}void DelContact(contact* pcon)//删除联系人
{char name[100];printf("请输入要删除的联系人:\n");scanf("%s", name);int index = FindByName(pcon, name);if (index == -1){printf("要删除的用户不存在!\n");return;}SeqListErase(pcon, index);system("cls");printf("删除成功!\n");
}void ModifyContact(contact* pcon)//修改联系人信息
{char name[100];printf("请输入要修改的联系人:\n");scanf("%s", name);int index = FindByName(pcon, name);if (index == -1){printf("要修改的用户不存在!\n");return;}printf("请输入修改后的姓名:\n");scanf("%s", pcon->a[index].name);printf("请输入修改后的年龄:\n");scanf("%d", &(pcon->a[index].age));printf("请输入修改后的性别:\n");scanf("%s", pcon->a[index].gender);printf("请输入修改后的电话:\n");scanf("%s", pcon->a[index].telephone);printf("请输入修改后的住址:\n");scanf("%s", pcon->a[index].address);system("cls");printf("修改成功!\n");
}void FindContact(contact* pcon)//查找联系人
{char name[100];printf("请输入要查找的联系人:\n");scanf("%s", name);int index = FindByName(pcon, name);if (index == -1){printf("要查找的用户不存在!\n");return;}system("cls");printf("查找成功!\n");printf("姓名:%s\n", pcon->a[index].name);printf("年龄:%d\n", pcon->a[index].age);printf("性别:%s\n", pcon->a[index].gender);printf("电话:%s\n", pcon->a[index].telephone);printf("住址:%s\n", pcon->a[index].address);
}void ShowContact(contact* pcon)//展示联系人列表
{if (pcon->size == 0){printf("通讯录为空!\n");return;}printf("姓名 年龄 性别 电话 地址\n");for (size_t i = 0; i < pcon->size; i++){printf("%s %d %s %s %s\n",pcon->a[i].name,pcon->a[i].age,pcon->a[i].gender,pcon->a[i].telephone,pcon->a[i].address);}
}void ClearContact(contact* pcon)//清空通讯录
{pcon->size = 0;printf("通讯录清空成功!\n");
}void SaveContact(contact* pcon)//保存通讯录
{FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("fopen fail");return;}for (size_t i = 0; i < pcon->size; i++){fwrite(pcon->a + i, sizeof(Info), 1, pf);}printf("通讯录数据保存成功!\n");fclose(pf);
}void LoadContact(contact* pcon)//载入历史通讯录
{FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("fopen fail");return;}Info info;while (fread(&info, sizeof(Info), 1, pf)){SeqListPushBack(pcon, info);}printf("通讯录数据载入成功!\n");fclose(pf);
}

三、测试

(1)添加联系人

选择功能

 输入联系人信息

我们查看通讯录检查一下是否真的添加成功

按照同样的步骤再添加一个联系人试试

(2)删除联系人

选择功能

输入要删除的联系人姓名

检查一下

确实删除了

(3)修改联系人

选择功能

输入要修改的联系人姓名

输入修改后的信息 

修改成功,我们检查一下

(4)查找联系人

选择功能,输入要查找的联系人姓名

(5)清空通讯录

我们试着多添加几个联系人

现在通讯录中有5个联系人,我们选择清空通讯录

再查看通讯录

(6)通讯录读档和存档

向通讯录中添加几个联系人

选择退出通讯录

 重新打开程序,选择查看通讯录,发现之前的联系人仍在通讯录中

完.

相关文章:

基于动态顺序表实现通讯录项目

本文中&#xff0c;我们将使用顺序表的结构来完成通讯录的实现。 我们都知道&#xff0c;顺序表实际上就是一个数组。而使用顺序表来实现通讯录&#xff0c;其内核是将顺序表中存放的数据类型改为结构体&#xff0c;将联系人的信息存放到结构体中&#xff0c;通过对顺序表的操…...

python使用jupyter记笔记

目录 一、安装 二、运行jupyter 三、使用 四、记笔记 Jupyter Notebook&#xff08;此前被称为 IPython notebook&#xff09;是一个交互式笔记本&#xff0c;支持运行 40 多种编程语言。 Jupyter Notebook 的本质是一个 Web 应用程序&#xff0c;便于创建和共享程序文档&a…...

C#封装服务

C#封装服务 新建服务项目&#xff1b;重构 OnStart 和 OnStop using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.ServiceProcess; using System.Text; using S…...

手写Vue3源码

Vue3核心源码 B站视频地址&#xff1a;https://www.bilibili.com/video/BV1nW4y147Pd?p2&vd_source36bacfbaa95ea7a433650dab3f7fa0ae Monorepo介绍 Monorepo 是管理项目代码的一种方式&#xff0c;只在一个仓库中管理多个模块/包 一个仓库可以维护多个模块&#xff0c;…...

如何无需重复输入FTP信息来安装WordPress主题和插件

WordPress作为一个广受欢迎的内容管理系统&#xff0c;提供了丰富的主题和插件来扩展网站的功能和外观。然而&#xff0c;许多用户在安装这些主题和插件时&#xff0c;经常遇到需要重复输入FTP信息的麻烦。幸运的是&#xff0c;有几种方法可以解决这个问题&#xff0c;让安装过…...

开发安全之:JSON Injection

Overview 在 XXX.php 的第 X 行中&#xff0c;responsemsg() 方法将未经验证的输入写入 JSON。攻击者可以利用此调用将任意元素或属性注入 JSON 实体。 Details JSON injection 会在以下情况中出现&#xff1a; 1. 数据从一个不可信赖的数据源进入程序。 2. 将数据写入到 …...

各种Linux版本安装Docker

文章目录 一、Ubuntu 20.04.61. 网卡和DNS配置2. Docker安装 二、CentOS Linux 7.91. 网卡和DNS配置2. Docker安装 三、Alibaba Cloud Linux 31. DNS配置2. repo说明3. Docker安装 四、验证是否安装成功 一、Ubuntu 20.04.6 1. 网卡和DNS配置 /etc/netplan 找到 *.yaml 文件 …...

git中合并分支时出现了代码冲突怎么办

目录 第一章、Git代码冲突介绍1.1&#xff09;什么是Git代码冲突①git merge命令介绍②代码冲突原因 1.2&#xff09;提示代码冲突的两种情况①本地不同分支的文件有差异时&#xff1a;②本地仓库和git远程仓库的文件有差异时&#xff1a; 1.3&#xff09;解决合并时的代码冲突…...

什么是防火墙?

目录 什么是防火墙&#xff0c;为什么需要防火墙&#xff1f;防火墙与交换机、路由器对比防火墙和路由器实现安全控制的区别防火墙的发展史1989年至1994年1995年至2004年2005年至今 什么是防火墙&#xff0c;为什么需要防火墙&#xff1f; “防火墙”一词起源于建筑领域&#x…...

tui.calender日历创建、删除、编辑事件、自定义样式

全是坑&#x1f573;&#xff01;全是坑&#x1f573;&#xff01;全是坑&#x1f573;&#xff01;能不用就不用&#xff01; 官方文档&#xff1a;https://github.com/nhn/tui.calendar/blob/main/docs/en/apis/calendar.md 实例的一些方法&#xff0c;比如创建、删除、修改、…...

OpenHarmonyOS-gn与Ninja

GN语法及在鸿蒙的使用 [gnninja学习 0x01]gn和ninja是什么 ohos_sdk/doc/subsys-build-gn-coding-style-and-best-practice.md GN 语言与操作 一、gn简介 gn是generate ninja的缩写&#xff0c;它是一个元编译系统&#xff08;meta-build system&#xff09;,是ninja的前端&am…...

Docker部署Traefik结合内网穿透远程访问Dashboard界面

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…...

2024年甘肃省职业院校技能大赛信息安全管理与评估 样题二 理论题

竞赛需要完成三个阶段的任务&#xff0c;分别完成三个模块&#xff0c;总分共计 1000分。三个模块内容和分值分别是&#xff1a; 1.第一阶段&#xff1a;模块一 网络平台搭建与设备安全防护&#xff08;180 分钟&#xff0c;300 分&#xff09;。 2.第二阶段&#xff1a;模块二…...

从代码到项目管理:程序员的职业跃迁与PMP认证之路

哈喽&#xff0c;我是eleven,软件工程专业毕业&#xff0c;工作六年多的时间从事过测试岗、研发岗、项目经理岗。一路走来一直按照自己的职业规划向前发展&#xff0c;每一步都成功转型&#xff0c;目前已顺利拿到PMP项目管理资格认证。希望能通过自己的经验给大家带来些许帮助…...

空间形状对结构加法产物的影响

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 有2个点被固定在一个5*5的平面内&#xff0c;在这个平面内还有2个点在随机的运动。最终这4个点是如何分布的&#xff1f; 1 - - - 5 - - 1 9 - - 1 - 13 - - - 1 1 1 - 1 …...

构建高效外卖系统:技术实践与代码示例

外卖系统在现代社会中扮演着重要的角色&#xff0c;为用户提供了便捷的用餐解决方案。在这篇文章中&#xff0c;我们将探讨构建高效外卖系统的技术实践&#xff0c;同时提供一些基础的代码示例&#xff0c;帮助开发者更好地理解和应用这些技术。 1. 技术栈选择 构建外卖系统…...

HCIP-BGP选路实验

一.实验拓扑图 二.详细配置 R1 interface GigabitEthernet0/0/0 ip address 12.1.1.1 255.255.255.0interface LoopBack0 ip address 1.1.1.1 255.255.255.0interface LoopBack1 ip address 10.1.1.1 255.255.255.0bgp 1 router-id 1.1.1.1 peer 12.1.1.2 as-number 2ipv4-fa…...

线性表--顺序表

目录 1.什么是顺序表 2.动态顺序表实现 2.1动态顺序表结构体 2.2初始化 2.3打印验证函数 2.4判断是否扩容&#xff0c;按需扩容 2.5头插/尾插 2.6头删/尾删 2.7指定位置插入数据/指定位置删除数据 3.动态顺序表代码 1.什么是顺序表 线性表是n个具有相同特性的数据元素的…...

前端面试题:节流和防抖

节流和防抖都是通过降低事件执行的频率而达到节省资源的效果 节流 一段时间只执行一次,多少秒之后获取验证码、resize 事件和scroll 事件等 类似王者荣耀中的传送,一段时间内只能传送一次,具体实现如下: function throttle(fn, delay) {let lastTime = 0;return functi…...

网络工程师学习笔记——交换机路由器 数据传输

交换机和路由器是数据通信最核心&#xff0c;也是所有网工最熟悉的设备。今天学习&#xff1a;交换机%路由器数据传输过程。 目录 一、交换机 1、交换机原理 2、交换机数据传输过程 3、交换机基本原理配置命令 二、路由器 1、路由器原理 2、路由器数据传输过程 3、静态…...

【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表

1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

ffmpeg(四):滤镜命令

FFmpeg 的滤镜命令是用于音视频处理中的强大工具&#xff0c;可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下&#xff1a; ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜&#xff1a; ffmpeg…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成

一个面向 Java 开发者的 Sring-Ai 示例工程项目&#xff0c;该项目是一个 Spring AI 快速入门的样例工程项目&#xff0c;旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计&#xff0c;每个模块都专注于特定的功能领域&#xff0c;便于学习和…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

云原生周刊:k0s 成为 CNCF 沙箱项目

开源项目推荐 HAMi HAMi&#xff08;原名 k8s‑vGPU‑scheduler&#xff09;是一款 CNCF Sandbox 级别的开源 K8s 中间件&#xff0c;通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度&#xff0c;为容器提供统一接口&#xff0c;实现细粒度资源配额…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...

微服务通信安全:深入解析mTLS的原理与实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、引言&#xff1a;微服务时代的通信安全挑战 随着云原生和微服务架构的普及&#xff0c;服务间的通信安全成为系统设计的核心议题。传统的单体架构中&…...