【C进阶】通讯录1.0(文末附原码)

news2024/12/27 12:05:01

⭐博客主页:️CS semi主页
⭐欢迎关注:点赞收藏+留言
⭐系列专栏:C语言进阶
⭐代码仓库:C Advanced
家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!!

通讯录1.0

  • 前言
  • 一、思路
  • 二、制作框架
  • 三、宏定义
  • 四、初始化通讯录
  • 五、增加联系人
  • 六、显示联系人
  • 七、删除联系人
  • 八、查找联系人
  • 九、删除指定联系人
  • 十、排序
  • 十一、清空
  • 十二、原码(增加细节)
  • 总结


前言

通讯录是利用C语言进行制作的一个比较复杂的模型,当我们进行制作通讯录的时候,难免会碰到很多难点,尤其是在进行分文件操作的时候,当我们进行制作的时候,必须要用到以前的知识,但是同时也要加入新的元素进去,这个才是我们学习的意义,闲话不多说,一句话就是“加油干!!!”


一、思路

我们在制作通讯录之前,很重要的一件事情就是需要理清楚我们的思路以及我们需要做些什么,通讯录顾名思义是要有联系人的各种各样的信息,我们今天就比较简单地实现一下存放1000个人的信息,然后利用各种各样的功能进行实现,如下图,我们需要进行实现的各类信息:在这里插入图片描述


二、制作框架

首先,这三板斧添加三个新建项是必须的,这样我们的代码就不会堆在一起显得很冗杂。
在这里插入图片描述
其次,我们需要在test.c项目里面进行总体函数的框架制作,我们需要慢慢地进行制作,一起跟着来吧!

首先你需要在contgact.h头文件里面包含所有的头文件以及函数声明,因为这样很清晰,很简洁,我们在其他项目里面加上#include"contact.h"即可,我们就可以直接用头文件里面的头文件和声明了,虽然很神奇,但很常规。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

其次就是利用初阶学习的知识进行制作一个swtich–case语句来进行封装这些功能(是在test.c中制作):

#include"contact.h"

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

int main() 
{
	int input = 0;
	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 7:
			break;
		case 0:
			break;
		default:
			break;
		}
	} while (input);
	return 0;
}

那我们接下来简单声明一下人的信息(在contact.h头文件中):

//人的信息
typedef struct PeoInfo {
	char name[20];
	int age;
	char sex[5];
	char addr[30];
	char tele[12];
}PeoInfo;

另外,我们创建出人的信息以后是不是需要开辟一个空间来将这些放进去,所以,我们在test.c中进行创建通讯录的操作,是创建空间把人放进去:
在这里插入图片描述
我们创建完之后,很疑惑的一件事情是我们不知道我们此时放了多少个人的信息,我们不知道我们新加上去的应该放在哪里,所以我们需要加一个sz变量进行显示当前已经放了多少了。所以我们把sz和PeoInfo两个变量都重新建立一个结构体并放在里面(在contact.h头文件中以及在test.c中声明)。在这里插入图片描述
在这里插入图片描述
此时我们进行总体的框架就搭建好了,我们这时候只用到了test.c和contact.h这两个文件,那就附上原码:
test.c:

#include"contact.h"

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

int main() 
{
	int input = 0;
	//创建通讯录
	Contact con;

	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 7:
			break;
		case 0:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

contact.h

#include<stdio.h>

//人的信息
typedef struct PeoInfo {
	char name[20];
	int age;
	char sex[5];
	char addr[30];
	char tele[12];
}PeoInfo;

typedef struct Contact {
	//创建通讯录
	PeoInfo data[1000];//存放人的信息
	int sz;//当前已经放的信息的个数
}Contact;

三、宏定义

我们加上一个宏定义吧!这样子更加方便清晰:
test.c

#include"contact.h"

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

int main() 
{
	int input = 0;
	//创建通讯录
	Contact con;

	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			break;
		case 6:
			break;
		case 7:
			break;
		case 0:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

contact.h

#define MAX 1000
#define NAMEMAX 20
#define SEWXMAX 5
#define ADDRMAX 30
#define TELEMAX 12

#include<stdio.h>

//人的信息
typedef struct PeoInfo {
	char name[NAMEMAX];
	int age;
	char sex[SEWXMAX];
	char addr[ADDRMAX];
	char tele[TELEMAX];
}PeoInfo;

typedef struct Contact {
	//创建通讯录
	PeoInfo data[MAX];//存放人的信息
	int sz;//当前已经放的信息的个数
}Contact;

四、初始化通讯录

这个为什么我要直接拿出来一整个模块来讲解,而不是直接来个大括号{0},是因为,我们如果将它们放到模块里更加灵活,所以直接来初始化:
contact.h中放声明:
在这里插入图片描述
contact.c中放定义:
在这里插入图片描述
test.c中放动作:
在这里插入图片描述
那我们进行完初始化那就可以进行相关的操作了,直接往下看~~~


五、增加联系人

联系人的增加应该算是瓶颈,是需要利用我们新学习的知识进行操作,是有略微难度的,这其中比较难的是进行scanf操作用到的结构体指针,接下来我细细讲解,关于如何写增加联系人的代码:
首先我们进入程序以后需要在test.c中的case 1:子语句下加我们需要操作的函数,这个与初始化相同(在test.c中):
在这里插入图片描述
其次,我们在contact.h中进行声明函数:
在这里插入图片描述
最后,是我们的重头戏,我们需要在contact.c中进行函数的定义,也就是函数的操作:
在这里插入图片描述
我们先写这么个函数头头,我们在进行增加联系人的前提条件就是联系人已经满了,我们吭哧吭哧添加了1000个了已经,再添加一个人早就满了,可是如果你不让计算机判断一下通讯录里面有没有满,满了以后你不让计算机判断一下,还给它加工作那它肯定要生脾气,到维护不了的地方,你也不知道输出的是啥,所以要加个判断:
在这里插入图片描述
这个MAX就是我们的宏定义1000,这个return;是因为我们是无参数返回的函数,所以加一个return;是退出程序的意思。

接下来就是重头戏的增加联系人的操作了,先看代码再解释:
在这里插入图片描述
这似乎很复杂,但大家想一想这个pc就是我们前面定义的结构体指针它指向的是Contact结构体,而这个结构体又包含了PeoInfo这个结构体,是不是很绕,那画个图解释一下吧!在这里插入图片描述
简单而言就是一个往下指向的作用,所以就是先pc->data,而data又是结构体指针PeoInfo类型的,所以再指向结构体指针里的name/age/sex/addr/tele,而其中只有age不是数组,所以需要加&符号。


六、显示联系人

我们有点猴急,我们就想看一看输入以后了想给它显示一下,那我们找对应的5来进行显示一下:
根据上面增加的用处,我们在test.c中的5中加入显示的元素:在这里插入图片描述
接下来我们在contact.h中写入函数的声明(因为显示操作不能改变通讯录里面的值):
在这里插入图片描述

最后我们在contact.c中写入函数的定义,这里有了前面的基础就比较简单了,那我们就直接上手写吧!在这里插入图片描述

刚开始的表头printf是用来固定打印信息名称的,底下的打印是打印输入的值的,如下图所示:
在这里插入图片描述


七、删除联系人

删除联系人的操作有些许复杂,跟紧节奏出发吧!
老规矩,还是需要在test.c中找到case2的位置进行呼出函数的操作:
在这里插入图片描述
其次需要在contact.h中声明函数:
在这里插入图片描述
最后我们就需要在contact.c中进行函数的定义,同时也是最难的一部分,我们先上代码再解析:
在这里插入图片描述
这串代码很长,但很好理解,首先我们需要判断已经没有联系人了的这种情况,所以我们就需要加一个if判断语句,如果是已经没有联系人了,那就单纯的返回空,在这里插入图片描述

如果有,那我们进行操作,先是需要查找通讯录里面的这个人的位置,就需要用到strcmp函数进行名字的对比,
在这里插入图片描述
另外就是需要删除这个人的所有信息,这里就直接将后面的信息全部往前覆盖即可,直接删除成功。
在这里插入图片描述
那很多人也想了,这串代码有点长,能不能重新建立一个函数进行直接调用,是不是更加方便一点,那我们就直接创建一个FindByName函数进行将这些数据进去然后调用即可。
改进以后:
只在contact.c中进行改进,就将代码拷贝到函数里面去,原本的pc就是地址:
在这里插入图片描述


八、查找联系人

查找这个动作不就是在删除里面我们调出来的一个函数吗?那我们直接用好了,再进行打印一下就好了:
test.c
在这里插入图片描述
contact.h
在这里插入图片描述
contact.c:
在这里插入图片描述


九、删除指定联系人

删除无非就是先找到这个联系人再进行覆盖。
test.c:
在这里插入图片描述
contact.h:
在这里插入图片描述
contact.c:
在这里插入图片描述


十、排序

这里排序我们用到的是qsort函数,大家如果不太了解的话,直接一个链接供大家参考:qsort函数详解
test.c:
在这里插入图片描述
contact.h:
在这里插入图片描述
contact.c:
在这里插入图片描述


十一、清空

清空操作与初始化是一样的:
test.c:
在这里插入图片描述
contact.h:
在这里插入图片描述
contact.c:
在这里插入图片描述


十二、原码(增加细节)

细节1:加入assert断言
细节2:运用Sleep函数进行控制时长
直接上代码:
test.c:

#include"contact.h"

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

int main() 
{
	int input = 0;
	//创建通讯录
	Contact con;
	//初始化通讯录
	InitContact(&con);

	do {
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			Sleep(1000);
			break;
		case 3:
			SearchContact(&con);
			break;
		case 4:
			ModifyContact(&con);
			Sleep(500);
			break;
		case 5:
			ShowContact(&con);
			break;
		case 6:
			qsort(&con, con.sz, sizeof(con.data[0]), ContactSortName);
			printf("排序成功\n");
			Sleep(1000);
			break;
		case 7:
			EmptyContact(&con);
			printf("已全部清空\n");
			Sleep(1000);
			break;
		case 0:
			printf("退出通讯录\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

contact.h:

#define MAX 1000
#define NAMEMAX 20
#define SEWXMAX 5
#define ADDRMAX 30
#define TELEMAX 12

#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<windows.h>

//人的信息
typedef struct PeoInfo {
	char name[NAMEMAX];
	int age;
	char sex[SEWXMAX];
	char addr[ADDRMAX];
	char tele[TELEMAX];
}PeoInfo;

typedef struct Contact {
	//创建通讯录
	PeoInfo data[MAX];//存放人的信息
	int sz;//当前已经放的信息的个数
}Contact;



//初始化通讯录
void InitContact(Contact* pc);

//增加联系人
void AddContact(Contact* pc);

//显示通讯录里的联系人
void ShowContact(const Contact* pc);

//删除联系人
void DelContact(Contact* pc);

//查找联系人
void SearchContact(const Contact* pc);

//修改指定联系人信息
void ModifyContact(Contact* pc);

//排序
int ContactSortName(void* e1, void* e2);

//清空
void EmptyContact(Contact* pc);

contact.c:

//负责实现声明

#include"contact.h"

//实现初始化通讯录
void InitContact(Contact* pc) {
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));//传过来的是地址,根据地址找到了data数组,算的是data数组的总大小
}

//增加联系人
void AddContact(Contact* pc) {
	assert(pc);
	if (pc->sz == MAX) {
		printf("通讯录已满,无法添加联系人\n");
		return;
	}
	//增加一个人信息
	printf("请输入名字>");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄>");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别>");
	scanf("%s", pc->data[pc->sz].sex);
	printf("请输入地址>");
	scanf("%s", pc->data[pc->sz].addr); 
	printf("请输入电话>");
	scanf("%s", pc->data[pc->sz].tele);
	pc->sz++;
}

//显示通讯录里的信息
void ShowContact(const Contact* pc) {
	assert(pc);
	int i = 0;
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "name", "age", "sex", "address", "telephone");
	for (i = 0; i < pc->sz; i++) {
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[i].name,
				pc->data[i].age,
				pc->data[i].sex,
				pc->data[i].addr,
				pc->data[i].tele);
	}
}


int FindByName(const Contact* pc,char name[]) {
	assert(pc);
	int i = 0;
	int pos = 0;
	for (i = 0; i < pc->sz; i++) {
		if (strcmp(pc->data[i].name, name) == 0) {
			pos = i;
			return i;
		}
	}
	return -1;
}
//删除联系人
void DelContact(Contact* pc) {
	assert(pc);
	char name[NAMEMAX] = { 0 };
	//没有联系人不删除
	if (pc->sz == 0) {
		printf("通讯录为空,无法删除\n");
		return;
	}
	//删除联系人
	//找到要删除的人
	printf("请输入要删除的人的名字:>");
	scanf("%s", name);
	//查找
	int ret = FindByName(pc, name);
	if (-1 == ret) {
		printf("查无此人\n");
		return;
	}
	else {
		//删除
		int i = 0;
		for (i = ret; i < pc->sz - 1; i++) {
			pc->data[i] = pc->data[i + 1];
		}
		pc->sz--;
		printf("删除成功\n");
	}
}

//查找联系人
void SearchContact(const Contact* pc) {
	assert(pc);
	char name[NAMEMAX] = { 0 };
	printf("请输入要查找人的名字>");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (-1 == ret) {
		printf("查无此人\n");
		return;
	}
	else {
		//打印信息
		printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "name", "age", "sex", "address", "telephone");
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", pc->data[ret].name,
				pc->data[ret].age,
				pc->data[ret].sex,
				pc->data[ret].addr,
				pc->data[ret].tele);
	}
}

//修改指定联系人
void ModifyContact(Contact* pc) {
	assert(pc);
	//先找这个联系人
	char name[NAMEMAX] = { 0 };
	printf("请输入要修改人的名字>");
	scanf("%s", name);
	int ret = FindByName(pc, name);
	if (-1 == ret) {
		printf("查无此人\n");
		return;
	}
	else {
		//信息重新录入
		printf("请输入名字>");
		scanf("%s", pc->data[ret].name);
		printf("请输入年龄>");
		scanf("%d", &(pc->data[ret].age));
		printf("请输入性别>");
		scanf("%s", pc->data[ret].sex);
		printf("请输入地址>");
		scanf("%s", pc->data[ret].addr);
		printf("请输入电话>");
		scanf("%s", pc->data[ret].tele);
		printf("修改完成\n");
	}
}

//排序
int ContactSortName(void* e1, void* e2) {
	assert(e1 && e2);
	return strcmp((Contact*)e1, (Contact*)e2);
}

//清空
void EmptyContact(Contact* pc) {
	assert(pc);
	pc->sz = 0;
	memset(pc->data, 0, sizeof(pc->data));
}

总结

这个通讯录到这里简单的操作肯定是结束了,但这个通讯录并不是最终版本哦,肯定还是需要完善的,变的更加高级,更加好用!!!


支持和三连是必不可少的家人们~~~

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

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

相关文章

数据结构进阶 unordered_set unordered_map的使用

作者&#xff1a;小萌新 专栏&#xff1a;数据结构进阶 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;介绍高阶数据结构 unorder_set unorder_map的使用 unorder_set unorder_mapunordered系列关联式容器unordered_set介绍unordere…

微信小程序流量主提升ecpm的一些方法

本篇文章主要讲解:微信小程序流量主提升ecpm的一些方法 日期:2023年1月19日 作者:任聪聪 一、对ecpm的疑问和科普 什么是ecpm ecpm就是千次广告曝光收入,是一个预估的价格,而不是额定的,他是随着曝光度,用户点击度,页面访问数来决定的。 ecpm为什么会低? 微信官方…

KaiwuDB 数据服务平台 1.0 产品详解

大家好&#xff0c;今天我分享的是 KaiwuDB 数据服务平台&#xff08;KDP&#xff09;&#xff0c;一款由我们独立自主研发&#xff0c;以 KaiwuDB 为核心的数据服务产品。KDP 产品建设目标是实现数据的云边端的一体化治理&#xff0c;提供一套完整的全生命周期服务。接下来我将…

2.5、线程概念和多线程模型

整体框架 1、什么是线程&#xff0c;为什么要引入线程&#xff1f; 还没有引入进程之前&#xff0c;各个程序只能串行执行 进程是程序的一次执行过程&#xff0c;但这些功能显然不可能是由一个程序顺序处理就能实现的 有的进程可能需要 “同时” 做很多事&#xff0c;而传统的…

伯俊ERP与金蝶云星空对接集成连通应收单新增

伯俊ERP与金蝶云星空对接集成表头表体组合查询连通应收单新增(应收单-标准应收单&#xff08;KD应收单销售退)数据源系统:伯俊ERP未来&#xff0c;伯俊科技也会砥砺前行&#xff0c;不断为品牌提供更全面的零售终端致胜利器。伯俊科技始终坚持创新发展&#xff0c;探索大零售行…

【IDEA】自动部署SpringBoot Jar包到远程服务器并通过脚本启动jar

【IDEA】自动部署SpringBoot Jar包到远程服务器并通过脚本启动jar 文章目录 前言一.Deployment使用二.ssh使用三.启动脚本 前言 IDEA版本: 2019.3 一.Deployment使用 IDRA原生的Deployment不需要离开idea就可以直接将项目部署到远程运行&#xff0c;同时拥有远程视图窗口…

高并发系统设计 --计数服务抽离

传统计数 模糊计数 Cache DB。写Cache&#xff0c;批量刷新DB。 有一个写请求&#xff0c;我们就写cache&#xff0c;写一个在cache中1&#xff0c;buffer记一个&#xff0c;差不多&#xff08;buffer满了&#xff0c;时间到了&#xff09;写一次DB&#xff0c;丢数据也就丢…

JVM快速入门学习笔记(二)

临近过年&#xff0c;事太多&#xff0c;学习效率也好低&#xff0c;最近已经好久没搞学习了&#xff0c;发篇简单的学习笔记意思下吧 5. 沙箱安全机制 Java安全模型的核心就是Java沙箱&#xff08;sandbox&#xff09;&#xff0c;什么是沙箱&#xff1f;沙箱是一个限制程序运…

Oracle 12c多租户特性详解:从Schema到PDB的变化与隔离

CDB和PDB的职责分离一些数据库管理员管理整个CDB&#xff0c;而另一些管理员管理单个的pdb。.管理整个CDB的dba作为普通用户连接到CDB&#xff0c;管理整个CDB和根的属性&#xff0c;以及pdb的一些属性。例如&#xff0c;这些dba可以创建、拔出、插入和删除pdb。它们还可以为根…

【c语言】文件操作详解

主页&#xff1a;114514的代码大冒险 qq:2188956112&#xff08;欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ &#xff09; Gitee&#xff1a;庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 目录 前言 一、文件是什么 二、文件的打开和关闭 1.文件指针 2.文件的打开和关闭 三&#xff0c;文件的顺…

《计算机体系结构量化研究方法》 B.4 虚拟存储器 笔记

B.4 虚拟存储器 一、基本概念 1、虚拟存储器把物理存储器划分成块以后分配给不同的进程&#xff1b;采用一种保护机制来限制各个进程&#xff0c;使其仅能访问属于自己的块。 2、重定位机制允许同一程序在物理存储器中的任意位置运行。 3、页和段用于块&#xff0c;缺页错误…

SSM框架整合入门案例

文章目录SSM整合案例1&#xff0c;SSM整合1.1 流程分析1.2 整合配置步骤1&#xff1a;创建Maven的web项目步骤2:添加依赖步骤3:创建项目包结构步骤4:创建SpringConfig配置类步骤5:创建JdbcConfig配置类步骤6:创建MybatisConfig配置类步骤7:创建jdbc.properties步骤8:创建Spring…

《Buildozer打包实战指南》第七节 常见的打包问题

目录 无法访问xxx网址&#xff0c;连接超时 目标路径xxx已经存在&#xff0c;并且不是一个空目录 每次打包时间都要很久 待更新 在打包过程中难免会碰到一些问题&#xff0c;在本节&#xff0c;笔者会把自己碰到的一些问题的解决方案写出来&#xff0c;好让读者节省时间。 …

KaiwuDB CTO 魏可伟:1.0 时序数据库技术解读

大家好&#xff0c;首先非常感谢大家参与本次 KaiwuDB 1.0 系列产品发布会。作为国内数据库新生品牌力量&#xff0c;KaiwuDB 是浪潮集团控股的数据库企业&#xff0c;我们聚焦在工业物联网、数字能源、交通车联网、智慧产业等快速发展的重要领域&#xff0c;希望为各大行业客户…

06技术太卷我学APEX-技术太卷我学APEX

06技术太卷我学APEX-技术太卷我学APEX 0 概述 自学APEX第7天&#xff0c;用APEX做了一个自学的笔记APP&#xff0c;名称就叫《技术太卷我学APEX》 1 登录页面 登录页面设置&#xff1a;就改了下名称和加上了测试账号。 登录页面效果&#xff1a; 这个是 APEX功能页面之一…

前端面试题合集-第一篇

前端面试题合集-第一篇 &#x1f514;每周不定时更新&#xff01; ⛄️不要让自己失去竞争力&#xff01; ☀️哪里都不是避风港&#xff0c;保持竞争力! 1. CSS选择器的优先级 !important>内联>id选择器>类选择器>标签选择器>通配符选择器>继承 在同一…

Java IO流补充 - Properties - IO流框架commons-io

文章目录IO流补充知识Properties结合IO流集合IO流框架IO流补充知识 Properties结合IO流集合 我们先来认识Properties属性集对象 Properties其实就是一个Map集合&#xff0c;但是我们一般不会当集合使用&#xff0c;因为HashMap更好用。 Properties核心作用: 属性文件&#xf…

设计模式_行为型模式 -《观察者模式》

设计模式_行为型模式 -《观察者模式》 笔记整理自 黑马程序员Java设计模式详解&#xff0c; 23种Java设计模式&#xff08;图解框架源码分析实战&#xff09; 概述 定义 观察者模式&#xff0c;又被称为发布-订阅&#xff08;Publish / Subscribe&#xff09;模式&#xff0c…

RSA与证书

这篇文章详细讲述一下RSA与证书的相关内容。内容有点多&#xff0c;但都是干货。 一、RSA算法 1.1简介 RSA算法是由美国三位科学家Rivest、Shamir和Adleman于1976年提出并在1978年正式发表的公开密码算 法&#xff0c;其命名取自三位创始人名字的首字母缩写。该算法基于数论…

CSS 计数器

CSS 计数器 CSS 计数器可让你根据内容在文档中的位置调整其显示的外观。例如&#xff0c;你可以使用计数器自动为网页中的标题编号&#xff0c;或者更改有序列表的编号。 本质上 CSS 计数器是由 CSS 维护的变量&#xff0c;这些变量可能根据 CSS 规则跟踪使用次数以递增或递减…