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

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

                                                                                文章专栏: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.rhkb.cn/news/311427.html

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

相关文章

JavaScript基础:js介绍、变量、数据类型以及类型转换

目录 介绍 引入方式 内部方式 外部形式 注释和结束符 单行注释 多行注释 结束符 输入和输出 输出 输入 变量 声明 赋值 关键字 变量名命名规则 常量 数据类型 数值类型 字符串类型 布尔类型 undefined 类型转换 隐式转换 显式转换 Number ✨介绍 &a…

数字IC/FPGA——亚稳态及跨时钟域

什么是亚稳态亚稳态会造成什么平均故障间隔时间如何解决亚稳态同步时钟和异步时钟单bit电平信号如何跨时钟域单bit脉冲信号如何跨时钟域多bit信号如何跨时钟域 目录 一、亚稳态1.基本概念2.危害3.平均故障时间4.解决亚稳态的方法 二、跨时钟域1.同步电路和异步电路&#xff08;…

模板初阶的学习

目录&#xff1a; 一&#xff1a;泛型模板 二&#xff1a;函数模板 三&#xff1a;类模板 1&#xff1a;泛型模板 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础。 以交换函数为列进行讲解&#xff1a; void Swap(…

【ENSP】华为三层交换机配置AAA认证,开启telnet服务

配置步骤 1.给交换机配置ip地址&#xff0c;以便登陆 2.配置AAA&#xff0c;用户名&#xff0c;密码&#xff0c;服务类型&#xff0c;用户权限 3.配置接入设备的数量 4.开启telnet服务 LSW2交换机配置 u t m #关闭提示 sys …

JVM主要知识点详解

目录 1. 性能监控和调优 1.1 调优相关参数 1.2 内存泄漏排查 1.3 cpu飙⾼ 2. 内存与垃圾回收 2.1JVM的组成&#xff08;面试题&#xff09; 2.2 Java虚拟机栈的组成 2.3 本地方法栈 2.4 堆 2.5 方法区&#xff08;抽象概念&#xff09; 2.5.1 方法区和永久代以及元空…

如何利用纯前端技术,实现一个网页版视频编辑器?

纯网页版视频编辑器 一、前言二、功能实现三、所需技术四、部分功能实现4.1 素材预设4.2 多轨道剪辑 一、前言 介绍&#xff1a;本篇文章打算利用纯前端的技术&#xff0c;来实现一个网页版的视频编辑器。为什么突然想做一个这么项目来呢&#xff0c;主要是最近一直在利用手机…

【机器学习】Logistic与Softmax回归详解

在深入探讨机器学习的核心概念之前&#xff0c;我们首先需要理解机器学习在当今世界的作用。机器学习&#xff0c;作为人工智能的一个重要分支&#xff0c;已经渗透到我们生活的方方面面&#xff0c;从智能推荐系统到自动驾驶汽车&#xff0c;再到医学影像的分析。它能够从大量…

服务器Linux搭建NPM私有仓库

服务器Linux搭建NPM私有仓库 环境搭建 安装 nodejs nodejs官网&#xff1a;https://nodejs.org/en/download/package-manager 可以去官网自行下载nodejs的Linux版本&#xff0c;但是出于别的原因考虑&#xff0c;可以使用nvm去下载nodejs这样会切换nodejs也方便。 nvm 这…

Slf4j+Log4j简单使用

Slf4jLog4j简单使用 文章目录 Slf4jLog4j简单使用一、引入依赖二、配置 log4j2.xml2.1 配置结构2.2 配置文件 三、使用四、使用MDC完成日志ID4.1 程序入口处4.2 配置文件配置打印4.3 多线程日志ID传递配置 五. 官网 一、引入依赖 <dependencies><dependency><g…

再获权威认可 比瓴科技入选安全牛优质企业

近日&#xff0c;安全牛面向国内网络安全初创企业展开调研&#xff0c;比瓴科技入围安全牛&#xff08;第四版&#xff09;《优质网络安全初创企业推荐》报告。 安全牛以问卷、访谈等形式先后调研了110多家优秀的初创型网络安全企业。从5大维度&#xff0c;对企业的未来发展潜力…

边缘计算网关主要有哪些功能?-天拓四方

随着物联网&#xff08;IoT&#xff09;的快速发展和普及&#xff0c;边缘计算网关已经成为了数据处理和传输的重要枢纽。作为一种集成数据采集、协议转换、数据处理、数据聚合和远程控制等多种功能的设备&#xff0c;边缘计算网关在降低网络延迟、提高数据处理效率以及减轻云数…

使用Python模仿文件行为

在Python中&#xff0c;你可以通过文件操作函数&#xff08;如open()函数&#xff09;以及模拟输入输出流的库&#xff08;如io模块&#xff09;来模拟文件行为。下面是一些示例&#xff0c;展示了如何使用这些工具在Python中模拟文件行为。 1、问题背景 在编写一个脚本时&…

动态规划|416.分割等和子集

力扣题目链接 class Solution { public:bool canPartition(vector<int>& nums) {int sum 0;// dp[i]中的i表示背包内总和// 题目中说&#xff1a;每个数组中的元素不会超过 100&#xff0c;数组的大小不会超过 200// 总和不会大于20000&#xff0c;背包最大只需要其…

[C语言][数据结构][链表] 单链表的从零实现!

目录 零.必备知识 1.一级指针 && 二级指针 2. 节点的成员列表 a.数据 b.指向下一个节点的指针. 3. 动态内存空间的开辟 (malloc-calloc-realloc) 一.单链表的实现与销毁 1.1 节点的定义 1.2 单链表的尾插 1.3 单链表的头插 1.4 单链表的尾删 1.5 单链表的头删 1…

ObjectiveC-第一部分-基础入门-学习导航

专题地址:MacOS一站式程序开发系列专题 第一部分:基础入门学习导航 OSX-01-Mac OS应用开发概述:简单介绍下MacOS生态、Xcode使用以及使用Xcode创建app的方法OSX-02-Mac OS应用开发系列课程大纲和章节内容设计:介绍下此系列专题的文章内容组织形式以及此系列专题的覆盖内容…

Angular 使用DomSanitizer防范跨站脚本攻击

跨站脚本Cross-site scripting 简称XSS&#xff0c;是代码注入的一种&#xff0c;是一种网站应用程序的安全漏洞攻击。它允许恶意用户将代码注入到网页上&#xff0c;其他用户在使用网页时就会收到影响&#xff0c;这类攻击通常包含了HTML和用户端脚本语言&#xff08;JS&…

金融机构面临的主要AI威胁:身份伪造统与社会工程攻击

目录 攻击者利用AI威胁的过程 金融机构如何防范AI攻击 针对AI欺诈的解决方案 2023年11月&#xff0c;诈骗分子伪装成某科技公司郭先生的好友&#xff0c;骗取430万元&#xff1b;2023年12月&#xff0c;一名留学生父母收到孩子“被绑架”的勒索视频&#xff0c;被索要500万元赎…

打造高效同城O2O平台教学:外卖送餐APP开发技术解析

今天&#xff0c;笔者将深入讲解外卖送餐APP开发技术&#xff0c;带您了解如何打造一款高效的同城O2O平台。 一、需求分析与功能设计 在开发外卖送餐APP之前&#xff0c;首先需要进行充分的需求分析&#xff0c;明确用户的需求和期望。基于用户的需求&#xff0c;设计合理的功…

分布鲁棒优化

部分代码 % 确定性优化结果 clc close all clear % A Benchmark Case of Optimal Recourse Under Wind Power Uncertainty D 320; %MW % demand what 60; % mean wind output V 3000; % $/MW % penalty cost for load loss a 3; % $/MW b 30; …

腾讯云幻兽帕鲁一键开服教程

腾讯云作为领先的云计算服务提供商&#xff0c;为广大用户提供了便捷、高效的游戏服务器搭建解决方案。其中&#xff0c;幻兽帕鲁一键开服功能&#xff0c;更是让游戏开服变得简单易懂。本文将为大家详细介绍腾讯云幻兽帕鲁一键开服的步骤&#xff0c;帮助大家轻松搭建自己的游…