基于单链表实现通讯管理系统!(有完整源码!)

                                                                                个人主页:秋风起,再归来~

                                                                                文章专栏:C语言实战项目                              

                                                                        个人格言:悟已往之不谏,知来者犹可追

                                                                                        克心守己,律己则安!

1、前言

友友们,这篇文章是基于单链表来实现通讯管理系统的,所以一定要先看完我之前写过的一篇关于单链表的实现(文章链接)的文章哦~

其实基于单链表实现通讯录的思路与基于顺讯表实现通讯录的思路是一样的,在这里我就不进行赘述了。如果还没有看过我之前写的一篇基于顺序表实现通讯录(文章链接)的宝子们一定要去看看哦~

2、各种接口的实现

以下是我们希望实现的接口~

//contact.h
#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100//前置声明
typedef struct SListNode contact;//用户数据
typedef struct PersonInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}PeoInfo;//初始化通讯录
void InitContact(contact** con);//添加通讯录数据
void AddContact(contact** con);//展示通讯录数据
void ShowContact(contact* con);//删除通讯录数据
void DelContact(contact** con);//查找通讯录数据
void FindContact(contact* con);//修改通讯录数据
void ModifyContact(contact** con);//销毁通讯录数据
void DestroyContact(contact** con);

2.1 初始化通讯录

我们希望在初始化通讯录时导入之前我们原有文件中的数据,那我们就可以进行如下的操作~

//从文件中导入原数据
void DLoadContact(contact** con)
{FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("open fail\n");return;}PeoInfo p = { 0 };while (fread(&p, sizeof(PeoInfo),1,pf)){SListPushBack(con, p);}printf("历史数据导入成功!\n");fclose(pf);pf = NULL;
}

在初始化通讯录之后加载数据! 

//初始化通讯录
void InitContact(contact** con)
{assert(con);(*con) = NULL;DLoadContact(con);
}

2.2 添加通讯录数据

//添加通讯录数据
void AddContact(contact** con)
{assert(con);PeoInfo p = {0};printf("请输入添加联系人的姓名:");scanf("%s", p.name);printf("请输入添加联系人的性别:");scanf("%s", p.sex);printf("请输入添加联系人的年龄:");scanf("%d", &(p.age));printf("请输入添加联系人的电话:");scanf("%s", p.tel);printf("请输入添加联系人的住址:");scanf("%s", p.addr);SListPushBack(con,p);printf("\n");
}

2.3 删除通讯录数据

在查找通讯录数据之外封装一个函数(findByName)来通过名字查找联系人!

(因为我们在之后的查找和修改接口中都会用到这个方法,所以我们把它封装成一个函数方便我们后续的使用!)

//通过名字查找联系人
contact* findByName(contact* con,char* name)
{assert(con);contact* cur = con;while (cur){if (strcmp(cur->data.name, name) == 0){return cur;}cur = cur->next;}return NULL;
}

在原有单链表的删除指定数据的接口上进行封装(让单链表摇身一变成为通讯录!)

//删除通讯录数据
void DelContact(contact** con)
{assert(con && (*con));char name[NAME_MAX];printf("请输入你要删除的联系人的名字:");scanf("%s", name);contact* pos = findByName(*con,name);if (pos == NULL){printf("您要删除的联系人不存在!\n");return;}SListErase(con, pos);printf("删除成功!\n");
}

2.4 展示通讯录数据

遍历我们的通讯录打印信息!

//展示通讯录数据
void ShowContact(contact* con)
{assert(con);contact* cur = con;printf("名字\t\t性别\t\t年龄\t\t电话\t\t住址\n");//打印表头while (cur){printf("%s\t\t%s\t\t%d\t\t%s\t\t%s\n",cur->data.name,cur->data.sex,cur->data.age,cur->data.tel,cur->data.addr);cur = cur->next;}
}

2.5 查找通讯录数据

//通过名字查找联系人
contact* findByName(contact* con,char* name)
{assert(con);contact* cur = con;while (cur){if (strcmp(cur->data.name, name) == 0){return cur;}cur = cur->next;}return NULL;
}

在接口内部调用该函数! 

//查找通讯录数据
void FindContact(contact* con)
{assert(con);char name[NAME_MAX];printf("请输入你要查找的联系人的名字:");scanf("%s", name);contact* ret = findByName(con, name);if (ret == NULL){printf("您要查找的联系人不存在!\n");return;}printf("找到了!\n");printf("名字\t\t性别\t\t年龄\t\t电话\t\t住址\n");//打印表头printf("%s\t\t%s\t\t%d\t\t%s\t\t%s\n",ret->data.name,ret->data.sex,ret->data.age,ret->data.tel,ret->data.addr);
}

2.6 修改通讯录数据

//通过名字查找联系人
contact* findByName(contact* con,char* name)
{assert(con);contact* cur = con;while (cur){if (strcmp(cur->data.name, name) == 0){return cur;}cur = cur->next;}return NULL;
}

在接口内部调用该函数! 

//修改通讯录数据
void ModifyContact(contact** con)
{assert(con);char name[NAME_MAX];printf("请输入你要修改的联系人的名字:");scanf("%s", name);contact* ret = findByName(*con, name);if (ret == NULL){printf("您要修改的联系人不存在!\n");return;}PeoInfo p = { 0 };printf("请输入修改后联系人的姓名:");scanf("%s", p.name);printf("请输入修改后联系人的性别:");scanf("%s", p.sex);printf("请输入修改后加联系人的年龄:");scanf("%d", &(p.age));printf("请输入修改后联系人的电话:");scanf("%s", p.tel);printf("请输入修改后联系人的住址:");scanf("%s", p.addr);SListModify(ret, p);printf("修改成功!\n");
}

2.7 销毁通讯录数据

因为我们希望在退出通讯管理系统的时候可以将我们的操作都保留下来,所以我们可以对其进行文件操作!

//将输入的数据保存到文件中
void SaveContact(contact** con)
{FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("open fail!\n");return;}contact* cur = *con;while (cur){fwrite(&(cur->data), sizeof(PeoInfo), 1, pf);cur = cur->next;}printf("历史数据保存成功!\n");fclose(pf);pf = NULL;
}

 在销毁通讯录之前保留数据!

//销毁通讯录数据
void DestroyContact(contact** con)
{SaveContact(con);SListDestroy(con);
}

3、完整源码

SeqList.h

#pragma once//避免头文件被多次引用
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include"Contact.h"
typedef PeoInfo SListDataType;//便于改变数据类型//定义一个结构体类型的节点
typedef struct SListNode
{SListDataType data;struct SListNode* next;//存储下一个节点的地址
}SListNode;//1. 新节点的创建
SListNode* SListCreatNode(SListDataType x);//2. 打印单链表
void PrintSList(SListNode* phead);//3. 头插
void SListPushFront(SListNode** phead, SListDataType x);//4. 头删
void  SListPopFront(SListNode** phead);//5. 尾差
void SListPushBack(SListNode** phead, SListDataType x);//6. 尾删
void  SListPopBack(SListNode** phead);//7. 查找元素X
SListNode* SListFind(SListNode* phead, SListDataType x);//8. 在pos位置修改
void SListModify(SListNode* pos, SListDataType x);//9. 在任意位置之前插入
void SListInsert(SListNode** phead, SListNode* pos, SListDataType x);//10. 在任意位置删除
void SListErase(SListNode** phead, SListNode* pos);//11. 销毁单链表
void SListDestroy(SListNode** phead);

Contact.h

#define _CRT_SECURE_NO_WARNINGS//contact.h
#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100//前置声明
typedef struct SListNode contact;//用户数据
typedef struct PersonInfo
{char name[NAME_MAX];char sex[SEX_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}PeoInfo;//初始化通讯录
void InitContact(contact** con);//添加通讯录数据
void AddContact(contact** con);//展示通讯录数据
void ShowContact(contact* con);//删除通讯录数据
void DelContact(contact** con);//查找通讯录数据
void FindContact(contact* con);//修改通讯录数据
void ModifyContact(contact** con);//销毁通讯录数据
void DestroyContact(contact** con);

SeqList.c

#include"SList.h"//1. 新节点的创建
SListNode* SListCreatNode(SListDataType x)
{SListNode* NewNode = (SListNode*)malloc(sizeof(SListNode));//开辟空间if (NewNode == NULL)//判断空间是否开辟成功{perror("malloc fail");return NULL;}NewNode->data = x;//赋值NewNode->next = NULL;//置空return NewNode;
}#if 0
//2. 打印单链表
void PrintSList(SListNode* phead)
{if (phead == NULL){printf("NULL");//如果链表没有元素就打印NULLreturn;}SListNode* cur = phead;//循环单链表打印while (cur != NULL){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n");
}
#endif//3. 头插
void SListPushFront(SListNode** phead, SListDataType x)
{assert(phead);SListNode* newnode = SListCreatNode(x);//创建一个新节点newnode->next = *phead;*phead = newnode;
}//4. 头删
void  SListPopFront(SListNode** phead)
{assert(phead);assert(*phead);//如果没有数据就不用头删,并报错SListNode* cur = (*phead)->next;free(*phead);*phead = cur;
}//5. 尾插
void SListPushBack(SListNode** phead, SListDataType x)
{assert(phead);if (*phead == NULL){*phead = SListCreatNode(x);//创建新节点并插入}else{SListNode* tail = *phead;while (tail->next != NULL)//找到尾节点{tail = tail->next;}tail->next = SListCreatNode(x);//创建新节点并插入}
}//6. 尾删
void  SListPopBack(SListNode** phead)
{assert(phead);assert(*phead);//链表为空就不进行尾删SListNode* tail = *phead;if (tail->next == NULL)//如果链表就只有一个元素就进行头删{SListPopFront(phead);}else{while (tail->next->next != NULL){tail = tail->next;}free(tail->next);tail->next = NULL;}
}#if 0
//7. 查找元素X
SListNode* SListFind(SListNode* phead, SListDataType x)
{assert(phead);while (phead->next != NULL)//注意最后一个节点是没有查找的{if (phead->data == x)return phead;phead = phead->next;}if (phead->data == x)return phead;//最后一个节点没有查找elsereturn NULL;//没找到
}
#endif//8. 在pos位置修改
void SListModify(SListNode* pos, SListDataType x)
{assert(pos);pos->data = x;
}//9. 在任意位置之前插入
void SListInsert(SListNode** phead, SListNode* pos, SListDataType x)
{assert(phead);assert(*phead);if (pos == *phead)//如果pos位置刚好是第一个节点就进行头插{SListPushFront(phead, x);}else{SListNode* newnode = SListCreatNode(x);SListNode* cur = *phead;while (cur->next != pos)//找到pos前一个节点{cur = cur->next;}cur->next = newnode;newnode->next = pos;}
}//10. 在任意位置删除
void SListErase(SListNode** phead, SListNode* pos)
{assert(phead && *phead && pos);if (pos == *phead)//如果pos位置就是第一个节点就进行头删{SListPopFront(phead);}else{SListNode* cur = *phead;while (cur->next != pos)//找到pos前一个节点{cur = cur->next;}cur->next = pos->next;free(pos);}
}//11. 销毁单链表
void SListDestroy(SListNode** phead)
{assert(*phead && phead);SListNode* cur = *phead;while (cur != NULL){SListNode* tmp = cur->next;free(cur);cur = tmp;}*phead = NULL;
}

Contact.c

#include"SList.h"//从文件中导入原数据
void DLoadContact(contact** con)
{FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("open fail\n");return;}PeoInfo p = { 0 };while (fread(&p, sizeof(PeoInfo),1,pf)){SListPushBack(con, p);}printf("历史数据导入成功!\n");fclose(pf);pf = NULL;
}//初始化通讯录
void InitContact(contact** con)
{assert(con);(*con) = NULL;DLoadContact(con);
}//添加通讯录数据
void AddContact(contact** con)
{assert(con);PeoInfo p = {0};printf("请输入添加联系人的姓名:");scanf("%s", p.name);printf("请输入添加联系人的性别:");scanf("%s", p.sex);printf("请输入添加联系人的年龄:");scanf("%d", &(p.age));printf("请输入添加联系人的电话:");scanf("%s", p.tel);printf("请输入添加联系人的住址:");scanf("%s", p.addr);SListPushBack(con,p);printf("\n");
}//展示通讯录数据
void ShowContact(contact* con)
{assert(con);contact* cur = con;printf("名字\t\t性别\t\t年龄\t\t电话\t\t住址\n");//打印表头while (cur){printf("%s\t\t%s\t\t%d\t\t%s\t\t%s\n",cur->data.name,cur->data.sex,cur->data.age,cur->data.tel,cur->data.addr);cur = cur->next;}
}//通过名字查找联系人
contact* findByName(contact* con,char* name)
{assert(con);contact* cur = con;while (cur){if (strcmp(cur->data.name, name) == 0){return cur;}cur = cur->next;}return NULL;
}//删除通讯录数据
void DelContact(contact** con)
{assert(con && (*con));char name[NAME_MAX];printf("请输入你要删除的联系人的名字:");scanf("%s", name);contact* pos = findByName(*con,name);if (pos == NULL){printf("您要删除的联系人不存在!\n");return;}SListErase(con, pos);printf("删除成功!\n");
}//查找通讯录数据
void FindContact(contact* con)
{assert(con);char name[NAME_MAX];printf("请输入你要查找的联系人的名字:");scanf("%s", name);contact* ret = findByName(con, name);if (ret == NULL){printf("您要查找的联系人不存在!\n");return;}printf("找到了!\n");printf("名字\t\t性别\t\t年龄\t\t电话\t\t住址\n");//打印表头printf("%s\t\t%s\t\t%d\t\t%s\t\t%s\n",ret->data.name,ret->data.sex,ret->data.age,ret->data.tel,ret->data.addr);
}//修改通讯录数据
void ModifyContact(contact** con)
{assert(con);char name[NAME_MAX];printf("请输入你要修改的联系人的名字:");scanf("%s", name);contact* ret = findByName(*con, name);if (ret == NULL){printf("您要修改的联系人不存在!\n");return;}PeoInfo p = { 0 };printf("请输入修改后联系人的姓名:");scanf("%s", p.name);printf("请输入修改后联系人的性别:");scanf("%s", p.sex);printf("请输入修改后加联系人的年龄:");scanf("%d", &(p.age));printf("请输入修改后联系人的电话:");scanf("%s", p.tel);printf("请输入修改后联系人的住址:");scanf("%s", p.addr);SListModify(ret, p);printf("修改成功!\n");
}//将输入的数据保存到文件中
void SaveContact(contact** con)
{FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("open fail!\n");return;}contact* cur = *con;while (cur){fwrite(&(cur->data), sizeof(PeoInfo), 1, pf);cur = cur->next;}printf("历史数据保存成功!\n");fclose(pf);pf = NULL;
}
//销毁通讯录数据
void DestroyContact(contact** con)
{SaveContact(con);SListDestroy(con);
}

 这里我就没有单独去写一个菜单了,本身的意义也并不大,但是如果友友们想写一个来玩一玩,可以看看我之前那篇基于顺序表实现通讯录(文章链接,那里有菜单的模版(只要改几个接口的名字就行了)~

4、 完结散花

好了,这期的分享到这里就结束了~

如果这篇博客对你有帮助的话,可以用你们的小手指点一个免费的赞并收藏起来哟~

如果期待博主下期内容的话,可以点点关注,避免找不到我了呢~

我们下期不见不散~~

​​​​

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

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

相关文章

ARM单片机的GPIO口在控制不同LED、按键时的设置

个人备忘&#xff0c;不喜勿喷。 GPIO口在驱动共阴极、共阳极LED灯时需要不同的初始化设置 对于这一类的led灯&#xff1a; 最好选择推挽、上拉、高速输出&#xff0c;同时IO口初始化时需要拉高。 上面这种需要下拉输入&#xff1b; 上图这种需要上拉输入&#xff0c;这样才…

MySQL基础知识——MySQL事务

事务背景 什么是事务&#xff1f; 一组由一个或多个数据库操作组成的操作组&#xff0c;能够原子的执行&#xff0c;且事务间相互独立&#xff1b; 简单来说&#xff0c;事务就是要保证一组数据库操作&#xff0c;要么全部成功&#xff0c;要么全部失败。 注&#xff1a;MyS…

Tomcat启动闪退的10个解决小技巧

引言 大家好&#xff01;在我们日常开发中&#xff0c;使用Tomcat作为Web服务器是相当常见的。 然而&#xff0c;遇到Tomcat启动后立即闪退的问题也不是什么稀罕事。 这种情况可能会让人感到困惑和沮丧&#xff0c;特别是当你急需完成一个项目或者修复一个重要的bug时。 不过…

数据集学习

1&#xff0c;CIFAR-10数据集 CIFAR-10数据集由10个类的60000个32x32彩色图像组成&#xff0c;每个类有6000个图像。有50000个训练图像和10000个测试图像。 数据集分为五个训练批次和一个测试批次&#xff0c;每个批次有10000个图像。测试批次包含来自每个类别的恰好1000个随机…

【SpringBoot】获取参数

获取参数 传递单个参数传递多个参数传递对象后端参数重命名传递数组传递 json 数据获取 URL 中参数上传文件获取 cookie 和 session获取cookie获取session 传递单个参数 RequestMapping("/user") RestController public class UserController {// 传递单个参数Reque…

FPGA(Verilog)实现按键消抖

实现按键消抖功能&#xff1a; 1.滤除按键按下时的噪声和松开时的噪声信号。 2.获取已消抖的按键按下的标志信号。 3.实现已消抖的按键的连续功能。 Verilog实现 模块端口 key_filter(input wire clk ,input wire rst_n ,input wire key_in , //按下按键时为0output …

MemberPress配置和使用会员登录页面

目录 隐藏 创建会员登录页面 编辑登录页面 设计您的登录页面 链接到您的登录页面 创建会员登录页面 要创建MemberPress会员登录页面&#xff0c;您需要做的就是导航到 MemberPress > 设置 > 页面选项卡&#xff0c;然后在页面顶部附近的“MemberPress 登录页面”…

【数据分享】中国首套1米分辨率土地覆盖数据(2023年发布)

土地覆盖数据是我们在各项研究中都非常常用的数据&#xff01;本次我们整理的是全国各城市的1米分辨率的土地覆盖数据&#xff01; 武汉大学李卓鸿、何伟等研究者基于深度学习框架和开放数据&#xff0c;具体包括全球土地覆盖&#xff08;GLC&#xff09;数据、OSM地图数据、谷…

SpringMVC(二)【请求与响应】

0、测试环境 我们简化开发&#xff0c;创建一个简单的环境&#xff08;因为没有其它包比如 service、dao&#xff0c;所以这里不用 Spring 容器&#xff0c;只用 SpringMVC 容器&#xff09;&#xff1a; Servelet 容器配置&#xff1a; package com.lyh.config;import org.s…

c语言多功能计算软件170

定制魏&#xff1a;QTWZPW&#xff0c;获取更多源码等 目录 题目 要求 主要代码片段 题目 设计一个计算器软件&#xff0c;具备如下功能提示界面。 要求 设计出界面&#xff0c;注意界面名称最后为自己的姓名&#xff1b;&#xff08;20分&#xff09;能够实现加、减、乘、…

【目标检测数据集】VOC2012 数据集与 SBD dataset 介绍

一、介绍 VOC 数据是 PASCAL VOC Challenge 用到的数据集&#xff0c;官网&#xff1a;http://host.robots.ox.ac.uk/pascal/VOC/ 备注&#xff1a;VOC数据集常用的均值为&#xff1a;mean_RGB(122.67891434, 116.66876762, 104.00698793) Pytorch 上通用的数据集的归一化指…

紫光展锐T610平台_4G安卓核心板方案定制开发

紫光展锐T610核心板配备Android 11操作系统&#xff0c;采用12nm制程工艺。该处理器CPU由2颗基于Cortex-A75架构的大核心和6颗基于Cortex-A55架构的小核心组成&#xff0c;最高主频为1.8GHz。GPU采用的是614.4MHz的Mali G52&#xff0c;可以流畅播放2400*1080分辨率视频&#x…