C语言实战项目---通讯录

项目要实现的内容:能够存放100个人的通讯录程序,能够实现联系人数据的存储,删除,修改,查找,展示联系人的信息。

所需知识:结构体,指针,函数.................

废话不多说,咱们直接开始

1.界面的打印

我们需要一个可以执行选择的界面提供用户选择不同的数字来执行不同的程序。

我们在这里提前声明一下:

1.add(增加联系人的信息)

2.deal(删除联系人的信息)

3.search(查找联系人的信息)

4.modify(修改联系人的信息)

5.show(展示联系人的信息)

那我们现在就开始

void menu()
{
	printf("************************************************\n");
	printf("***      1. add        2.deal                   *\n");
	printf("***      3.search      4.modify                 *\n");
	printf("***      5.show        6.exit                   *\n");
	printf("*************************************************\n");
	
}

这个就是我们的菜单

菜单的打印很简单就使用一个 printf一个函数,我们接着继续把选择语句写出来 在我们写之前我们来思考一个问题(我们一共有六个可供选择的程序接口,那么我们该如何分辨我们选择执行的程序不会出错呢?)其实有个办法就是使用  枚举常量来实现。

大家来看不懂枚举的大家看我往期博客 我把地址放在这 CSDN

enum Option
{
	exit,       //退出信息管理系统   0
	add,        //增加信息管理系统   1
	deal,       //删除信息管理系统   2
	search,     //搜索信息管理系统   3 
	modify,     //修改信息管理系统   4
	show,       //展示信息管理系统   5

};

这样我们就可以清楚的知道我们所选择的每个选项,所要执行的程序。

我们来实现选择,选择不同的数字来执行不同的程序。原理很简单,使用一个do while(循环)

嵌套一个Switch语句。

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择\n");
		scanf_s("%d", &input);
		switch (input)
		{
		case exit:
			printf("退出信息管理系统");
			break;
		case add:
			ADDContact(&con);
			break;
		case deal:
			DEALContact(&con);
			break;
		case search:
			SearchContact(&con);
			break;
		case modify:
			ModifyCkontact(&con);
			break;
		case show:
			SHOWContact(&con);
			break;
		default:
			printf("请重新选择");
			break;
		}


	} while (input);

	return 0;
}


大家请看,当我们使用了枚举类型之后我们的选择都具象化了。

最基本的菜单和界面操作完成后我们来实现各种接口。

2.实现接口的预操作

2.1 创建结构体变量

我们创建的结构体是用来保存联系人的信息,其中包含联系人的“姓名”“性别”“地址”“年龄”“电话”

我们使用typedef 来将结构体命名为 peopleinform(people--人,inform--信息)

typedef struct peopleinform //设置人的信息
{
	char name[20];
	char sex[5];
	char adrs[30];
	int age;
	char tele[20];

}peopleinform;

这是一个人的信息,但是我们的通讯录要实现的是100个人的信息,那么我们就需要再创建一个结构体来实现。

typedef struct Contact
{
	peopleinform date[100]; //用来存放数据
	int sz; //用来记录的是信息管理系统中存放信息的个数

}Contact;

以上就是我们预处理,那么我们来实现接口。

 3.初始化联系人信息管理系统

再实现联系人数据增加的前提是我们要初始化date,sz,保证它们中没有任何的数据,以免对我们后续联系人数据的增加产生干扰。

我们初始化有两个办法,一个就是使用memset函数之间初始化

                                       二是使用循环来实现。

                                       由于C语言提供了函数,我们就使用这个。

//初始化信息管理系统
void IntiContact(Contact* pc);
void IntiContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->date, 0, sizeof(pc->date));
	/*
	memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值
	s指向要填充的内存块。
	c是要被设置的值。
	n是要被设置该值的字符数。
	返回类型是一个指向存储区s的指针
	*/


}

关键点拨:我们使用指针类型的原因,大家都知道传参。一个是传值,一个是传地址。

为什么在这里我们选择传地址(完了使用指针访问地址)???

在此之前我还有一篇博客(函数栈帧的创建与销毁)地址放在这里--CSDN 感兴趣的可以去详细了解。

解释:形参是实参的一份临时拷贝,如果单纯的传值,我们访问的时候是不需要修改的。

传值-----(B是一个中间人我是C需要把一份东西给A,我把东西给B,B给A),但是当我要找到A时,我就需要A的地址了。

传地址----(B这个中间人直接把A的地址给了我,我直接去找A,对A里面的值进行修改)。

因为我们需要对   date 和 sz 的内部的值进行修改所以 我们使用的是传地址。

初始化完成之后我们就可以来实现各种各样的接口了。

4.联系人数据的增加

//增加学生信息的信息
void ADDContact(Contact* pc);

这个过程是相对比较简单的使用printf函数和scanf函数即可。

报错:scanf函数我们在使用的时候,如果我们在后面不加上具体的数量,大小会报错。

void ADDContact(Contact* pc)
{
	assert(pc);
	//先判断信息管理系统有没有空间支持增加
	if (pc->sz == 100)
	{
		printf("信息管理系统已满无法增加\n");
		return;

	}
	//如果没有返回就增加一个人的信息
	printf("请输入名字");
	scanf_s("%s", pc->date[pc->sz].name, 20);
	printf("请输入年龄");
	scanf_s("%d", &(pc->date[pc->sz].age));
	printf("请输入性别");
	scanf_s("%s", pc->date[pc->sz].sex, 5);
	printf("请输入电话");
	scanf_s("%s", pc->date[pc->sz].tele, 20);
	printf("请输入地址");
	scanf_s("%s", pc->date[pc->sz].adrs, 30);
	//由于信息录入完成所以增加了一个人的信息
	pc->sz++;
	printf("增加成功\n");

}

 程序跑起来效果就是这样。

5.联系人数据的查看

由于“删除”“修改”“查找”都需要使用遍历查找,所以我们把它们放在后面,我们先来实现查看接口。

//查看学生信息的信息
void SHOWContact(Contact* pc);

相较于后面几个接口这个接口比较好实现,使用循环来打印就是。

大家请看

void SHOWContact(Contact* pc)
{
	assert(pc);
	;	if (pc->sz == 0)
	{
		printf("信息管理系统为空无法打印\n");
		return;


	}
	int i = 0;
	printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		//打印每个人的信息
		printf("%-20s%-5d%-5s%-12s%-30s\n", //分别打印姓名,年龄,性别,电话,地址。
			pc->date[i].name, pc->date[i].age, pc->date[i].sex, pc->date[i].tele, pc->date[i].adrs);
	}
}

我来为大家解释一下代码:

printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");

这一行代码:是打印我们的上面部分,采用的是左对齐的方式。(所以%20s,我们会加上“-”这个符号,其中%20s,是宽度)

printf("%-20s%-5d%-5s%-12s%-30s\n", //分别打印姓名,年龄,性别,电话,地址。
            pc->date[i].name, pc->date[i].age, pc->date[i].sex, pc->date[i].tele, pc->date[i].adrs);

这一行打印的是我们下面的部分。

那我们接着继续往下看

6.联系人数据的删除
 

6.1查找指定联系人

//删除指定学生信息的信息
void DEALContact(Contact* pc);

在我们实现删除的前提是找到指定的联系人,那么该如何操作呢?

思路如下:1.自定函数FindByName通过遍历来找到指定的姓名

                  2.再来删除

查找的代码:

int FIndByNmae(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->date[i].name, name) == 0)
		{
			return i;
		}
	}
	return -1; //找不到
}

分析如下:我们使用循环来遍历SZ(sz中存储的是有效联系人的信息,我们查找是否有名字相同的),我们使用了  strcmp 函数我们可以找到此人。找不到就会直接返回。

怕大家不理解Strcmp 我找来了资料大家可以看看。

 6.2删除指定联系人

oid DEALContact(Contact* pc)
{
	char name[20];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("没有学生信息的数据无法删除");
		return;
	}
	//找到学生信息
	printf("输入想要删除学生信息的名字:");
	scanf_s("%s", name, 20);
	//找到名字为name的人
	//分装一个新的函数FIndByName用来查找学生信息
	int ret = FIndByNmae(pc, name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除这个人的信息 
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->date[i] = pc->date[i + 1];
	}
	pc->sz--;
	printf("删除成功");

}

我来给大家详细通过画图来解释一下删除的全过程(如何进行删除操作的)

 

假设我们要删除 ret那么如何删除呢?

我们通过覆盖,从后面到前面覆盖,就是使用ret后面的那一个来把ret覆盖起来。

以上就是删除联系人的信息

7.联系人数据的修改

 //修改指定学生信息的信息 
void  ModifyCkontact(Contact*pc);

当我们有了自定义函数来实现查找之后,修改操作便会简单很多。 我们之间把增加的后半段代码复制过来。

void  ModifyCkontact(Contact* pc)
{
	char name[20];
	assert(pc);
	printf("请输入你要修改的人的名字:");
	scanf_s("%s", name, 20);
	int ret = FIndByNmae(pc, name);
	if (ret == -1)
	{
		printf("要修改的人不存在\n");
		return;
	}
	//修改
	printf("请输入名字");
	scanf_s("%s", pc->date[ret].name, 20);
	printf("请输入年龄");
	scanf_s("%d", &(pc->date[ret].age));
	printf("请输入性别");
	scanf_s("%s", pc->date[ret].sex, 5);
	printf("请输入电话");
	scanf_s("%s", pc->date[ret].tele, 20);
	printf("请输入地址");
	scanf_s("%s", pc->date[ret].adrs, 30);

	printf("修改成功");
}



8.联系人数据的查找

//查找指定学生信息的信息
 void SearchContact(Contact*pc);
void SearchContact(Contact*pc)
{
	char name[20];
	assert(pc);
	printf("请输入你要查找的人的名字:");
	scanf_s("%s", name, 20);
	int ret = FIndByNmae(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//显示出来
	printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-12s%-30s\n", //分别打印姓名,年龄,性别,电话,地址。
		pc->date[ret].name, pc->date[ret].age, pc->date[ret].sex, pc->date[ret].tele, pc->date[ret].adrs);

}

 相同的原理只要我们可以找到就可以实现。

9.通讯录的完整代码

text.c

#include"Contact.h"
void menu()
{ 
	printf("************************************************\n" );
	printf("        基于动态链表实现的学生信息系统          *\n");
	printf("***      1. add        2.deal                   *\n");
	printf("***      3.search      4.modify                 *\n");
	printf("***      5.show        6.exit                   *\n");
	printf("*************************************************\n");
	printf("本系统提供了增加,删除,搜索,修改,展示 学生信息\n");
}
enum Option
{
	exit,       //退出信息管理系统
	add,        //增加信息管理系统
	deal,       //删除信息管理系统
	search,     //搜索信息管理系统
	modify,     //修改信息管理系统
	show,       //展示信息管理系统

};
int main()
{
	int input = 0;
	Contact con;  //con就是创建的信息管理系统
	//初始化信息管理系统(因为在开始信息管理系统没有进行初始化内部存放的都是随机值)
	IntiContact(&con);
	do
	{
		menu();
		printf("请选择\n");
		scanf_s("%d", &input);
		switch (input)
		{
		case exit:
			printf("退出信息管理系统");
			break;
		case add:
			ADDContact(&con);
			break;
		case deal:
			DEALContact(&con);
			break;
		case search:
			SearchContact(&con);
			break;
		case modify:
			ModifyCkontact(&con);
			break;
		case show:
			SHOWContact(&con);
			break;
		default:
			printf("请重新选择");
			break;
		}


	} while (input);

	return 0;
}

 Contact.c

#include"Contact.h"
void IntiContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	memset(pc->date, 0, sizeof(pc->date));
	/*
	memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值
	s指向要填充的内存块。
	c是要被设置的值。
	n是要被设置该值的字符数。
	返回类型是一个指向存储区s的指针
	*/


}
void ADDContact(Contact* pc)
{
	assert(pc);
	//先判断信息管理系统有没有空间支持增加
	if (pc->sz == 100)
	{
		printf("信息管理系统已满无法增加\n");
		return;

	}
	//如果没有返回就增加一个人的信息
	printf("请输入名字");
	scanf_s("%s", pc->date[pc->sz].name,20);
	printf("请输入年龄");
	scanf_s("%d", &(pc->date[pc->sz].age));
	printf("请输入性别");
	scanf_s("%s", pc->date[pc->sz].sex,5);
	printf("请输入电话");
	scanf_s("%s", pc->date[pc->sz].tele,20);
	printf("请输入地址");
	scanf_s("%s", pc->date[pc->sz].adrs,30);
	//由于信息录入完成所以增加了一个人的信息
	pc->sz++;
	printf("增加成功\n");

}
void SHOWContact(Contact* pc)
{
	assert(pc);
	;	if (pc->sz == 0)
	{
		printf("信息管理系统为空无法打印\n");
		return;


	}
	int i = 0;
	printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		//打印每个人的信息
		printf("%-20s%-5d%-5s%-12s%-30s\n", //分别打印姓名,年龄,性别,电话,地址。
			pc->date[i].name, pc->date[i].age, pc->date[i].sex, pc->date[i].tele, pc->date[i].adrs);
	}
}

int FIndByNmae(Contact* pc, char name[])
{
	assert(pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (strcmp(pc->date[i].name, name) == 0)
		{
			return i;

		}
	}

	return -1; //找不到

 }

void DEALContact(Contact* pc)
{
	char name[20];
	assert(pc);
	if (pc->sz == 0)
	{
		printf("没有学生信息的数据无法删除");
		return;
	}
	//找到学生信息
	printf("输入想要删除学生信息的名字:");
	scanf_s("%s", name, 20);
	//找到名字为name的人
	//分装一个新的函数FIndByName用来查找学生信息
	int ret = FIndByNmae(pc, name);
	if (ret == -1)
	{
		printf("要删除的人不存在\n");
		return;
	}
	//删除这个人的信息 
	int i = 0;
	for (i = ret; i < pc->sz-1; i++)
	{
		pc->date[i] = pc->date[i + 1];
	}
	pc->sz--;
	printf("删除成功");

}
void SearchContact(Contact*pc)
{
	char name[20];
	assert(pc);
	printf("请输入你要查找的人的名字:");
	scanf_s("%s", name, 20);
	int ret = FIndByNmae(pc, name);
	if (ret == -1)
	{
		printf("要查找的人不存在\n");
		return;
	}
	//显示出来
	printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-12s%-30s\n", //分别打印姓名,年龄,性别,电话,地址。
		pc->date[ret].name, pc->date[ret].age, pc->date[ret].sex, pc->date[ret].tele, pc->date[ret].adrs);

}

void  ModifyCkontact(Contact* pc)
{
	char name[20];
	assert(pc);
	printf("请输入你要修改的人的名字:");
	scanf_s("%s", name, 20);
	int ret = FIndByNmae(pc, name);
	if (ret == -1)
	{
		printf("要修改的人不存在\n");
		return;
	}
	//修改
	printf("请输入名字");
	scanf_s("%s", pc->date[ret].name, 20);
	printf("请输入年龄");
	scanf_s("%d", &(pc->date[ret].age));
	printf("请输入性别");
	scanf_s("%s", pc->date[ret].sex, 5);
	printf("请输入电话");
	scanf_s("%s", pc->date[ret].tele, 20);
	printf("请输入地址");
	scanf_s("%s", pc->date[ret].adrs, 30);

	printf("修改成功");
}


Contact.h

#pragma once
#include<string.h>
#include<assert.h>
#define NAME_MAX 20;
#define SEX_MAX 5;
#define ADRS_MAX 20;
#define TELE_MAX 15;
#include<stdio.h>
typedef struct peopleinform //设置人的信息
{
	char name[20];
	char sex[5];
	char adrs[30];
	int age;
	char tele[20];

}peopleinform;
typedef struct Contact
{
	peopleinform date[100]; //用来存放数据
	int sz; //用来记录的是信息管理系统中存放信息的个数

}Contact;
//初始化信息管理系统
void IntiContact(Contact* pc);
//增加学生信息的信息
void ADDContact(Contact* pc);
//查看学生信息的信息
void SHOWContact(Contact* pc);
//删除指定学生信息的信息
void DEALContact(Contact*pc);
//查找指定学生信息的信息
 void SearchContact(Contact*pc);
 //修改指定学生信息的信息 
void  ModifyCkontact(Contact*pc);


今天的博客就到这里了,后续为大家更新C++的相关课程。

感谢你的观看

                               

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

leetcode尊享面试——二叉树(python)

250.统计同值子树 使用dfs深度搜索&#xff0c;同值子树&#xff0c;要满足三个条件&#xff1a; 对于当前节点node&#xff0c;他的左子树血脉纯净&#xff08;为同值子树&#xff09;&#xff0c;右子树血脉纯净&#xff08;为同值子树&#xff09;&#xff0c;node的值等于…

Qt 6.7 正式发布!

本文翻译自&#xff1a;Qt 6.7 Released! 原文作者&#xff1a;Qt Group研发总监Volker Hilsheimer 在最新发布的Qt 6.7版本中&#xff0c;我们大大小小作出了许多改善&#xff0c;以便您在构建现代应用程序和用户体验时能够享受更多乐趣。 部分新增功能已推出了技术预览版&a…

MySQL系列之MySQL 存储引擎

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

【LeetCode】环形链表I 环形链表II

一、环形链表I 题目 思路 该题使用快慢指针 slow、 fast slow 走一步 &#xff0c;fast 走两步 当fast 走到空 或者 fast的下一个结点为空&#xff0c; 则无环 fast若追上slow &#xff0c; 则有环 结论证明 该思路默认了 &#xff1a; 若存在环形链表 &#xff0c; 无论…

文件夹批量重命名:文件夹名称编号实战,快速实现文件分类与整理

随着电脑中存储的文件日益增多&#xff0c;如何有效地管理和组织这些文件成为了许多用户面临的一大挑战。文件夹批量重命名是一种非常实用的技巧&#xff0c;它可以帮助我们快速实现文件的分类与整理&#xff0c;使文件存储更加有序、高效。 为什么需要文件夹批量重命名&#x…

IP SSL证书申请教程:实现HTTPS加密访问

随着网络安全意识的提高&#xff0c;HTTPS加密访问已经成为网站安全性的重要标准。通过安装SSL证书&#xff0c;网站可以实现数据的加密传输&#xff0c;有效保护用户隐私和数据安全。本文将详细介绍如何为IP地址申请SSL证书&#xff0c;并实现HTTPS加密访问。 一、准备工作 …

Kaggle入门-泰坦尼克号数据及代码

本文讲述了kaggle入门级别的竞赛&#xff1a;泰坦尼克号&#xff0c;有提及如何下载数据&#xff0c;附带有思路和代码解析 前言 我个人还是喜欢直接在kaggle运行&#xff0c;但是有人不能科学上网呀 数据 在找到泰坦尼克号比赛里&#xff0c;创建一个notebook&#xff0c;然…

Excel Module: Iteration #1 EasyExcel生成下拉列表模版时传入动态参数查询下拉数据

系列文章 EasyExcel生成带下拉列表或多级级联列表的Excel模版自定义校验导入数据(修订) 目录 系列文章前言仓库一、实现1.1 下拉元数据对象1.2 构建下拉元数据的映射关系1.3 框架方式1.3.1 框架实现1.3.2 框架用例模版类加载下拉业务导出接口 1.4 EasyExcel方式1.4.1 EasyExce…

数据仓库与数据挖掘实验练习3-4(实验二2024.5.8)

练习3 1.简单文件操作练习 import pandas as pd # 读取文件 pd.read_csv(pokemon.csv) # 读取 CSV 文件的函数调用&#xff0c;它将文件中的数据加载到 DataFrame 中&#xff0c;并指定了 Pokemon 列作为索引列。 pd.read_csv(pokemon.csv,index_colPokemon)#查看类型 type(p…

UE5材质基础(2)——数学节点篇1

UE5材质基础&#xff08;2&#xff09;——数学节点篇1 目录 UE5材质基础&#xff08;2&#xff09;——数学节点篇1 Add节点 Append节点 Abs节点 Subtract节点 Multiply节点 Divide节点 Clamp节点 Time节点 Lerp节点 Add节点 快捷键&#xff1a;A鼠标左键 值相加…

智慧安监中的物联网主机E6000

物联网主机E6000的研发背景主要源于我国对物联网技术在安全生产、环境监测、火灾预警与防控、人员定位与紧急救援等领域的迫切需求。近年来&#xff0c;随着物联网技术的飞速发展&#xff0c;我国政府对智慧安监的重视程度不断提升&#xff0c;相关的政策扶持力度也在加大。在这…

Ansible--Templates 模块 Tags模块 Roles模块

一 Templates 模块 ①Jinja是基于Python的模板引擎。Template类是Jinja的一个重要组件&#xff0c;可看作一个编译过的模 板文件&#xff0c;用来产生目标文本&#xff0c;传递Python的变量给模板去替换模板中的标记。 ②在配置文件中&#xff0c;会有一些数据&#xff08;如…

CCF-Csp算法能力认证, 202212-1现值计算(C++)含解析

前言 推荐书目&#xff0c;在这里推荐那一本《算法笔记》&#xff08;胡明&#xff09;&#xff0c;需要PDF的话&#xff0c;链接如下 「链接&#xff1a;https://pan.xunlei.com/s/VNvz4BUFYqnx8kJ4BI4v1ywPA1?pwd6vdq# 提取码&#xff1a;6vdq”复制这段内容后打开手机迅雷…

前端双语实现方案(VUE版)

一、封装一个lib包 结构如下 en.js use strict;exports.__esModule true; exports.default {sp: {input: {amountError: Incorrect amount format},table: {total: Total:,selected: Selected:,tableNoData: No data,tableNoDataSubtext: Tip: Suggest to recheck your fil…

LeetCode 110. 平衡二叉树

LeetCode 110. 平衡二叉树 1、题目 题目链接&#xff1a;110. 平衡二叉树 给定一个二叉树&#xff0c;判断它是否是 平衡二叉树 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2…

AI写作助手:推荐顶级论文写作工具

ChatGPT生成内容需要注意的问题 永远不要直接提交未经修改的AI文本使用工具如Quillbot、Versabot(支持中文论文生成和润色)、Paraphrasing Tool和Jasper来改变文本的措辞亲自修改短语、句子和文本的其他元素提示ChatGPT重新写自己的文本&#xff0c;并通过多个草稿进行修订 Ch…

如何把多个文件(夹)向上移动1层(或多层)(在批量复制前或后进行)

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 假定情况是&#xff0c;我要把下图里的4个文件夹内部的全部文件&#xff0c;合并到04的当前位置来&#xff08;4个文件夹里面各有5个兔兔的图片&#xff09…

【吃透Java手写】2-Spring(下)-AOP-事务及传播原理

【吃透Java手写】Spring&#xff08;下&#xff09;AOP-事务及传播原理 6 AOP模拟实现6.1 AOP工作流程6.2 定义dao接口与实现类6.3 初始化后逻辑6.4 原生Spring的方法6.4.1 实现类6.4.2 定义通知类&#xff0c;定义切入点表达式、配置切面6.4.3 在配置类中进行Spring注解包扫描…

华为ensp中BFD和OSPF联动(原理及配置命令)

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年5月6日20点26分 BFD通常指的是双向转发检测。BFD是一个旨在快速检测通信链路故障的网络协议&#xff0c;提供了低开销、短延迟的链路故障检测机制。它主要用于监测两个…

start.spring.io不支持java8,idea使用阿里云又报错

做项目的时候&#xff0c;我们可以发现&#xff0c;访问https://start.spring.io/ 创建脚手架项目的时候&#xff0c;最低是java 17了 但是对于很多项目来说&#xff0c;还是在用java8&#xff0c;这该怎么办呢&#xff1f; 值得庆幸的是&#xff0c;阿里云也同样有相同功能的…