数据结构——通讯录项目

1.通讯录的介绍

顺序表是通讯录的底层结构。

通讯录是将顺序表的类型替换成结构体类型来储存用户数据,通过运用顺序表结构来实现的。

用户数据结构:

typedef struct PersonInfo
{char name[12];char sex[10];int age;char tel[11];char addr[100];
}PeoInfo;

2. 通讯录功能的实现

2.1 构建菜单

将通讯录的所有功能都一一列出来,让用户一目了然。

Contact.c:

void menu()
{printf("*******************************************\n");printf("******* 1.添加联系人    2.查找联系人 ******\n");printf("******* 1.修改联系人    2.删除联系人 ******\n");printf("******* 1.查看通讯录    0.退出通讯录 ******\n");printf("*******************************************\n");
}

测试结果如下:

 2.2 构建选择操作

Contact.c:

	int op = -1;do {menu();printf("请选择您的操作:\n");scanf("%d", &op);switch (op){case 1://添加联系人break;case 2://查找联系人break;case 3://修改联系人break;case 4://删除联系人break;case 5://查看通讯录break;case 0://退出通讯录printf("通讯录退出中.....\n");break;}} while(op);

 测试结果如下:

 2.3 构建通讯录数据类型

Contact.c:

typedef struct PersonInfo
{char name[NAME_MAX];//使用宏便于后期修改代码char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}PeoInfo;

2.4 通讯录的初始化和销毁

Contact.h:

//初始化通讯录
void InitContact(contact* con);//实际初始化的是顺序表
//销毁通讯录数据
void DestroyContact(contact* con);

Contact.c:

void InitContact(contact* con)
{SLInit(con);
}
void DestroyContact(contact* con)
{SLDestory(con);
}

2.5 增加联系人

Contact.h:

void AddContact(contact* con);

Contact.c:

void AddContact(contact* con)
{SLCheckCapacity(con);printf("请输入联系人姓名:\n");scanf("%s", con->arr[con->size].name);printf("请输入联系人性别:\n");scanf("%s", con->arr[con->size].sex);printf("请输入联系人年龄:\n");scanf("%d", &con->arr[con->size].age);printf("请输入联系人电话:\n");scanf("%s", con->arr[con->size].tel);printf("请输入联系人住址:\n");scanf("%s", con->arr[con->size].addr);con->size++;
}

测试结果如下:

2.6 展示联系人

Contact.h:

void ShowContact(contact* con);

Contact.c:

void ShowContact(contact* con) {printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");for (int i = 0; i < con->size; i++){printf("%s %s %d %s %s\n",con->arr[i].name,con->arr[i].sex,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}
}

测试结果如下:

2.7 查找联系人

Contact.h:

void FindContact(contact* con);

Contact.c:

//查找通讯录数据
int FindByName(contact* con, char name[])//根据需求设计查找的方式
{for (int i = 0; i < con->size; i++){if (strcmp(con->arr[i].name, name) == 0){return i;}}return -1;
}
void FindContact(contact* con)
{char name[NAME_MAX];printf("请输入要查找人的名字:\n");scanf("%s", name);int FindIndex = FindByName(con, name);if (FindIndex < 0){printf("联系人不存在!\n");return;}printf(%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n, "姓名", "性别", "年龄", "电话", "住址");printf(%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n,con->arr[FindIndex].name,con->arr[FindIndex].sex,con->arr[FindIndex].age,con->arr[FindIndex].tel,con->arr[FindIndex].addr);
}

测试结果如下:

 2.8 删除联系人

 Contact.h:

void DelContact(contact* con);

Contact.c:

void DelContact(contact* con)
{//删除之前一定要查找printf("请输入要删除的联系人的姓名:\n");char name[NAME_MAX];scanf("%s", name);int ret = FindByName(con, name);//找不到,不能执行删除if (ret < 0){printf("要删除的联系人不存在!\n");return;}//执行删除操作SLErase(con, ret);
}

测试结果如下:

2.9 修改联系人

Contact.h:

void ModifyContact(contact* con);

Contact.c:

void ModifyContact(contact* con)
{//修改之前进行查找char name[NAME_MAX];printf("请输入要修改联系人的姓名:\n");scanf("%s",name);int findIndex = FindByName(con, name);//没有找到,不能执行修改操作if (findIndex < 0){printf("要修改的联系人不存在!\n");return;}//找到了,执行修改操作printf("请输入姓名:\n");scanf("%s", con->arr[findIndex].name);printf("请输入年龄:\n");scanf("%d", &con->arr[findIndex].age);printf("请输入性别:\n");scanf("%s", con->arr[findIndex].sex);printf("请输入电话:\n");scanf("%s", con->arr[findIndex].tel);printf("请输入地址:\n");scanf("%s", con->arr[findIndex].addr);printf("修改联系人成功!\n");
}
//找到了,执行修改操作

测试结果如下:

3. 通讯录功能优化

上面我们已经实现的通讯录的基本功能,但是我们会发现程序一旦结束,通讯录里储存的数据便会丢失。对于这种情况我们该如何解决呢?

答:将通讯录数据以二进制多大的方式储存到文件里

3.1 储存数据

Contact.h:

void SaveContact(contact* con)

Contact.c:

void SaveContact(contact* 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->arr[i]), sizeof(Info), 1, pf);}printf("通讯录数据保存成功!\n");fclose(pf);
}

测试结果如下:

3.2 读取数据

 Contact.h:

void LoadContact(contact* con);

Contact.c:

void LoadContact(contact* con) {FILE* pf = fopen("contact.txt", "rb");if (pf == NULL) {perror("fopen error!\n");return;}//循环读取⽂件数据Info info = { 0 };while (fread(&info, sizeof(Info), 1, pf)){SLCheckCapacity(con);con->arr[con->size] = info;con->size++;}//printf("%s %s\n", info.name, info.tel);printf("历史数据导入通讯录成功!\n");fclose(pf);}

测试结果如下:

这样我们就不用担心数据丢失了!

4. 项目完整代码

SeqList.h:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include"Contact.h"
typedef Info SLDataType;
typedef struct SeqList
{SLDataType* arr;int capacity;int size;
}SL;
//初始化和打印
void SLInit(SL* ps);
void SLPrint(SL* ps);
//扩容
void SLCheckCapacity(SL* ps);
//头插和尾插
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);
//头删和尾删
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);
//在指定位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x);
//在指定位置删除
void SLErase(SL* ps, int pos);
//查找数据
//int SLFind(SL* ps, SLDataType x);
//销毁
void SLDestory(SL* ps);

SeqList.c:

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void SLInit(SL* ps)
{ps->arr = NULL;ps->size = ps->capacity = 0;
}
//void SLPrint(SL* ps)
//{
//	for (int i = 0; i < ps->size; i++)
//	{
//		printf("%d ", ps->arr[i]);
//	}
//	printf("\n");
//}
//检查内存空间,扩容
void SLCheckCapacity(SL* ps)
{int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newcapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc fall!");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;
}
//尾插
void SLPushBack(SL* ps,SLDataType x)
{assert(ps);//空间不够,扩容SLCheckCapacity(ps);//空间足够,直接插入ps->arr[ps->size++] = x;
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);//判断是否扩容SLCheckCapacity(ps);//旧数据往后挪动一位for (int i = ps->size; i > 0; i--){ps->arr[i] = ps->arr[i - 1];}ps->arr[0] = x;ps->size++;
}
//尾删
void SLPopBack(SL* ps) {assert(ps);//判断顺序表是否为空assert(ps->size);//不为空ps->size--;
}
//头删
void SLPopFront(SL* ps)
{assert(ps);//判断顺序表是否为空assert(ps->size);for (int i = 0; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}
//在指定位置插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps && (pos>=0&&pos <= ps->size));//判断是否扩容SLCheckCapacity(ps);for (int i = ps->size; i > pos; i--){ps->arr[i ] = ps->arr[i - 1];}ps->arr[pos] = x;ps->size++;
}
//在指定位置删除
void SLErase(SL* ps, int pos)
{assert(ps && (pos >= 0 && pos <= ps->size));//判断顺序表是否为空assert(ps->size);//不为空for (int i = pos; i < ps->size-1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}
//查找数据//int SLFind(SL* ps, SLDataType x)
//{
//	assert(ps);
//	for (int i = 0; i < ps->size; i++)
//	{
//		if (ps->arr[i] == x)
//		{
//			return i;
//		}
//	}
//	return -1;
//}
void SLDestory(SL* ps)
{assert(ps);if (ps->arr){free(ps->arr);}ps->arr = NULL;ps->capacity = ps->size = 0;
}

Contact.h:

#pragma once
#include<stdio.h>
#define NAME_MAX 100
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100
//⽤户数据
typedef struct PersonInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}Info;
//前置声明  防止头文件嵌套调用
typedef struct SeqList contact;//初始化通讯录
void InitContact(contact* con);//实际初始化的是顺序表
//销毁通讯录数据
void DestroyContact(contact* con);
//添加通讯录数据
void AddContact(contact* con);
//展⽰通讯录数据
void ShowContact(contact* con);
//删除通讯录数据
void DelContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact* con);
//保存数据
void SaveContact(contact* con);
//读取数据
void LoadContact(contact* con);

Contact.c:

#include"SeqList.h"
void InitContact(contact* con)
{SLInit(con);
}
void DestroyContact(contact* con)
{SLDestory(con);
}
//添加联系人
void AddContact(contact* con)
{SLCheckCapacity(con);printf("请输入联系人姓名:\n");scanf("%s", con->arr[con->size].name);printf("请输入联系人性别:\n");scanf("%s", con->arr[con->size].sex);printf("请输入联系人年龄:\n");scanf("%d", &con->arr[con->size].age);printf("请输入联系人电话:\n");scanf("%s", con->arr[con->size].tel);printf("请输入联系人住址:\n");scanf("%s", con->arr[con->size].addr);con->size++;
}
//展⽰通讯录数据
void ShowContact(contact* con) {printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");for (int i = 0; i < con->size; i++){printf("%-20s\t%-5s\t%-4d\t%-12s\t%-20s\n",con->arr[i].name,con->arr[i].sex,con->arr[i].age,con->arr[i].tel,con->arr[i].addr);}
}
//查找通讯录数据
int FindByName(contact* con, char name[])//根据需求设计查找的方式
{for (int i = 0; i < con->size; i++){if (strcmp(con->arr[i].name, name) == 0){return i;}}return -1;
}
void FindContact(contact* con)
{char name[NAME_MAX];printf("请输入要查找人的名字:\n");scanf("%s", name);int FindIndex = FindByName(con, name);if (FindIndex < 0){printf("联系人不存在!\n");return;}printf("%-20s\t%-5s\t%-4s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "住址");printf("%-20s\t%-5s\t%-4d\t%-12s\t%-20s\n",con->arr[FindIndex].name,con->arr[FindIndex].sex,con->arr[FindIndex].age,con->arr[FindIndex].tel,con->arr[FindIndex].addr);
}
//删除通讯录数据
void DelContact(contact* con)
{//删除之前一定要查找printf("请输入要删除的联系人的姓名:\n");char name[NAME_MAX];scanf("%s", name);int ret = FindByName(con, name);//找不到,不能执行删除if (ret < 0){printf("要删除的联系人不存在!\n");return;}//执行删除操作SLErase(con, ret);
}
//修改通讯录数据
void ModifyContact(contact* con)
{//修改之前进行查找char name[NAME_MAX];printf("请输入要修改联系人的姓名:\n");scanf("%s",name);int findIndex = FindByName(con, name);//没有找到,不能执行修改操作if (findIndex < 0){printf("要修改的联系人不存在!\n");return;}//找到了,执行修改操作printf("请输入姓名:\n");scanf("%s", con->arr[findIndex].name);printf("请输入年龄:\n");scanf("%d", &con->arr[findIndex].age);printf("请输入性别:\n");scanf("%s", con->arr[findIndex].sex);printf("请输入电话:\n");scanf("%s", con->arr[findIndex].tel);printf("请输入地址:\n");scanf("%s", con->arr[findIndex].addr);printf("修改联系人成功!\n");
}
//保存数据
void SaveContact(contact* 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->arr[i]), sizeof(Info), 1, pf);}printf("通讯录数据保存成功!\n");fclose(pf);pf = NULL;
}
//读取数据
void LoadContact(contact* con) {FILE* pf = fopen("contact.txt", "rb");if (pf == NULL) {perror("fopen error!\n");return;}//循环读取⽂件数据Info info = { 0 };while (fread(&info, sizeof(Info), 1, pf)){SLCheckCapacity(con);con->arr[con->size] = info;con->size++;}//printf("%s %s\n", info.name, info.tel);printf("历史数据导入通讯录成功!\n");fclose(pf);pf = NULL;
}

ConTest.c

#include"SeqList.h"
void menu()
{printf("*******************************************\n");printf("******* 1.添加联系人    2.查找联系人 ******\n");printf("******* 3.修改联系人    4.删除联系人 ******\n");printf("******* 5.查看通讯录    0.退出通讯录 ******\n");printf("*******************************************\n");
}
int main()
{int op = -1;contact con;//通讯录初始化InitContact(&con);LoadContact(&con);do {menu();printf("请选择您的操作:\n");scanf("%d", &op);switch (op){case 1://添加联系人AddContact(&con);break;case 2://查找联系人FindContact(&con);break;case 3://修改联系人ModifyContact(&con);break;case 4://删除联系人DelContact(&con);printf("联系人删除成功!\n");break;case 5://查看通讯录ShowContact(&con);break;break;case 0://退出通讯录printf("通讯录退出中.....\n");break;}} while (op);SaveContact(&con);DestroyContact(&con);return 0;
}

 对于顺序表代码的实现在上一篇中有讲解,如果有的小伙伴有兴趣,可以去看一看。链接在下方:http://t.csdnimg.cn/wpM1t

本文为作者学习后的总结,如果有什么不恰当的地方,欢迎大佬指正!!! 

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

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

相关文章

跨境电子商务支付与结算

一、跨境电子商务支付与结算的业务架构 跨境电子商务支付与结算的业务架构&#xff0c;结合跨境电子商务支付与结算的技术架构&#xff0c;其业务架构主要包括以下五大模块 &#xff08;1&#xff09;商户模块。商户模块包括虚拟账户、管理平台、多币种收银台、争议管理。 &…

【备战蓝桥杯系列】蓝桥杯国二选手笔记二:算法模版笔记(Java)

感谢大家的点赞&#xff0c;关注&#xff0c;评论。准备蓝桥杯的同学可以关注一下本专栏哦&#xff0c;不定期更新蓝桥杯笔记以及经验分享。本人多次参加过蓝桥杯&#xff0c;并获得过蓝桥杯国二的成绩。 算法模版笔记&#xff08;Java&#xff09; 这篇文章给大家分享我的蓝桥…

LeetCode 1315.祖父节点值为偶数的节点和

给你一棵二叉树&#xff0c;请你返回满足以下条件的所有节点的值之和&#xff1a; 该节点的祖父节点的值为偶数。&#xff08;一个节点的祖父节点是指该节点的父节点的父节点。&#xff09; 如果不存在祖父节点值为偶数的节点&#xff0c;那么返回 0 。 示例&#xff1a; 输入…

php apache 后台超时设置

最近在写一个thinkphp项目的时候&#xff0c;发现Ajax从后端请求数据时间比较长&#xff0c;大概需要45秒左右&#xff0c;但是一旦请求时间超过40s&#xff0c;页面就会超时500了&#xff0c;一开始以为是ajax请求时间不能太长&#xff0c;后来将Ajax请求改为同步且timeout设置…

2024长三角快递物流供应链与技术装备展览会(杭州站)

2024.7.8-10 杭州国际博览中心 科技创新&#xff0c;数字赋能 同期举办&#xff1a;数字物流技术展 新能源商用车及物流车展 电商物流包装展 冷链物流展 指导单位 国家邮政局发展研究中心浙江省邮政管理局中国快递协会 承办单位 上海信世展览服务有限公司 主办单位 浙江…

H5简约星空旋转引导页源码

源码名称&#xff1a;H5简约星空旋转引导页 源码介绍&#xff1a;一款带有星空旋转背景特效的源码&#xff0c;带有四个按钮 需求环境&#xff1a;H5 下载地址&#xff1a; https://www.changyouzuhao.cn/11655.html

数据结构:红黑树的模拟实现

目录 1、什么是红黑树&#xff1f; 2、红黑树的相关操作与实现 1、节点定义 2、查找操作 3、插入操作 1、cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;cur存在且为红 2、cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u不存在/u存在且为黑 4、判断…

能发顶会!GNN结合LLMs的三大创新思路!新SOTA准确率提升10倍

LLMs在处理NLP任务方面表现出色&#xff0c;而GNNs在挖掘和分析复杂关系数据&#xff08;图数据&#xff09;方面展现出其卓越的能力。这种趋势催生了将这两种技术整合的研究兴趣&#xff0c;为解决更多领域的实际问题。GNN结合LLMs也逐渐成为了研究的热点。 GNNLLMs可以发挥二…

集智书童 | 炸裂 !轻量化YOLO | ShuffleNetv2与Transformer结合,重塑YOLOv7成就超轻超快YOLO

本文来源公众号“集智书童”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;炸裂 &#xff01;轻量化YOLO | ShuffleNetv2与Transformer结合&#xff0c;重塑YOLOv7成就超轻超快YOLO 随着移动计算技术的迅速发展&#xff0c;在移动…

ECharts饼图图例消失踩的坑

在使用Echarts的饼图时&#xff0c;当时做法是在图例数小于8时显示全部的图例&#xff0c;在大于8的时候显示前8个图例。于是用了两种不同的方式处理。导致出现切换时间后图例不显示的情况。 错误过程&#xff1a; 在进行图例生成时采用了两种不同的方式&#xff1a; ①如果…

打造你的HTML5打地鼠游戏:零基础入门教程

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

Rust生命周期和生命周期声明‘作用Missing lifetime specifier

Missing lifetime specifier&#xff1a;报错说明缺失声明周期声明 Rust 生命周期机制是与所有权机制同等重要的资源管理机制。 之所以引入这个概念主要是应对复杂类型系统中资源管理的问题。 引用是对待复杂类型时必不可少的机制&#xff0c;毕竟复杂类型的数据不能被处理器…

UDP连接树莓派时提高连接速度,降低卡顿感

背景 树莓派4B刷的是ubuntu20.4系统&#xff0c;使用win10自带的远程桌面连接和其连接&#xff0c;卡的一批&#xff0c;于是探索并记录下如何降低连接卡顿感 步骤一 点击显示选项&#xff0c; 降低显示配置和颜色深度&#xff1a; 步骤二 我的树莓派是通过电脑移动热点的方式…

Qt+FFmpeg+opengl从零制作视频播放器-13.打包为exe包发布软件

1.首先visual studio给生成程序添加桌面图标。 右键工程,添加新文件资源文件Resource.rc 选择导入文件,我这里导入了Player.ico文件。 添加后,在资源文件那里就可以看见ico文件。 然后编译release程序, 生成的可执行程序就带上了图标。 2.使用Qt 程序打包发布-windeployq…

AWS入门实践-AWS CLI工具的使用介绍

AWS CLI&#xff08;Amazon Web Services Command Line Interface&#xff09;是一个强大的工具&#xff0c;它允许您直接从命令行与AWS服务进行交互。这不仅可以加快许多任务的处理速度&#xff0c;而且还可以通过脚本自动化。 一、AWS CLI工具的安装 1、Windows 安装下载…

uniapp图片涂鸦插件(支持多种涂鸦方式,图片放大缩小)

工程地址https://gitee.com/geshijia/ct-graffiti ct-graffiti涂鸦组件使用说明 参考说明 参考链接&#xff1a;https://github.com/ylyuanlu/yl-graffiti 感谢作者的付出&#xff0c;给我提供了一些思路&#xff0c;并做了如下优化&#xff1a; 增加图片放大缩小移动功能添…

第十四届蓝桥杯蜗牛

蜗牛 线性dp 目录 蜗牛 线性dp 先求到达竹竿底部的状态转移方程 求蜗牛到达第i根竹竿的传送门入口的最短时间​编辑 题目链接&#xff1a;蓝桥杯2023年第十四届省赛真题-蜗牛 - C语言网 关键在于建立数组将竹竿上的每个状态量表示出来&#xff0c;并分析出状态转移方程 in…

[实战]API防护破解之签名验签

前言&#xff1a; 传统的接口在传输的过程中&#xff0c;是非常容易被抓包进行篡改&#xff0c;从而进行中间人攻击。这时候我们可以通过对参数进行签名验证&#xff0c;如果参数与签名值不匹配&#xff0c;则请求不通过&#xff0c;直接返回错误信息&#xff0c;从而防止黑客…

混合A*源码解读(c++)

基于ros中通过slam建立的栅格地图&#xff0c;使用混合A*进行路径规划。 首先是run_hybrid_astar.cpp: #include "hybrid_a_star/hybrid_a_star_flow.h" #include "3rd/backward.hpp" #include <ros/ros.h>namespace backward { backward::SignalHa…

带钢切割控制液压比例阀放大器

比例阀控制器放大器放大板技术是电液比例控制系统中的重要组成部分&#xff0c;它负责对比例阀进行精确控制&#xff0c;以实现对液压系统中流量、压力等参数的精细调节。可以实现对液压流量或压力的精确控制&#xff0c;从而使系统以更高的精度和更快的响应速度执行各种操作。…