C语言数据结构-基于单链表实现通讯录

news2024/11/20 10:35:18

文章目录

  • 1 基础要求
  • 2 通讯录功能
    • 2.1 引入单链表的文件
    • 2.2 定义联系人数据结构
    • 2.3 打开通讯录
    • 2.4 保存数据后销毁通讯录
    • 2.5 添加联系人
    • 2.6 删除联系人
    • 2.7 修改联系人
    • 2.8 查找联系人
    • 2.9 查看通讯录
  • 3 通讯录代码展示
    • 3.1 SeqList_copy.h
    • 3.2 SeqList_copy.c
    • 3.3 Contact.h
    • 3.4 Contact.c
    • 3.5 test.c
    • 3.6 调试控制台截图


1 基础要求

单链表,文件操作,结构体,二级指针
思路:利用上一篇博客-单链表,对单链表简易修改,应用到通讯录.

2 通讯录功能

通讯录只能能存100个人
用户信息:名字,性别,年龄,电话,地址
通讯录的展示,增,删,改,查,找.
联系人信息存储

2.1 引入单链表的文件

为了显现区别,笔者备份单链表的文件并且更名为SeqList_copy.hSeqList_copy.c
创建Contact.hContact.c以及测试代码功能的test.c
test.cContact.c引用的头文件都是Contact.hSeqList_copy.h
在这里插入图片描述

2.2 定义联系人数据结构

Contact.h头文件中
定义名字最大长度,性别最大长度,电话最大长度,地址最大长度

#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50
//前置声明
typedef struct SListNode contact;
//定义结构体
typedef struct ContactInfo
{ 
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}ConInfo;

2.3 打开通讯录

void ContactInit(contact** pcon)
{
	FILE* pf = fopen("Contact_Info.txt", "rb");	//二进制方式打开文件
	if (pf == NULL)
	{
		perror("fopen error.\n");  //主动报错,打开失败
		return;
	}
	ConInfo info;
	//回顾一下fread 
	//size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
	//从流中读取一个由count元素组成的数组,每个元素的大小为size字节,并将它们存储在ptr指定的内存块中。
	//流的位置指示器按读取的总字节数前进。
	//如果成功读取的总字节数为(size * count)
	while (fread(&info, sizeof(info), 1, pf))
	{
		SLPushBack(pcon, info);
	}
	printf("历史数据已导入通讯录\n");
}

2.4 保存数据后销毁通讯录

销毁通讯录之前一定要保存数据,不然2.3打开有存储联系人的通讯录的作用就没有了

void ContactSave(contact* con)
{
	FILE* pf = fopen("Contact_Info.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen error\n");
		return;
	}
	contact* cur = con;
	while (cur)
	{
		fwrite(&(cur->data), sizeof(cur->data), 1, pf);
		cur = cur->next;
	}
	printf("成功保存通讯录数据\n");
}

void ContactDestory(contact** pcon)
{
	ContactSave(*pcon);
	SLDestory(pcon);
}

2.5 添加联系人

使用单链表一节中尾插法添加数据

void ContactAdd(contact** pcon)
{
	ConInfo info;
	printf("请输入添加联系人姓名:\n");
	scanf("%s", &info.name);
	printf("请输入添加联系人性别:\n");
	scanf("%s", &info.sex);
	printf("请输入添加联系人年龄:\n");
	scanf("%d", &info.age);
	printf("请输入添加联系人电话:\n");
	scanf("%s", &info.tel);
	printf("请输入添加联系人地址:\n");
	scanf("%s", &info.addr);

	SLPushBack(pcon, info);
	printf("已添加联系人数据\n");
}

2.6 删除联系人

借助FindByName()函数,找到索引.然而缺陷明显,找到的索引是第一次出现的输入的姓名,同样,只能通过姓名查找

//我们这里通过姓名删除联系人
contact* FindByName(contact* con, char name[])
{
	contact* cur = con;
	while (cur)
	{
		if (strcmp(cur->data.name,name) == 0)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

void ContactDel(contact** pcon)
{
	char name[NAME_MAX];
	printf("请输入你要删除的联系人姓名:\n");
	scanf("%s", name);
	contact* pos = FindByName(*pcon, name);
	if (pos == NULL)
	{
		printf("该联系人不存在\n");
		return;
	}
	SLErase(pcon, pos);
	printf("已删除该联系人\n");
}

2.7 修改联系人

注意age年龄是int整型,其他四个数据结构都是数组,用scanf时,这里的数组相当于首元素地址,不用&.

void ContactModify(contact* con)
{
	char name[NAME_MAX];
	printf("请输入你要修改的联系人姓名:\n");
	scanf("%s", name);
	contact* pos = FindByName(con, name);
	if (pos == NULL)
	{
		printf("该联系人不存在\n");
		return;
	}
	printf("该联系人姓名修改为:\n");
	scanf("%s", pos->data.name);	
	printf("该联系人性别修改为:\n");
	scanf("%s", pos->data.sex);	
	printf("该联系人年龄修改为:\n");
	scanf("%d", &pos->data.age);	
	printf("该联系人电话修改为:\n");
	scanf("%s", pos->data.tel);
	printf("该联系人地址修改为:\n");
	scanf("%s", pos->data.addr);

	printf("修改成功\n");
}

2.8 查找联系人

同样根据姓名查看详细联系人的通讯录信息

void ContactFind(contact* con)
{
	char name[NAME_MAX];
	printf("请输入你要查找的联系人姓名:\n");
	scanf("%s", name);
	contact* pos = FindByName(con, name);
	if (pos == NULL)
	{
		printf("该联系人不存在\n");
		return;
	}
	printf("找到了\n");
	printf("%s %s %d %s %s\n",
		pos->data.name,
		pos->data.sex,
		pos->data.age,
		pos->data.tel,
		pos->data.addr
	);
}

2.9 查看通讯录

第一次自己写的时候,cur=cur->next放在while循环外面了.QAQ

void ContactShow(contact* con)
{
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	contact* cur = con;
	while (cur)
	{
		printf("%s %s %d %s %s\n", 
			cur->data.name, 
			cur->data.sex, 
			cur->data.age, 
			cur->data.tel, 
			cur->data.addr);
		cur = cur->next;
	}
}

3 通讯录代码展示

3.1 SeqList_copy.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include"Contact.h"


//定义链表的结构
//typedef int SLDataType
typedef struct ContactInfo SLDataType;   //更改SLDataType的类型

typedef struct SListNode
{
	SLDataType data;	//保存的数据
	struct SListNode* next;		//指针变量存放下一个节点的地址
}SLNode;

//1 打印链表
void SLPrint(SLNode* phead);

//2 尾插
void SLPushBack(SLNode** pphead, SLDataType x);
//3 头插
void SLPushFront(SLNode** pphead, SLDataType x);

//4 尾删
void SLPopBack(SLNode** pphead);

//5 头删
void SLPopFront(SLNode** pphead);

//SLFind()找到要查找数据的下标
//找节点的函数这里传一级实际上就可以了,因为不改变头结点
//但是这里要写二级指针,因为要保持接口一致性
//缺点:这个函数有一定的局限性,他找到数据x的下标是第一次出现的x的下标后,不会找后续的x的下标
SLNode* SLFind(SLNode** pphead, SLDataType x);

//6 定点前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x);

//7 定点后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x);

//8 删除pos节点
void  SLErase(SLNode** pphead, SLNode* pos);

//9 删除pos后的节点
void SLEraseAfter(SLNode* pos);

//10 销毁链表
void SLDestory(SLNode** pphead);

3.2 SeqList_copy.c

#include"SList_copy.h"

//1 创建新的节点的函数
SLNode* SLBuyNode(SLDataType x)
{
	SLNode* node = (SLNode*)malloc(sizeof(SLNode));
	node->data = x;
	node->next = NULL;
	return node;
}

//2 尾插
void SLPushBack(SLNode** pphead, SLDataType x)	//保存第一个节点的指针的地址
{
	assert(pphead);
	//创建一个节点
	SLNode* node = SLBuyNode(x);
	if (*pphead == NULL)
	{
		*pphead = node;
		return;
	}
	//链表不为空,找尾
	SLNode* pcur = *pphead;
	while (pcur->next)//相当于pcur->next!=NULL
	{
		pcur = pcur->next;
	}
	pcur->next = node;
}

//3 头插
void SLPushFront(SLNode** pphead, SLDataType x)
{
	assert(pphead);
	SLNode* node = SLBuyNode(x);
	//新结点跟头结点连接起来
	node->next = *pphead;
	//让新节点成为头结点
	*pphead = node;
}

//4 尾删
void SLPopBack(SLNode** pphead)
{
	assert(pphead);

	assert(*pphead);	//第一个节点不能为空
	//判断只有一个结点的情况
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}

	//找到尾节点和尾节点的前一个节点
	SLNode* pre = NULL;
	SLNode* ptail = *pphead;
	while (ptail->next)
	{
		pre = ptail;
		ptail = ptail->next;
	}
	//pre的next指针不指向ptail,而是指向ptail的下一个节点
	//pre->next = NULL;
	pre->next = ptail->next;
	//因为在SLPrint(SLNode* phead)函数中有判断节点是否为空while (pcur),所以置空
	free(ptail);
	ptail = NULL;

}

//5 头插
void SLPopFront(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);	//第一个节点不能为空
	SLNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
	del = NULL;
}

//6 定点前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{
	assert(pphead);
	assert(pos);	//pos不能为空
	assert(*pphead);  //NULL前插入数据是荒谬的,所以assert第一个节点
	SLNode* node = SLBuyNode(x);

	//当只有一个结点(pos就是第一个节点)
	//if (((*pphead)->next) == NULL||pos==*pphead),可以简化成以下代码
	if (pos == *pphead) {
		node->next = *pphead;
		*pphead = node;
		return;
	}

	//找到pos的前一个节点
	SLNode* pre = *pphead;
	while (pre->next != pos)
	{
		pre = pre->next;
	}
	//处理pre node pos的位置
	node->next = pos;
	pre->next = node;
}

//7 定点后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x)
{
	assert(pos);
	SLNode* node = SLBuyNode(x);
	node->next = pos->next;
	pos->next = node;
}

//8 删除pos节点
void SLErase(SLNode** pphead, SLNode* pos)
{
	assert(*pphead);
	assert(pphead);
	assert(pos);
	//pos是头结点
	if (pos == *pphead)
	{
		*pphead = (*pphead)->next;
		free(pos);
		return;
	}
	//pos不是头结点,找pos的前一个节点
	SLNode* pre = *pphead;
	while (pre->next != pos)
	{
		pre = pre->next;
	}
	pre->next = pos->next;
	free(pos);
	pos = NULL;   //代码规范
}

//9 删除pos后的节点
void SLEraseAfter(SLNode* pos)
{
	//删除pos之后的节点也不能空
	assert(pos && pos->next);
	SLNode* del = pos->next;
	pos->next = del->next;
	free(del);
}

void SLDestory(SLNode** pphead)
{
	assert(pphead);
	SLNode* pcur = *pphead;
	while (pcur)
	{
		SLNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	//头结点记得置空
	*pphead = NULL;
}

3.3 Contact.h

#pragma once
//创建保存联系人数据的结构
#define NAME_MAX 120
#define SEX_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 50

typedef struct ContactInfo
{
	char name[NAME_MAX];
	char sex[SEX_MAX];
	int age;
	char tel[TEL_MAX];
	char addr[ADDR_MAX];
}ConInfo;
//前置声明
typedef struct SListNode contact;

//1.打开通讯录
void ContactInit(contact** pcon);

//2.保存数据后销毁通讯录
void ContactDestory(contact** pcon);

//3.添加联系人
void ContactAdd(contact** pcon);

//4.删除联系人
void ContactDel(contact** pcon);

//5.修改联系人
void ContactModify(contact* con);

//6.查找联系人
void ContactFind(contact* pcon);

//7.查看通讯录
void ContactShow(contact* pcon);


3.4 Contact.c

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SList_copy.h"

//1.打开通讯录
void ContactInit(contact** pcon)
{
	FILE* pf = fopen("Contact_Info.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen error.\n");  //主动报错,打开失败
		return;
	}
	ConInfo info;
	//回顾一下fread 
	//size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
	//从流中读取一个由count元素组成的数组,每个元素的大小为size字节,并将它们存储在ptr指定的内存块中。
	//流的位置指示器按读取的总字节数前进。
	//如果成功读取的总字节数为(size * count)
	while (fread(&info, sizeof(info), 1, pf))
	{
		SLPushBack(pcon, info);
	}
	printf("历史数据已导入通讯录\n");
}

void ContactSave(contact* con)
{
	FILE* pf = fopen("Contact_Info.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen error\n");
		return;
	}
	contact* cur = con;
	while (cur)
	{
		fwrite(&(cur->data), sizeof(cur->data), 1, pf);
		cur = cur->next;
	}
	printf("成功保存通讯录数据\n");
}

void ContactDestory(contact** pcon)
{
	ContactSave(*pcon);
	SLDestory(pcon);
}

void ContactAdd(contact** pcon)
{
	ConInfo info;
	printf("请输入添加联系人姓名:\n");
	scanf("%s", &info.name);
	printf("请输入添加联系人性别:\n");
	scanf("%s", &info.sex);
	printf("请输入添加联系人年龄:\n");
	scanf("%d", &info.age);
	printf("请输入添加联系人电话:\n");
	scanf("%s", &info.tel);
	printf("请输入添加联系人地址:\n");
	scanf("%s", &info.addr);

	SLPushBack(pcon, info);
	printf("已添加联系人数据\n");
}

//我们这里通过姓名删除联系人
contact* FindByName(contact* con, char name[])
{
	contact* cur = con;
	while (cur)
	{
		if (strcmp(cur->data.name,name) == 0)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

void ContactDel(contact** pcon)
{
	char name[NAME_MAX];
	printf("请输入你要删除的联系人姓名:\n");
	scanf("%s", name);
	contact* pos = FindByName(*pcon, name);
	if (pos == NULL)
	{
		printf("该联系人不存在\n");
		return;
	}
	SLErase(pcon, pos);
	printf("已删除该联系人\n");
}

void ContactModify(contact* con)
{
	char name[NAME_MAX];
	printf("请输入你要修改的联系人姓名:\n");
	scanf("%s", name);
	contact* pos = FindByName(con, name);
	if (pos == NULL)
	{
		printf("该联系人不存在\n");
		return 1;
	}
	printf("该联系人姓名修改为:\n");
	scanf("%s", pos->data.name);	
	printf("该联系人性别修改为:\n");
	scanf("%s", pos->data.sex);	
	printf("该联系人年龄修改为:\n");
	scanf("%d", &pos->data.age);	
	printf("该联系人电话修改为:\n");
	scanf("%s", pos->data.tel);
	printf("该联系人地址修改为:\n");
	scanf("%s", pos->data.addr);

	printf("修改成功\n");
}

void ContactFind(contact* con)
{
	char name[NAME_MAX];
	printf("请输入你要查找的联系人姓名:\n");
	scanf("%s", name);
	contact* pos = FindByName(con, name);
	if (pos == NULL)
	{
		printf("该联系人不存在\n");
		return;
	}
	printf("找到了\n");
	printf("%s %s %d %s %s\n",
		pos->data.name,
		pos->data.sex,
		pos->data.age,
		pos->data.tel,
		pos->data.addr
	);
}

void ContactShow(contact* con)
{
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	contact* cur = con;
	while (cur)
	{
		printf("%s %s %d %s %s\n", 
			cur->data.name, 
			cur->data.sex, 
			cur->data.age, 
			cur->data.tel, 
			cur->data.addr);
		cur = cur->next;
	}
}



3.5 test.c

test()我封装了五个函数,都是用来测试通讯录功能的,调试结束后,就将函数封装在一起,写一个菜单完成通讯录功能.

#define _CRT_SECURE_NO_WARNINGS
#include"Contact.h"
#include"SList_copy.h"

void test1()
{
	contact *pcontact=NULL;
	ContactInit(&pcontact);
}

void test2()
{
	contact* pcontact = NULL;
	ContactInit(&pcontact);
	ContactAdd(&pcontact);
	ContactDel(&pcontact);
	ContactShow(pcontact);

}

void test3()
{
	contact* pcontact = NULL;

	ContactInit(&pcontact);
	ContactShow(pcontact);
	ContactAdd(&pcontact);
	ContactShow(pcontact);
	ContactDel(&pcontact);
	ContactShow(pcontact);
}
void test4()
{
	contact* pcontact = NULL;

	ContactInit(&pcontact);
	ContactAdd(&pcontact);
	ContactAdd(&pcontact);
	ContactShow(pcontact);
	ContactFind(pcontact);

	ContactShow(pcontact);

}

void test5()
{
	contact* pcontact = NULL;

	ContactInit(&pcontact);
	ContactAdd(&pcontact);
	ContactShow(pcontact);
	ContactModify(pcontact);

	ContactShow(pcontact);

	ContactDestory(&pcontact);
}


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

int main()
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	int op = 0;
	contact* con=NULL;
	ContactInit(&con);
	do {
		menu();
		printf("请选择:\n");
		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:
			printf("输入错误\n");
			break;
		}
	} while (op!=0);
	ContactDestory(&con);

	return 0;
}

3.6 调试控制台截图

在这里插入图片描述

这里忘记啥问题了,一转眼就忘了
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在多次语法错误,死循环,输出乱码,代码崩溃后,终于简单完成通讯录的功能!

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

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

相关文章

【论文阅读】Reachability and distance queries via 2-hop labels

Cohen E, Halperin E, Kaplan H, et al. Reachability and distance queries via 2-hop labels[J]. SIAM Journal on Computing, 2003, 32(5): 1338-1355. Abstract 图中的可达性和距离查询是许多应用的基础&#xff0c;从地理导航系统到互联网路由。其中一些应用程序涉及到巨…

免费开源-数字孪生城市污水处理平台

智慧城市污水处理平台&#xff0c;基于污水厂三维模型可视化场景&#xff0c;结合物联网IOT、视频监控以及综合运营数据&#xff0c;增加污水处理厂的掌控力度。飞渡科技利用数字孪生技术结合物联网IOT技术&#xff0c;直观展现各污水处理站点的整体建设规模&#xff0c;以及污…

pytorch:YOLOV1的pytorch实现

pytorch&#xff1a;YOLOV1的pytorch实现 注&#xff1a;本篇仅为学习记录、学习笔记&#xff0c;请谨慎参考&#xff0c;如果错误请评论指出。 参考&#xff1a; 动手学习深度学习pytorch版——从零开始实现YOLOv1 目标检测模型YOLO-V1损失函数详解 3.1 YOLO系列理论合集(YOL…

Windows Service Name重复问题

Windows Service Name重复问题 1&#xff0c;问题 2&#xff0c;打开命令提示符&#xff0c;管理员身份运行 3&#xff0c;输入命令&#xff1a;sc delete MYSQL57 4&#xff0c;验证一下&#xff0c;可以看见已经没有感叹号啦 &#xff0c;可以看见已经没有感叹号啦

基于Qt的Live2D模型显示以及控制

基于Qt的Live2D模型显示以及控制 基本说明 Live2D官方提供有控制Live2D模型的SDK,而且还提供了一个基于OpenGL的C项目Example,我们可以基于该项目改成Qt的项目&#xff0c;做一个桌面端的Live2D桌宠程序。 官方例子 经过改造效果如下图所示。 官方项目配置 下载官方提供的SD…

视觉检测系统在半导体行业的应用

一、半导体产业链概述 半导体产业链是现代电子工业的核心组成部分&#xff0c;涵盖了从原材料到最终产品的整个生产过程。这个产业链主要分为以下几个环节&#xff1a; 1.原材料供应&#xff1a;半导体行业的基石是半导体材料&#xff0c;如硅片、化合物半导体等。这些材料需要…

CentOS7安装Docker,DockerCompose

安装docker 1、卸载docker 查看是否有旧版本docker docker info首先检测我们虚拟机是否已经安装过Docker&#xff0c;如果安装则需卸载。代码中“\”符号为换行符&#xff0c;相当于一行内容分为多行&#xff0c;这是检测docker的各种组件 yum remove docker \docker-clien…

高项备考葵花宝典-项目进度管理输入、输出、工具和技术(上,很详细考试必过)

项目进度管理的目标是使项目按时完成。有效的进度管理是项目管理成功的关键之一&#xff0c;进度问题在项目生命周期内引起的冲突最多。 小型项目中&#xff0c;定义活动、排列活动顺序、估算活动持续时间及制定进度模型形成进度计划等过程的联系非常密切&#xff0c;可以视为一…

高项备考葵花宝典-项目进度管理输入、输出、工具和技术(中,很详细考试必过)

项目进度管理的目标是使项目按时完成。有效的进度管理是项目管理成功的关键之一&#xff0c;进度问题在项目生命周期内引起的冲突最多。 小型项目中&#xff0c;定义活动、排列活动顺序、估算活动持续时间及制定进度模型形成进度计划等过程的联系非常密切&#xff0c;可以视为一…

LeetCode算法题解(单调栈)|LeetCode84. 柱状图中最大的矩形

一、LeetCode84. 柱状图中最大的矩形 题目链接&#xff1a;84. 柱状图中最大的矩形 题目描述&#xff1a; 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大…

更改Android Studio的.android和.gradle文件夹默认位置

一、首先关闭Android Studio&#xff0c; 二、目标位置新建文件夹 这一步&#xff0c;为了省去麻烦&#xff0c;我并没有直接在我的目标位置新建文件夹&#xff0c;而是把C盘下的.android和.gradle文件夹整个复制过来&#xff0c;和SDK都在同一目录下&#xff0c;感觉这样可以…

Sql Server 2017主从配置之:AlwaysOn高可用

AlwaysOn高可用功能&#xff0c;真正实现了数据库的灾备切换、高可用。 AlwaysOn通过Windows Server故障转移群集&#xff0c;部署高可用数据库组。 在故障转移群集基础上完成部署读写分离&#xff0c;只读负载平衡最多3个写入节点实现故障转移最多3个数据实时同步节点 环境…

网络入门---网络编程初步认识和实践(使用udp协议)

目录标题 前言准备工作udpserver.hpp成员变量构造函数初始化函数(socket,bind)start函数(recvfrom) udpServer.ccudpClient.hpp构造函数初始化函数run函数(sendto) udpClient.cc测试 前言 在上一篇文章中我们初步的认识了端口号的作用&#xff0c;ip地址和MAC地址在网络通信时…

Centos7、Mysql8.0 load_file函数返回为空的终极解决方法--暨selinux的深入理解

零、问题背景 最近想换房&#xff0c;为了方便自己对比感兴趣的房子&#xff0c;因此决定将目标房源的基本信息放在表里&#xff0c;特别是要一目了然的看到众多房子的各种图纸和照片&#xff0c;因此决定要在Mysql8.0.34数据库中以二进制形式保存图片&#xff08;抛开合理性和…

VSCode 报错 gopls was not able to find modules in your workspace.

由于在VSCode中打开一个项目时出现如下提示&#xff1a; 于是检索其解决办法 根据提示我们可以看到这是由于gopls所出的问题,在工作空间找不到相关module&#xff0c;这是VSCode中go插件所依赖附带的&#xff0c;该语言服务器提供诸如自动完成&#xff0c;转到定义&#xff0c;…

《python每天一小段》--12 数据可视化《1》

欢迎阅读《Python每天一小段》系列&#xff01;在本篇中&#xff0c;将使用Python Matplotlib实现数据可视化的简单图形。 一、概念 Matplotlib是一个流行的Python数据可视化库&#xff0c;它提供了丰富的绘图功能&#xff0c;可以创建各种类型的图表&#xff0c;包括折线图、…

echarts绘制一个环形图

其他echarts&#xff1a; echarts绘制一个柱状图&#xff0c;柱状折线图 echarts绘制一个饼图 echarts绘制一个环形图2 效果图&#xff1a; 代码&#xff1a; <template><div class"wrapper"><!-- 环形图 --><div ref"doughnutChart…

[面试题~k8s] 云原生必问基础篇

文章目录 概念篇1. k8s 是什么2. Container3. Pod4. Node5. Namespace6. Service7. Label8. Replica Set&#xff08;副本集)9. Deployment10. Volume11. Namespace12. PV 和 PVC 基础篇1. 删除 pod 流程2. k8s 有哪些组件master nodeworker node 3. k8s 和 docker 的关系4. 简…

mysql原理--InnoDB数据页结构

1.不同类型的页 页是 InnoDB 管理存储空间的基本单位&#xff0c;一个页的大小一般是 16KB 。InnoDB 为了不同的目的而设计了许多种不同类型的页。下面讨论存放我们表中记录的那种类型的页&#xff0c;官方称这种存放记录的页为索引&#xff08; INDEX &#xff09;页&#xff…

【开源】基于Vue+SpringBoot的河南软件客服系统

文末获取源码&#xff0c;项目编号&#xff1a; S 067 。 \color{red}{文末获取源码&#xff0c;项目编号&#xff1a;S067。} 文末获取源码&#xff0c;项目编号&#xff1a;S067。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统管理人员2.2 业务操作人员 三、…