数据结构小项目----通讯录的实现(这里用链表实现) 超详细~~~~૮(˶ᵔ ᵕ ᵔ˶)ა

目录

Contact.h说明:

结构体与头文件的包含:  ​编辑

 函数在头文件的声明与定义:

 Contact.c中各个函数的实现:

1.检查链表中的数据是否满了,满了就扩容

 2.链表的尾插

 3.链表的删除

4.查找名字是否匹配

 5.初始化通讯录

6. 通讯录的摧毁

7.添加联系人的信息

8.删除联系人的信息 

9.修改联系人信息

 10.查找联系人

11.通讯录当前的联系人展示

ConTest.c源文件:

测试数据: 

最后完整代码展示: 

Contact.h:

Contact.c:

ConTest.c:


Contact.h说明:

概述:为了实现这个小项目,我开创了一个头文件:Contact.h .和两个源文件:Contact.c,ConTest.c,在Contact.h中进行结构体的声明,函数的声明和头文件的包含。Contact.c文件主要用于各个函数的实现,而ConTest则用于测试函数。

 

结构体与头文件的包含:  

 这里通过结构体数组来进行数据的插入与删除操作,为了后续的书写方便,将各个结构体变量的名字重新定义为其缩写形式(底层原理是顺序表

 函数在头文件的声明与定义:

void SLCheckCapacity(Contact* pocn);//用于顺序表的扩容
void SLPushBack(Contact* ps, ConDataType x);//顺序表的尾插
void SLErase(Contact* ps, int pos);//顺序表的删除
int FindByName(Contact* pocn, char name[]);//查找名字是否匹配void ContactInit(Contact* pocn);//通讯录的初始化
void ContactDestory(Contact* pocn);//通讯录的摧毁void ContactAdd(Contact* pocn);//通讯录的增加联系人
void ContactDel(Contact* pocn);//通讯录的删除联系人
void ContactModify(Contact* pocn);//通讯录的修改联系人信息
void ContactFind(Contact* pocn);//通讯录的查找
void ContactShow(Contact* pocn);//当前通讯录的信息的展示

 

 Contact.c中各个函数的实现:

1.检查链表中的数据是否满了,满了就扩容

代码详解:

//检查链表中的数据是否满了,满了就扩容
void SLCheckCapacity(Contact* pocn) {if (pocn->size == pocn->capacity) {int newCapacity = pocn->capacity == 0 ? 4 : 2 * pocn->capacity;//这里通过realloc来申请空间ConDataType* tmp = (ConDataType*)realloc(pocn->arr, newCapacity * sizeof(ConDataType));if (tmp == NULL) {perror("realloc fail!");exit(1);}//扩容成功pocn->arr = tmp;//注意要将当前的指针指向开创好的空间pocn->capacity = newCapacity;//容量也不要遗漏}
}

 由于顺序表是由数组实现的,如果定义一个静态数组,很不利于数据的存储。定义得太大浪费空间,定义得太小空间不够,这里我选择使用动态链表的形式实现这个问题,所以这里定义了一个函数SLCheckCapacity来检查链表的大小(size)是否超过其最大容量(capacity)。如果超过了,就需要进行扩容操作。没有就不需要进行任何操作。同时,为了和里这里扩容两倍。

 2.链表的尾插

代码详解:

//链表的尾插
void SLPushBack(Contact* ps, ConDataType x) {assert(ps);SLCheckCapacity(ps);ps->arr[ps->size++] = x;
}

首先判断这里的结构体指针是否为空,简单粗暴的方法:断言(assert),注意要引用头文件#include<assert.h>。接着要检查顺序表的容量是否满了,如果满了就扩容。 接着将数据插入尾部。

 3.链表的删除

代码解释:

//链表的删除
void SLErase(Contact* ps, int pos) {assert(ps);assert(pos >= 0 && pos < ps->size);//pos以后的数据往前挪动一位for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];}ps->size--;
}

4.查找名字是否匹配

代码解释:

//查找名字是否匹配
int FindByName(Contact* pocn, char name[]) {for (int i = 0; i < pocn->size; i++) {if (strcmp(pocn->arr[i].name, name) == 0) {return i;}}return -1;
}

如果有遗忘strcmp的小伙伴记得查收~

strcmp比较两个字符串的大小,一个字符一个字符比较,按ASCLL码比较
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字 

 5.初始化通讯录

 代码解释:

//初始化通讯录
void ContactInit(Contact* pocn) {pocn->arr = NULL;pocn->capacity = pocn->size = 0;
}

6. 通讯录的摧毁

代码解释:

//通讯录的摧毁
void ContactDestory(Contact* pocn) {assert(pocn);if (pocn->arr) {free(pocn->arr);}pocn->arr = NULL;pocn->capacity = pocn->size = 0;
}

7.添加联系人的信息

代码解释:

//添加联系人的信息
void ContactAdd(Contact* pocn) {Info info;//输入各个联系人的信息printf("请输入联系人姓名:\n");scanf("%s", info.name);printf("请输入联系人年龄:\n");scanf("%d", &info.age);printf("请输入联系人性别:\n");scanf("%s", info.gender);printf("请输入联系人电话:\n");scanf("%s", info.tel);printf("请输入联系人地址:\n");scanf("%s", info.addr);//用尾插法进行数据的增添SLPushBack(pocn, info);
}

输入联系人的各个信息后将其尾插到链表后

8.删除联系人的信息 

代码解释:

//删除联系人的信息
void ContactDel(Contact* pocn) {//删除之前要先查找//找到之后可以删除找不到,就不能进行删除操作printf("请输入要删除的联系人名字:\n");char name[NAME_MAX];scanf("%s", name);//定义findIndex来判断是否存在联系人信息int findIndex = FindByName(pocn, name);if (findIndex < 0) {printf("要删除的信息不存在!\n");return;}//存在就删除SLErase(pocn, findIndex);printf("联系人删除成功!\n");
}

9.修改联系人信息

代码解释:

//修改联系人信息
void ContactModify(Contact* pocn) {//修改之前先查找//如果没有找到,就无法进行修改操作char name[NAME_MAX];printf("请输入要修改的联系人姓名:\n");scanf("%s", name);int findIndex = FindByName(pocn, name);if (findIndex < 0) {printf("要修改的联系人找不到!\n");return;}//修改后输入新的联系人的信息printf("请输入姓名:\n");scanf("%s", pocn->arr[findIndex].name);printf("请输入年龄:\n");scanf("%d", &pocn->arr[findIndex].age);printf("请输入性别:\n");scanf("%s", pocn->arr[findIndex].gender);printf("请输入电话:\n");scanf("%s", pocn->arr[findIndex].tel);printf("请输入地址:\n");scanf("%s", pocn->arr[findIndex].addr);printf("联系人修改成功!\n");
}

 10.查找联系人

代码解释:

//查找联系人
void ContactFind(Contact* pocn) {printf("请输入要查找的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int findIndex = FindByName(pocn, name);if (findIndex < 0) {printf("找不到该联系人,联系人不存在!\n");return;}else printf("找到了,输出对应信息:\n");printf("%s %s %s %s %s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%s %d %s %s %s\n",pocn->arr[findIndex].name,pocn->arr[findIndex].age,pocn->arr[findIndex].gender,pocn->arr[findIndex].tel,pocn->arr[findIndex].addr);
}

11.通讯录当前的联系人展示

代码解释:

//通讯录当前的联系人展示
void ContactShow(Contact* pocn) {printf("%s %s %s %s %s\n", "姓名", "年龄", "性别", "电话", "地址");for (int i = 0; i < pocn->size; i++) {printf("%s %d %s %s %s\n",pocn->arr[i].name,pocn->arr[i].age,pocn->arr[i].gender,pocn->arr[i].tel,pocn->arr[i].addr);}
}

ConTest.c源文件:

代码详解:

//引入头文件
#include"Contact.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;ContactInit(&con);do {menu();printf("请选择操作:");scanf("%d", &op);//这里按照菜单的指示来选择操作switch (op) {//各个数字对应各个的操作case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactModify(&con);break;case 4:ContactFind(&con);break;case 5:ContactShow(&con);break;case 0:printf("通讯录退出中……\n");break;default :break;}} while (op != 0);ContactDestory(&con);//注意结束时要摧毁通讯录,防止内存泄漏return 0;
}

在ConTest文件中,主要是实现菜单的打印与各个函数操作的选择

测试数据: 

 

 

最后完整代码展示: 

 

Contact.h:

#include<assert.h>
#include<stdlib.h>//为了后续方便,这里将所要用到的数组的数据都重新定义
#define NAME_MAX 100
#define GENDER_MAX 10
#define TEL_MAX 12
#define ADDR_MAX 100
//联系人信息的存储(用结构体实现)
typedef struct PresonInformation
{char name[NAME_MAX];int age;char gender[GENDER_MAX];char tel[TEL_MAX];char addr[ADDR_MAX];
}Info;typedef Info ConDataType;
//对链表的声明与定义(结构体数组),用于对上述结构体信息存储
typedef struct SeqList
{ConDataType* arr;int capacity;int size;
}Contact;void SLCheckCapacity(Contact* pocn);//用于顺序表的扩容
void SLPushBack(Contact* ps, ConDataType x);//顺序表的尾插
void SLErase(Contact* ps, int pos);//顺序表的删除
int FindByName(Contact* pocn, char name[]);//查找名字是否匹配void ContactInit(Contact* pocn);//通讯录的初始化
void ContactDestory(Contact* pocn);//通讯录的摧毁void ContactAdd(Contact* pocn);//通讯录的增加联系人
void ContactDel(Contact* pocn);//通讯录的删除联系人
void ContactModify(Contact* pocn);//通讯录的修改联系人信息
void ContactFind(Contact* pocn);//通讯录的查找
void ContactShow(Contact* pocn);//当前通讯录的信息的展示

Contact.c:

#include"Contact.h"
//检查链表中的数据是否满了,满了就扩容
void SLCheckCapacity(Contact* pocn) {if (pocn->size == pocn->capacity) {int newCapacity = pocn->capacity == 0 ? 4 : 2 * pocn->capacity;//这里通过realloc来申请空间ConDataType* tmp = (ConDataType*)realloc(pocn->arr, newCapacity * sizeof(ConDataType));if (tmp == NULL) {perror("realloc fail!");exit(1);}//扩容成功pocn->arr = tmp;//注意要将当前的指针指向开创好的空间pocn->capacity = newCapacity;//容量也不要遗漏}
}
//链表的尾插
void SLPushBack(Contact* ps, ConDataType x) {assert(ps);SLCheckCapacity(ps);ps->arr[ps->size++] = x;
}
//链表的删除
void SLErase(Contact* ps, int pos) {assert(ps);assert(pos >= 0 && pos < ps->size);//pos以后的数据往前挪动一位for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];}ps->size--;
}
//查找名字是否匹配
int FindByName(Contact* pocn, char name[]) {for (int i = 0; i < pocn->size; i++) {if (strcmp(pocn->arr[i].name, name) == 0) {return i;}}return -1;
}//初始化通讯录
void ContactInit(Contact* pocn) {pocn->arr = NULL;pocn->capacity = pocn->size = 0;
}
//通讯录的摧毁
void ContactDestory(Contact* pocn) {assert(pocn);if (pocn->arr) {free(pocn->arr);}pocn->arr = NULL;pocn->capacity = pocn->size = 0;
}
//添加联系人的信息
void ContactAdd(Contact* pocn) {Info info;//输入各个联系人的信息printf("请输入联系人姓名:\n");scanf("%s", info.name);printf("请输入联系人年龄:\n");scanf("%d", &info.age);printf("请输入联系人性别:\n");scanf("%s", info.gender);printf("请输入联系人电话:\n");scanf("%s", info.tel);printf("请输入联系人地址:\n");scanf("%s", info.addr);//用尾插法进行数据的增添SLPushBack(pocn, info);
}//删除联系人的信息
void ContactDel(Contact* pocn) {//删除之前要先查找//找到之后可以删除找不到,就不能进行删除操作printf("请输入要删除的联系人名字:\n");char name[NAME_MAX];scanf("%s", name);//定义findIndex来判断是否存在联系人信息int findIndex = FindByName(pocn, name);if (findIndex < 0) {printf("要删除的信息不存在!\n");return;}//存在就删除SLErase(pocn, findIndex);printf("联系人删除成功!\n");
}
//修改联系人信息
void ContactModify(Contact* pocn) {//修改之前先查找//如果没有找到,就无法进行修改操作char name[NAME_MAX];printf("请输入要修改的联系人姓名:\n");scanf("%s", name);int findIndex = FindByName(pocn, name);if (findIndex < 0) {printf("要修改的联系人找不到!\n");return;}//修改后输入新的联系人的信息printf("请输入姓名:\n");scanf("%s", pocn->arr[findIndex].name);printf("请输入年龄:\n");scanf("%d", &pocn->arr[findIndex].age);printf("请输入性别:\n");scanf("%s", pocn->arr[findIndex].gender);printf("请输入电话:\n");scanf("%s", pocn->arr[findIndex].tel);printf("请输入地址:\n");scanf("%s", pocn->arr[findIndex].addr);printf("联系人修改成功!\n");
}
//查找联系人
void ContactFind(Contact* pocn) {printf("请输入要查找的联系人姓名:\n");char name[NAME_MAX];scanf("%s", name);int findIndex = FindByName(pocn, name);if (findIndex < 0) {printf("找不到该联系人,联系人不存在!\n");return;}else printf("找到了,输出对应信息:\n");printf("%s %s %s %s %s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%s %d %s %s %s\n",pocn->arr[findIndex].name,pocn->arr[findIndex].age,pocn->arr[findIndex].gender,pocn->arr[findIndex].tel,pocn->arr[findIndex].addr);
}
//通讯录当前的联系人展示
void ContactShow(Contact* pocn) {printf("%s %s %s %s %s\n", "姓名", "年龄", "性别", "电话", "地址");for (int i = 0; i < pocn->size; i++) {printf("%s %d %s %s %s\n",pocn->arr[i].name,pocn->arr[i].age,pocn->arr[i].gender,pocn->arr[i].tel,pocn->arr[i].addr);}
}

ConTest.c:

//引入头文件
#include"Contact.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;ContactInit(&con);do {menu();printf("请选择操作:");scanf("%d", &op);//这里按照菜单的指示来选择操作switch (op) {//各个数字对应各个的操作case 1:ContactAdd(&con);break;case 2:ContactDel(&con);break;case 3:ContactModify(&con);break;case 4:ContactFind(&con);break;case 5:ContactShow(&con);break;case 0:printf("通讯录退出中……\n");break;default :break;}} while (op != 0);ContactDestory(&con);//注意结束时要摧毁通讯录,防止内存泄漏return 0;
}

博客到这里也是结束了,制作不易,喜欢的小伙伴可以点赞加关注支持下博主,这对我真的很重要~~

 

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

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

相关文章

代码随想录二刷 |二叉树 | 将有序数组转换为二叉搜索树

代码随想录二刷 |二叉树 | 将有序数组转换为二叉搜索树 题目描述解题思路代码实现 题目描述 109.将有序数组转换为二叉搜索树 将一个按照升序排列的有序数组&#xff0c;转换为一棵高度平衡二叉搜索树。 本题中&#xff0c;一个高度平衡二叉树是指一个二叉树每个节点 的左右…

Zabbix 系统监控详解

1 介绍 1.1 摘要 本文深入浅出&#xff0c;切近实际运维应用&#xff0c;由 zabbix 3.4 版本入手&#xff0c;学习 zabbix 监控告警实现方式&#xff0c;由 zabbix 5.0 浅出实现快速部署、快速应用。本人从业多年&#xff0c;关注 zabbix 开源社区&#xff0c;以及 zabbix 官…

企业邮箱:定义、功能与优势一览

本文将为大家讲解&#xff1a;1、企业邮箱的定义&#xff1b;2、企业邮箱的主要功能特点&#xff1b;3、企业邮箱如何选择和部署&#xff1b;4、企业邮箱的运营与维护&#xff1b;5、企业邮箱在实际工作中的应用与挑战&#xff1b;6、2024年最新五大企业邮箱盘点 下面提到的功能…

【kali后续配置】Kali Linux 换源更新及配置SSH服务一文通(一键换源脚本)

在前面&#xff0c;我们已经下载并安装了Kali Linux 2023版本&#xff0c;因为一些事情的耽误&#xff0c;后面的一些操作教程没有发出来&#xff0c;今天给大家补上。 Kali Linux安装 前置准备&#xff1a; VMware安装kali Linux 镜像下载 kali源 官方源 deb http://htt…

基于JavaWeb+SSM+Vue基于微信小程序的网上商城系统的设计和实现

基于JavaWebSSMVue基于微信小程序的网上商城系统的设计和实现 滑到文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 滑到文末获取源码 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想…

UE5 蓝图编辑美化学习

虚幻引擎中干净整洁蓝图的15个提示_哔哩哔哩_bilibili 1.双击线段成节点。 好用&#xff0c;爱用 2.用序列节点 好用&#xff0c;爱用 3.用枚举。 好用&#xff0c;能避免一些的拼写错误 4.对齐节点 两点一水平线 5.节点上下贴节点 &#xff08;以前不懂&#xff0c;现在经常…

Java 内存模型深度解析

优质博文&#xff1a;IT-BLOG-CN 一、并发编程模型的两个关键问题 【1】并发中常见的两个问题&#xff1a;线程之间如何通信及线程之间如何同步。通信是指线程之间以何种机制来交换信息。在命令式编程中&#xff0c;线程之间的通信机制有两种&#xff1a;内存共享和消息传递&…

Python利用Excel读取和存储测试数据完成接口自动化教程

http_request2.py用于发起http请求 #读取多条测试用例#1、导入requests模块import requests#从 class_12_19.do_excel1导入read_data函数from do_excel2 import read_datafrom do_excel2 import write_datafrom do_excel2 import count_case#定义http请求函数COOKIENonedef ht…

深入理解Redis数据结构

目录 Redis的单线程 Redis单线程快的原因 Redis 单线程处理高并发客户端连接 Redis数据结构 字符串&#xff08;String&#xff09; 常用方法 数据结构 哈希表&#xff08;Hash&#xff09; 常用方法 数据结构 列表&#xff08;List&#xff09; 常用方法 数据结构…

微信小程序之WXML 模板语法之数据绑定、事件绑定、wx:if和列表渲染

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

Java深度解析:类的生命周期与类加载过程

文章目录 加载阶段连接阶段-验证连接阶段-准备连接阶段-解析初始化阶段使用卸载 最近在学习Java 虚拟机&#xff0c;学到了类的声明周期&#xff0c;有些比较难理解的点&#xff0c;特地来总结一下。 类的生命周期从大体上来看的话&#xff0c;有五个阶段&#xff0c;分别是加载…

十八周周报

文章目录 摘要文献阅读3D reconstruction of human bodies from single-view and multi-view images: A systematic review简介研究方法搜索策略选择标准搜索结果 三维重建方法单个视图中使用的技术基于参数化人体模型的回归基于非参数人体模型的回归 多个视图中使用的技术基于…