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

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

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

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

一、功能

(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 100

struct 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)通讯录读档和存档

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

选择退出通讯录

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

完.

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

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

相关文章

【微服务核心】ZooKeeper

文章目录 1. 简介2. 下载与安装2.1 单机版2.2 集群版 3. 选举机制3.1 首次启动3.2 非首次启动 4. 客户端常用命令行操作4.1 查看节点信息4.2 节点类型4.3 监听器原理4.4 写数据流程 5. 编程实现监听服务动态上下线6. 分布式锁6.1 手写简易分布式锁6.2 Curator 框架 7. 进阶知识…

python对象方法 反射

前言 类实例化得到的对象可以直接调用类中定义的函数&#xff0c;并且可以将对象本身作为第一个参数&#xff0c;那么类能不能也能像对象一样使用类体中的函数而不需要传递第一个参数呢&#xff1f;如果我们使用别人封装好的类&#xff0c;如何判断这个类或者对象是否有某个属…

未来 AI 可能给哪些产业带来哪些进步与帮助?

AI时代如何要让公司在创新领域领先吗&#xff1f;拥抱这5种创新技能&#xff0c;可以帮助你的公司应对不断变化。包括人工智能、云平台应用、数据分析、 网络安全和体验设计。这些技能可以帮助你提高业务效率、保护公司知识资产、明智决策、满足客户需求并提高销售额。 现在就加…

Python入门到精通(三)——Python循环语句

Python循环语句 一、while 循环 1、基础语法 2、嵌套应用 二、for 循环 1、基础语法 2、嵌套应用 三、循环中断&#xff1a;break 和 continue 1、break 2、continue 四、综合案例 一、while 循环 1、基础语法 while的条件需得到布尔类型&#xff0c;True表示继续循环…

一款真正可用的支付系统,可搭建自己的易支付系统,开源无后门

应用介绍 介绍: thinkphp开发的风吹雪支付系统易支付去后台验证版本&#xff0c;支持代理系统&#xff0c;适合搭建易支付系统&#xff0c;完整100%可运行网站源码。是为数不多的一款真正可用的支付系统&#xff0c;开源无后门可运营。 自带微信支付宝官方通道&#xff0c;资质…

探秘网络爬虫的基本原理与实例应用

1. 基本原理 网络爬虫是一种用于自动化获取互联网信息的程序&#xff0c;其基本原理包括URL获取、HTTP请求、HTML解析、数据提取和数据存储等步骤。 URL获取&#xff1a; 确定需要访问的目标网页&#xff0c;通过人工指定、站点地图或之前的抓取结果获取URL。 HTTP请求&#…

一键拆分,轻松整理,高效管理文本文件,让工作更轻松!

在日常工作中&#xff0c;我们经常需要处理大量的文本文件。如何快速整理这些文件&#xff0c;方便管理和使用成为了关键问题。为此&#xff0c;我们为您推荐一款强大的一键拆分和整理工具&#xff0c;助您高效管理文本文件&#xff01; 首先&#xff0c;在首助编辑高手的主页面…

Gradle——基础

1、Gradle基础 1.1、Ant/Maven/Gradle对比 无论那种项目构建工具&#xff0c;都有自身的优势和劣势&#xff0c;所以选择一款最适合项目的就是最好的&#xff01; 1.2、Gradle项目目录结构 Gradle项目默认目录结构和Maven项目的目录结构一致&#xff0c;都是基于约定大于配置…

好物周刊#37:元气桌面

https://github.com/cunyu1943/JavaPark https://yuque.com/cunyu1943 村雨遥的好物周刊&#xff0c;记录每周看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;每周五发布。 一、项目 1. MallChat 一个既能购物又能聊天的电商系统。以互联网企业级开发规范的…

《斗罗大陆Ⅱ绝世唐门》美女盘点:高颜值角色吸睛无数,玄机科技再塑国漫辉煌

在国漫崛起的大潮中&#xff0c;玄机科技以其精湛的建模技术和独特的审美视角&#xff0c;打造了一部又一部备受瞩目的佳作。其中&#xff0c;《绝世唐门》作为玄幻类动画的代表&#xff0c;凭借其丰富的人物设定和颜值爆表的角色&#xff0c;赢得了无数观众的喜爱和追捧。今天…

DC-3靶机刷题记录

靶机下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1-P5ezyt5hUbmmGMP4EI7kw?pwdrt2c 提取码&#xff1a;rt2c 参考&#xff1a; http://t.csdnimg.cn/hhPi8https://www.vulnhub.com/entry/dc-32,312/ 官网http://t.csdnimg.cn/5mVZ7DC-3 (1).pdfhttps://…

裸辞后找工作有多难?分享个人经历+面经+学习路线【内含免费下载初级前端面试题】- 回忆我的2023

&#x1f449; 个人博客主页 &#x1f448; &#x1f4dd; 一个努力学习的程序猿 专栏&#xff1a; HTML和CSS JavaScript jQuery Vue Vue3 React TypeScript uni-app Linux 前端面试分享 前端学习方案分享(VitePress、html2canvasjspdf、vuedraggable、videojs) 前端踩坑日记&…

2023年上半年网络工程师真题(2/3)

21.在OSI参考模型中&#xff0c;负责对应用层消息进行压缩&#xff0c;加密功能的层次为&#xff08;C&#xff09;。 A.传输层 B.会话层 C.表示层 D.应用层 表示层。表示层处理的是用户信息的表示问题。端用户(应用进程)之间传送的数据包含语义和语法两个方面。语义是数据…

索引的概述和性能分析

索引index&#xff0c;是一种有序的数据结构&#xff0c;可以高效的获取数据&#xff0c;在数据库中维护着满足查找特定算法的数据结构&#xff0c;就是索引 无索引的情况&#xff0c;查询数据时会全表扫描&#xff0c;效率极低 索引结构 &#xff08;1&#xff09;二叉树&…

flink学习之水位线

什么是水位线 在事件时间语义下&#xff0c;我们不依赖系统时间&#xff0c;而是基于数据自带的时间戳去定义了一个时钟&#xff0c; 用来表示当前时间的进展。于是每个并行子任务都会有一个自己的逻辑时钟&#xff0c;它的前进是靠数 据的时间戳来驱动的。 我们可以把时钟也以…

Linux下MySQL用户管理、权限、密码

一、原理 MySQL的用户管理实质上是对用户表的管理&#xff0c;系统中的数据库mysql存在一张用户表&#xff08;user&#xff09;&#xff0c;所有的用户都在该表内&#xff0c;对用户的管里也就是对该表进行增删查改的操作。 show databases; 如图中的mysql数据库&#xff0c;…

Leetcode 用队列实现栈

题目&#xff1a; 请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。 int pop() 移除并…

2024/1/20 并查集

目录 并查集关键代码 亲戚 村村通 团伙&#xff08;新知识&#xff09; 并查集关键代码 返回祖宗节点路径压缩&#xff1a; int find(int x) {if(f[x]!x) f[x]find(f[x]);return f[x]; } 合并&#xff1a; void make(int x,int y) {int f1find(f[x]);int f2find(f[y]);…

69.使用Go标准库compress/gzip压缩数据存入Redis避免BigKey

文章目录 一&#xff1a;简介二&#xff1a;Go标准库compress/gzip包介绍ConstantsVariablestype Headertype Reader 三&#xff1a;代码实践1、压缩与解压工具包2、单元测试3、为何压缩后还要用base64编码 代码地址&#xff1a; https://gitee.com/lymgoforIT/golang-trick/t…

图像分割实战-系列教程15:deeplabV3+ VOC分割实战3-------网络结构1

&#x1f341;&#x1f341;&#x1f341;图像分割实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 deeplab系列算法概述 deeplabV3 VOC分割实战1 deeplabV3 VOC分割实战2 deeplabV3 VOC分割实战3 dee…