C语言实现个人通讯录(功能优化)

news2024/10/6 6:01:59

实战项目---通讯录(功能优化)

  • 1.基本思路介绍:
    • 1.1基本思路:
  • 2.通讯录的具体实现:
    • 2.1 通讯录的建立:
    • 2.2通讯录功能:
  • 3.具体功能函数的实现:
    • 3.1 增添联系人:
    • 3.2 删除联系人:
    • 3.3 查找联系人:
    • 3.4 修改联系人:
    • 3.5 打印通讯录:
    • 3.6 通讯录的排序:
    • 3.7 文件导入和导出功能:
    • 3.8 分组打印:
    • 3.9 隐蔽空间的实现:
  • 4.代码缺陷,以及优化:
    • 4.1 内存泄漏:
    • 4.2 代码可读性维护:
    • 4.3 代码的可调式性:

  • 用C语言实现个人通讯录,完成个人通讯录的增加、减少、查找、修改联系人,同时实现通讯录的排序功能和隐藏空间的功能等;
  • 分三个文件实现:Test.c 这个文件用于测试代码,测试功能实现,以及最后的主函数,都可以用这个实现。(注意:在写项目过程中,一定要每实现一个功能就要运行测试,不然,代码过长调试困难)Contact.h文件,用于声明各种定义声明以及内部库的引用,这样可以简化代码,让代码更加可读(类型定义、库函数声明、函数定义、宏定义等)Contact.c这就是最关键的文件,用于对各项函数的实现;

1.基本思路介绍:

1.1基本思路:

  • 我们的基本思路其实在Test.c文件中最能体现:
#include"Contact.h"
int main()
{
	int input;
	//菜单
	mune1();
	//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
	//若输入为0,则判断为FALSE,跳出循环,退出通讯录

	//创建通讯录:
	Contact con;
	//初始化函数:传入指针减少内存占用
	InitContact(&con);

	do {
		//选项的输入
		printf("请输入选项>:");
		scanf("%d", &input);
		//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
		//若输入为0,则判断为FALSE,跳出循环,退出通讯录
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SEARCH:
			SearchContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			PrintContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			//保存到文件中
			SaveContact(&con);
			//销毁通讯录空间
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		case Hide_Room:
			//将当前写入文件保存到文件中
			SaveContact(&con);
			//销毁当前空间
			DestroyContact(&con);
			if (EncryptionContact())
			{
				//初始化原本空间,进入加密空间
				Hide_InitContact(&con);
				ShowHide();
				//加密程序空间功能
				func(&con);
				goto judge;
			}
			else
			{
				goto judge;
			}
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);

judge:
	return 0;
}

这里的基本思路就是:

  1. 通讯录的建立:先定义通讯录,在初始化通讯录,也就是为通讯录内部创建空间,以便存放数据;
  2. 功能的选择实现:创建好通讯录接下来我们肯定就是调用功能,我们用循环来实现功能的反复调用,用Switch语句来实现功能的选择(调用)。这里的基本功能是七项(方便展示可以定义一个菜单)

这就是整体基本思路,在Test.c中一目了然。

2.通讯录的具体实现:

2.1 通讯录的建立:

1.我们描述一个人是复杂的,不是一个类型元素可以描述,比如姓名是字符串,年龄是整形,所以这里要采用自定义类型(结构体)来定义联系人信息:

//人的信息
typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char address[ADDR_MAX];
	char phone[PHONE_MAX];
	char class[CLASS_MAX];
}PeoInfo;

这里我们定义了联系人的姓名、年龄、性别、地址、电话、以及分组;
2.个人通讯录相当于一个数组,元素是PeoInfo类型(联系人),这里我们可以采用静态数组,但实际上静态数组在后续的添加人数的时候,扩容比较呆板,所以这里我们选择的是顺序表的数据结构,这更方便于增添人数(当然链表也可以实现,后续补充)

//以顺序表实现
typedef  struct Contact
{
	//创建通讯录
	PeoInfo* data;
	int sz;//记录当前通讯录中的人数
	int capacity;//记录当前通讯录的空间大小
}Contact;

通过这个代码我们就可以定义一个通讯录喽!当然接下来就要初始化通讯录,创建空间:

void InitContact(Contact* pc)
{
	assert(pc);
	pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
	//在堆上申请空间
	if (pc->data == NULL)
	{
		//检验是否申请成功,方便调试检验;
		perror("malloc error");
	}
	pc->sz = 0;//最初空间人数
	pc->capacity = INIT_MAX;//空间大小
}

这里的代码表示我们在堆上申请空间,申请了INIT_MAX个人数空间,OK这里通讯录的建立就完成咯!

2.2通讯录功能:

通讯录具体有什么功能需要实现呢?这里只需要看一眼Test.h就一目了然了:

#pragma once
//类型的定义和声明放入头文件
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
#include<windows.h>
//宏定义:
#define INIT_MAX 4
#define NAME_MAX 20
#define SEX_MAX 5
#define ADDR_MAX 20
#define PHONE_MAX 12
#define CLASS_MAX 20
//选择菜单
void mune1();
void mune();
//枚举优化选项
enum input
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SHOW,
	SORT,
	Hide_Room = 110,
};
enum way
{
	S_ByName = 1,
	S_ByAge,
	S_BySex,
	S_ByAddr,
	S_ByPhone,
	S_ByClass,
};
//人的信息
typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char sex[SEX_MAX];
	char address[ADDR_MAX];
	char phone[PHONE_MAX];
	char class[CLASS_MAX];
}PeoInfo;

//以顺序表实现
typedef  struct Contact
{
	//创建通讯录
	PeoInfo* data;
	int sz;
	int capacity;
}Contact;

//初始化结构体
void InitContact(Contact* pc);
//扩容函数
void CapacityContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//查找联系人
int SearchContact(const Contact* pc);
//查找方法:
// 按名字查找:
	int SearchByName(const Contact* ps);
// 按年龄查找:
	void SearchByAge(const Contact* ps);
// 按性别查找:
	void SearchBySex(const Contact* ps);
// 按地址查找:
	void SearchByAddr(const Contact* ps);
//按分组查找:
	void SearchByClass(const Contact* ps);
// 按电话查找:
	int SearchByPhone(const Contact* ps);
//修改联系人
void ModifyContact(Contact* pc);
//打印通讯录
void PrintContact(const Contact* pc);
//对通讯录成员进行排序
void SortContact(const Contact* pc);
//销毁通讯录内存空间
void DestroyContact(Contact* pc);
//保存通讯录到磁盘
void SaveContact(const Contact* pc);
//加载通讯录信息
void LondContact(Contact* pc);
//通讯录按照名字排序
	void SortContact(const Contact* pc);
//通讯录成员信息交换
	void Swap(PeoInfo* left, PeoInfo* right);
//双指针快排
	void DP_QuickSort(PeoInfo* a, int left, int right);
//选择排序
	void InsertSort(PeoInfo* a, int n);
//隐蔽空间定义
void  Hide_InitContact(Contact* pc);
//隐蔽空间文件调用
	void Hide_LondContact(Contact* pc);
//隐蔽空间密码登录
	bool EncryptionContact();
//进入展示
	void ShowHide();
//隐蔽空间文件保存
	void Hide_SaveContact(const Contact* pc);

void func(Contact* pc);

可以看到.h文件里包含了很多内容:头文件定义,宏定义,自定义类型声明,函数声明等等;
接下来我们就具体实现一下上述功能函数:

3.具体功能函数的实现:

这里就是最重要的地方咯,注意咯!!!

3.1 增添联系人:

增添联系人代码实现:

void AddContact(Contact* pc)
{
	assert(pc);
	//自动扩容
	CapacityContact(pc);

	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].address);
	printf("请输入联系人电话:");
	scanf("%s", pc->data[pc->sz].phone);
	printf("请设置联系人组别:");
	scanf("%s", pc->data[pc->sz].class);
	//这里sz记录当前通讯录人数
	pc->sz++;
	return;
}

增添联系人代码比较简单,但要注意一个问题,我们不断添加人数,会达到通讯录初始化的最大空间容量,所以我们需要考虑通讯录的扩容问题,如果我们按照最开始的想法用数组来存储联系人,则不能灵活的更改通讯录容量,需要手动更改代码空间比较麻烦,而用顺序表就可以很好解决这个问题;

void CapacityContact(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * INIT_MAX * 2);
		if (pc->data == NULL)
		{
			perror("realloc error");
		}
		pc->capacity = pc->capacity * 2;
		printf("扩容成功\n");
	}
}

当sz(当前通讯录人数)等于capacity(通讯录空间大小),则可以通过动态内存管理realloc,对原来的空间扩容,可以自动实现就十分方便;

3.2 删除联系人:

1.删除联系人需要考虑,通讯录中是否储存了联系人,判断通讯录是否为空;
2.实际情况中,我们删除是根据人的姓名等信息,所以这里就要具体得到要删除对象的位置,这里就要用查找功能;
3.删除的思想:覆盖+下标索引减小,实现部分空间无法访问,间接的删除;

void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录中无对象可操作!请先增加!");
		mune1();
		return;
	}
	int ret = SearchByName(pc);
	if (ret == -1)
	{
		printf("删除失败请重新操作!");
		mune1();
		return;
	}
	int i = ret;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];

	}

	printf("删除成功!\n");
	//这里并不是完全删除,把\0发给int时默认为零,我们sz减减,就相当于访问不到那片空间
	pc->sz--;
	mune1();
}

3.3 查找联系人:

1.这里就用最简单的方法:遍历通讯录对比实现
2.当然这里我提供了六种查找方式,当然最也可以算是五种,因为最后一种分类查找我把它定为分组;

总查找函数:

int SearchContact(const Contact* pc)
{
	assert(pc);
	//多种方式查找:
	mune();
	int input;
	int ret = -1;
	do {
		//选项的输入
		printf("请输入选项>:");
		scanf("%d", &input);
		//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
		//若输入为0,则判断为FALSE,跳出循环,
		switch (input)
		{
		case S_ByName:
			ret = SearchByName(pc);
			break;
		case S_ByAge:
			SearchByAge(pc);
			break;
		case S_BySex:
			SearchBySex(pc);
			break;
		case S_ByAddr:
			SearchByAddr(pc);
			break;
		case S_ByPhone:
			ret = SearchByPhone(pc);
			break;
		case S_ByClass:
			SearchByClass(pc);
			break;
		case EXIT:
			printf("查找完成,已经返回上一级\n");
			mune1();
			break;
		default:
			printf("该查找方式还待开发哦,请重新输入\n");
			break;
		}
	} while (input);
	return ret;
}

这里和test.c中相似,各类查找也差不多相同,这里我就列出一个比较常用的咯!

  • 按照姓名查找:
	int SearchByName(const Contact* ps)
{
	int i = 0;
	char name[NAME_MAX];
	int k = 1;
	printf("请输入需要的联系人名字:");
	scanf("%s", name);
	for (i = 0; i < ps->sz; i++)
	{
		if (strcmp(name, ps->data[i].name) == 0)
		{
			//暂时不考虑重名
			if (k == 1)
			{
				printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
				k--;
			}

			printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
				ps->data[i].name,
				ps->data[i].age,
				ps->data[i].sex,
				ps->data[i].address,
				ps->data[i].phone,
				ps->data[i].class);

			return i;
		}
	}
	printf("无法找到该联系人信息\n");
	return -1;
}

(这里存在缺陷:就是重名,因为这里函数要返回int,所以只能用于不重名查找,当然如果重名,我们多掉用两次就可以了,还有就是通讯录里重名应该有其他备注吧哈哈!)

3.4 修改联系人:

这个代码也比较简单思路是:找到,并且输入新信息覆盖即可;

void ModifyContact(Contact* pc)
{
	int ret = -1;
	int i;
	i = SearchByName(pc);
	if (i != ret)
	{
		printf("请输入修改的内容(部分):\n");
		printf("请输入联系人名字:");
		scanf("%s", pc->data[i].name);
		printf("请输入联系人年龄:");
		scanf("%d", &(pc->data[i].age));
		printf("请输入联系人性别:");
		scanf("%s", pc->data[i].sex);
		printf("请输入联系人地址:");
		scanf("%s", pc->data[i].address);
		printf("请输入联系人电话:");
		scanf("%s", pc->data[i].phone);
	}
}

3.5 打印通讯录:

这个功能应该最先完成,因为有了它方便调试每个功能的代码;
思路很简单:遍历打印(但要注意格式美化,不然可太挫了)

void PrintContact(const Contact* pc)
{
	assert(pc);
	int i = 0;
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].address,
			pc->data[i].phone,
			pc->data[i].class);
	}
}

3.6 通讯录的排序:

这个功能实现就相对于前面的功能来说就有意思多了,来听我细细道来:

  • 排序算法有八种,各种排序都是很不错的思路,比如被用于教学的冒泡排序,简单易懂,思想也贴切排序思想,所以常常用来教学初级;(具体八大排序算法,之后也会写成博客)
  • 这里我就选用八大排序最舒服的快排,为什么选用快排呢,当然是快咯,哈哈,但快排也在这里有一些缺陷,如果数据很少,或者有很多都是顺序输入,快排就有一点点吃亏,没事儿----会优化!!!
  • 先来介绍一下快排的思路吧,快排最开始是Hoare大佬提出来的思路如图:
    在这里插入图片描述
    这就是最开始Hoare大佬的快排思路:
  • 1.先定一个key值,把比key小的放key的以边,把比key大的放一边,这样key就找到了正确位置,这就是一趟的思路,不断二分,就可以排序了。
  • 2.不断二分,可递归,可不用递归,这里我就只是说一下递归方式。
void Swap( int* left,int* right)
{
	int t = *left;
	*left = *right;
	*right = t;
}
void Hoare_QuickSort(int* a, int left, int right)
{
//当二分到key值的一边只有一个数,或者没有时,便递归结束
	if (left >= right)
		return;
		
	int end = right, begin = left;
	int keyi = left;//这里表示的是key的下标索引
	while (left < right)
	{
		//左边做key,右边先走,可以保证相遇位置比key更小
		//right找小找到和找不到:
		//找到:left没有找到大,直到相遇
		//没找到:直接和left相遇,直接找到keyi值
		while (left<right&&a[right] >= a[keyi])//right找小停下
			right--;

		while (left<right&&a[left] <= a[keyi])//left找大(保证相遇小于key)
			left++;
		Swap( &a[left],&a [right]);//交换两者,分配
	}
	//最后相遇位置便是key的位置:
	Swap(&a[left], &a[keyi]);
	keyi = left;
	//key左边数组的处末索引:begin,keyi-1
	Hoare_QuickSort(a, begin, keyi - 1);
	//key右边数组的初末索引:keyi+1,end
	Hoare_QuickSort(a, keyi + 1, end);
}

当然Hoare大佬提出的版本肯定是存在一定缺陷的,需要优化,但是这种思想真的厉害!
这里直接给出时间复杂度:O(NlgN)~O(N*N)

  • 缺陷: 1.当所需要排的数列是顺序或者逆序时,快排时间复杂度是最大N的平方,严重影响快排的速度。2.快排在对数据少,并且部分具有一定顺序的排序并不是很完美。3.Hoare大佬的快排思路难以理解,思路理解困难。

对于上述缺陷我这里就不过度介绍了,但的确有优化方式(我会在后续的八大排序中介绍)在通讯录排序中用较优秀的方式来实现(这里就是和库里排序函数实现相近了):

void Swap(PeoInfo* left, PeoInfo* right)
{
	PeoInfo t = *left;
	*left = *right;
	*right = t;
}

int GerMidNumi(PeoInfo* a, int left, int right)
{
	int mid = (right + left) / 2;

	if (strcmp(a[left].name, a[mid].name) > 0)
	{
		if (strcmp(a[mid].name, a[right].name) > 0)
		{
			return mid;
		}
		else if (strcmp(a[left].name, a[right].name) < 0)
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else
	{
		if (strcmp(a[left].name, a[right].name) > 0)
		{
			return left;
		}
		else if (strcmp(a[mid].name, a[right].name) < 0)
		{
			return mid;
		}
		else
		{
			return right;
		}
	}
}

void  DP_QuickSort(PeoInfo* a, int left, int right)
{
	int end = right, begin = left;
	if (left >= right)
		return;
	//小区间优化:
	if ((right - left + 1) > 10)
	{
		//方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显)
		int midi = GerMidNumi(a, left, right);
		if (midi != left)
			Swap(&a[left], &a[midi]);

		int prev = left;
		int cur = prev + 1;
		int keyi = left;

		while (cur <= right)
		{
			if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur)
				Swap(&a[cur], &a[prev]);
			cur++;
		}
		Swap(&a[prev], &a[keyi]);
		keyi = prev;

		DP_QuickSort(a, begin, keyi - 1);
		DP_QuickSort(a, keyi + 1, end);
	}
	else
	{
		InsertSort(a, right - left + 1);
	}
}

void InsertSort(PeoInfo* a, int n)
{
	for (int i = 1; i < n; i++)
	{
		int end = i - 1;
		PeoInfo tmp = a[i];
		// 将tmp插入到[0,end]区间中,保持有序
		while (end >= 0)
		{
			if (strcmp(tmp.name, a[end].name) < 0)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

这里很有趣,但在这个部分就不过度介绍了,在后续博客会有详细介绍哈!

3.7 文件导入和导出功能:

我们当前所写的代码都是在内存里写的,一旦关闭数据便会清除,所以需要把数据导入到本地磁盘中进行保存,这里就需要文件相关知识了。知识掌握了,就十分简单了!

  • 本地导入内存:
void LondContact(Contact* pc)
{
	FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb");
	if (NULL == pf)
	{
		perror("LondContact error");
	}
	else
	{
		int i = 0;
		PeoInfo tmp = { 0 };
		while (fread(&tmp, sizeof(PeoInfo), 1, pf))
		{
			CapacityContact(pc);
			pc->data[i] = tmp;
			pc->sz++;
			i++;
		}
		fclose(pf);
		pf = NULL;
	}
}
  • 内存存入本地:
void SaveContact(const Contact* pc)
{
	FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb");
	if (NULL == pf)
	{
		perror("SaveContact error");
	}
	else
	{
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存成功\n");
	}
}

这就实现了通讯录的基本功能喽

3.8 分组打印:

这里我的通讯录是把分组定义为联系人的属性了的,所以只需要按照分组查找打印即可:

	void SearchByClass(const Contact* ps)
{
	{
		int i = 0;
		char class[CLASS_MAX];
		int flag = 0;
		int k = 1;
		printf("请输入需要查找联系人的组别:");
		scanf("%s", class);
		for (i = 0; i < ps->sz; i++)
		{
			if (strcmp(class, ps->data[i].class) == 0)
			{
				flag = 1;
				if (k == 1)
				{
					printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
					k--;
				}
				printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
					ps->data[i].name,
					ps->data[i].age,
					ps->data[i].sex,
					ps->data[i].address,
					ps->data[i].phone,
					ps->data[i].class);
			}
		}
		if (flag)
		{
			return;
		}
		else
		{
			printf("无法找到该联系人信息\n");
		}
	}
}

3.9 隐蔽空间的实现:

  • 这里的思路就是另外开辟本地文件,作为存储空间,但要注意的是,调用隐蔽空间时,切记先保存通讯录原本空间,并且退出(销毁)。再打开隐蔽空间的文件,就相当于实现一个小的通讯录,功能可照搬所以就不过多介绍。
  • 只介绍一下进入空间时的一些优化吧,比如ShowHide()函数,看似只是加载界面,其实他还可以实现清除屏幕(调用windows自带的cls)原先信息,做到更舒服的访问。代码如下:
void ShowHide()
{
	char arr1[] = "Welcome to Hide Room !!!";
	char arr2[] = "########################";

	int left = 0;
	int right = strlen(arr1) - 1;

	while (left <= right)
	{
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		printf("%s\n", arr2);
		Sleep(1000);
		//清屏
		system("cls");
		left++;
		right--;
	}
	printf("%s\n", arr1);
}
  • 输入密码进入bool EncryptionContact()函数,这个函数还有太多可优化的地方:比如三次密码输入失败,24小时重试,这里用C语言就不方便了,可以用linux实现(后续会出相关博客)这里只能打印表示,还有就是密码的修改,这里我想的是还可以实现一个管理程序(哈哈,写博客想着想着就去实现了个,现在和大家分享!!!)
void Administrators(char* password)
{
	char newpassword[20];
	printf("请输入修改密码》:");
	scanf("%s", newpassword);
	strcpy(password, newpassword);
	printf("修改成功\n");
}

bool EncryptionContact()
{
	int i = 0;
	char password[20] = { 0 };
	char insure[20] = { "123456" };
//打开一个文件夹用来记录空间密码:
	FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb");
	if (NULL == pf1)
	{
		perror("password1 error");
	}
	else
	{
		char tmp[20] = { 0 };
		fread(&tmp, 20, 1, pf1);
		strcpy(insure, tmp);
		fclose(pf1);
		pf1 = NULL;
	}
//判断的主要函数:
	printf("请输入进入密码》:");
	for (i = 0; i < 3; i++)
	{
		scanf("%s", password);
		if (0 == strcmp(password, insure))
		{
			return true;
		}
		else if (0==strcmp(password,"管理员入口"))
		{
		//进入管理员系统进行密码修改
			Administrators(insure);
		//存入密码文件中
			FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb");
			if (NULL == pf2)
			{
				perror("password2 error");
			}
			else
			{
				fwrite(insure, 20, 1, pf2);
				fclose(pf2);
				pf2 = NULL;
				printf("保存成功\n");
			}
			printf("请输入进入密码》:");
		}
		else
		{
			printf("第%d次密码输入错误\n", i + 1);
			if (i < 2)
				printf("请重新输入》:");
		}
	}
	//linux操作系统实现
	printf("密码输入三次错误!请在24小时后重试\n");
	return false;
}

这里可以形成一个对比,就是代码没有封装可读性就很差,这里可以把写入和写出封装成函数。这里关于隐蔽空间其他功能大致相同就不过多介绍了。

Contact.c完整代码:

#include"Contact.h"

void mune()
{
	printf("*******************************************************\n");
	printf("********1.SearchByName    2.SearchByAge ***************\n");
	printf("********3.SearchBySex     4.SearchByAddr   ************\n");
	printf("********5.SearchByPhone   6.SearchByclass  ************\n");
	printf("*******************  0.exit  **************************\n");
	printf("*******************************************************\n");
}
void mune1()
{
	printf("**************************************\n");
	printf("********1.ADD    2.DEL ***************\n");
	printf("********3.SEARCH 4.MODIFY ************\n");
	printf("********5.SHOW   6.SORT   ************\n");
	printf("********0.EXIT            ************\n");

}

void func(Contact* pc)
{
	int input;
	mune1();
	do {
		printf("请输入选项>:");
		scanf("%d", &input);
		//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
		//若输入为0,则判断为FALSE,跳出循环,退出通讯录
		switch (input)
		{
		case ADD:
			AddContact(pc);
			break;
		case DEL:
			DelContact(pc);
			break;
		case SEARCH:
			SearchContact(pc);
			break;
		case MODIFY:
			ModifyContact(pc);
			break;
		case SHOW:
			PrintContact(pc);
			break;
		case SORT:
			SortContact(pc);
			break;
		case EXIT:
			//保存到文件中
			Hide_SaveContact(pc);
			//销毁通讯录空间
			DestroyContact(pc);
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);

	return;
}

void LondContact(Contact* pc)
{
	FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "rb");
	if (NULL == pf)
	{
		perror("LondContact error");
	}
	else
	{
		int i = 0;
		PeoInfo tmp = { 0 };
		while (fread(&tmp, sizeof(PeoInfo), 1, pf))
		{
			CapacityContact(pc);
			pc->data[i] = tmp;
			pc->sz++;
			i++;
		}
		fclose(pf);
		pf = NULL;
	}
}

//主要用于函数的实现操作,功能实现处
//动态内存处理
void InitContact(Contact* pc)
{
	assert(pc);
	pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
	if (pc->data == NULL)
	{
		perror("malloc error");
	}
	pc->sz = 0;
	pc->capacity = INIT_MAX;

	//读取文件
	LondContact(pc);
}

void CapacityContact(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		pc->data = (PeoInfo*)realloc(pc->data, sizeof(PeoInfo) * INIT_MAX * 2);
		if (pc->data == NULL)
		{
			perror("realloc error");
		}
		pc->capacity = pc->capacity * 2;
		printf("扩容成功\n");
	}
}

void AddContact(Contact* pc)
{
	assert(pc);
	//自动扩容
	CapacityContact(pc);

	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].address);
	printf("请输入联系人电话:");
	scanf("%s", pc->data[pc->sz].phone);
	printf("请设置联系人组别:");
	scanf("%s", pc->data[pc->sz].class);

	pc->sz++;
	return;
}

void DelContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录中无对象可操作!请先增加!");
		mune1();
		return;
	}
	int ret = SearchByName(pc);
	if (ret == -1)
	{
		printf("删除失败请重新操作!");
		mune1();
		return;
	}
	int i = ret;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];

	}

	printf("删除成功!\n");
	//这里并不是完全删除,把\0发给int时默认为零,我们sz减减,就相当于访问不到那片空间
	pc->sz--;
	mune1();
}

int SearchContact(const Contact* pc)
{
	assert(pc);
	//多种方式查找:
	mune();
	int input;
	int ret = -1;
	do {
		//选项的输入
		printf("请输入选项>:");
		scanf("%d", &input);
		//若输入的是菜单选择里面的,就执行但不跳出循环,处于等待界面
		//若输入为0,则判断为FALSE,跳出循环,
		switch (input)
		{
		case S_ByName:
			ret = SearchByName(pc);
			break;
		case S_ByAge:
			SearchByAge(pc);
			break;
		case S_BySex:
			SearchBySex(pc);
			break;
		case S_ByAddr:
			SearchByAddr(pc);
			break;
		case S_ByPhone:
			ret = SearchByPhone(pc);
			break;
		case S_ByClass:
			SearchByClass(pc);
			break;
		case EXIT:
			printf("查找完成,已经返回上一级\n");
			mune1();
			break;
		default:
			printf("该查找方式还待开发哦,请重新输入\n");
			break;
		}
	} while (input);
	return ret;
}

	int SearchByName(const Contact* ps)
{
	int i = 0;
	char name[NAME_MAX];
	int k = 1;
	printf("请输入需要的联系人名字:");
	scanf("%s", name);
	for (i = 0; i < ps->sz; i++)
	{
		if (strcmp(name, ps->data[i].name) == 0)
		{
			//暂时不考虑重名
			if (k == 1)
			{
				printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
				k--;
			}

			printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
				ps->data[i].name,
				ps->data[i].age,
				ps->data[i].sex,
				ps->data[i].address,
				ps->data[i].phone,
				ps->data[i].class);

			return i;
		}
	}
	printf("无法找到该联系人信息\n");
	return -1;
}

	void SearchByAge(const Contact* ps)
{
	int i = 0;
	int age;
	int flag = 0;
	int k = 1;
	printf("请输入需要查找联系人的年龄:");
	scanf("%d", &age);
	for (i = 0; i < ps->sz; i++)
	{
		if (age == ps->data[i].age)
		{
			flag = 1;
			if (k == 1)
			{
				printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
				k--;
			}

			printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
				ps->data[i].name,
				ps->data[i].age,
				ps->data[i].sex,
				ps->data[i].address,
				ps->data[i].phone,
				ps->data[i].class);
		}
	}
	if (flag)
	{
		return;
	}
	else
	{
		printf("无法找到该联系人信息\n");
	}
}

	void SearchBySex(const Contact* ps)
{
	int i = 0;
	char sex[SEX_MAX];
	int flag = 0;
	int k = 1;
	printf("请输入需要查找联系人的性别:");
	scanf("%s", sex);
	for (i = 0; i < ps->sz; i++)
	{
		if (strcmp(sex, ps->data[i].sex) == 0)
		{
			flag = 1;
			if (k == 1)
			{
				printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
				k--;
			}
			printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
				ps->data[i].name,
				ps->data[i].age,
				ps->data[i].sex,
				ps->data[i].address,
				ps->data[i].phone,
				ps->data[i].class);
		}
	}
	if (flag)
	{
		return;
	}
	else
	{
		printf("无法找到该联系人信息\n");
	}
}

	void SearchByAddr(const Contact* ps)
{
	{
		int i = 0;
		char addr[ADDR_MAX];
		int flag = 0;
		int k = 1;
		printf("请输入需要查找联系人的地址:");
		scanf("%s", addr);
		for (i = 0; i < ps->sz; i++)
		{
			if (strcmp(addr, ps->data[i].address) == 0)
			{
				flag = 1;
				if (k == 1)
				{
					printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
					k--;
				}
				printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
					ps->data[i].name,
					ps->data[i].age,
					ps->data[i].sex,
					ps->data[i].address,
					ps->data[i].phone,
					ps->data[i].class);
			}
		}
		if (flag)
		{
			return;
		}
		else
		{
			printf("无法找到该联系人信息\n");
		}
	}
}

	void SearchByClass(const Contact* ps)
{
	{
		int i = 0;
		char class[CLASS_MAX];
		int flag = 0;
		int k = 1;
		printf("请输入需要查找联系人的组别:");
		scanf("%s", class);
		for (i = 0; i < ps->sz; i++)
		{
			if (strcmp(class, ps->data[i].class) == 0)
			{
				flag = 1;
				if (k == 1)
				{
					printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
					k--;
				}
				printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
					ps->data[i].name,
					ps->data[i].age,
					ps->data[i].sex,
					ps->data[i].address,
					ps->data[i].phone,
					ps->data[i].class);
			}
		}
		if (flag)
		{
			return;
		}
		else
		{
			printf("无法找到该联系人信息\n");
		}
	}
}

	int SearchByPhone(const Contact* ps)
{
	int i = 0;
	char phone[PHONE_MAX];
	int k = 1;
	printf("请输入需要查找联系人电话号码:");
	scanf("%s", phone);
	for (i = 0; i < ps->sz; i++)
	{
		if (strcmp(phone, ps->data[i].phone) == 0)
		{
			if (k == 1)
			{
				printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
				k--;
			}

			printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
				ps->data[i].name,
				ps->data[i].age,
				ps->data[i].sex,
				ps->data[i].address,
				ps->data[i].phone,
				ps->data[i].class);

			return i;
		}
	}
	printf("无法找到该联系人信息\n");
	return -1;
}

void ModifyContact(Contact* pc)
{
	int ret = -1;
	int i;
	i = SearchByName(pc);
	if (i != ret)
	{
		printf("请输入修改的内容(部分):\n");
		printf("请输入联系人名字:");
		scanf("%s", pc->data[i].name);
		printf("请输入联系人年龄:");
		scanf("%d", &(pc->data[i].age));
		printf("请输入联系人性别:");
		scanf("%s", pc->data[i].sex);
		printf("请输入联系人地址:");
		scanf("%s", pc->data[i].address);
		printf("请输入联系人电话:");
		scanf("%s", pc->data[i].phone);

	}

}

void PrintContact(const Contact* pc)
{
	assert(pc);
	int i = 0;
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话", "组别");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\t%-12s\n",
			pc->data[i].name,
			pc->data[i].age,
			pc->data[i].sex,
			pc->data[i].address,
			pc->data[i].phone,
			pc->data[i].class);
	}
}

void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	pc = NULL;
}

void SaveContact(const Contact* pc)
{
	FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\contact.txt", "wb");
	if (NULL == pf)
	{
		perror("SaveContact error");
	}
	else
	{
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存成功\n");
	}
}

void SortContact(const Contact* pc)
{
	assert(pc);

	DP_QuickSort(pc->data, 0, pc->sz - 1);

	printf("排序完成\n");

}

void Swap(PeoInfo* left, PeoInfo* right)
{
	PeoInfo t = *left;
	*left = *right;
	*right = t;
}

int GerMidNumi(PeoInfo* a, int left, int right)
{
	int mid = (right + left) / 2;

	if (strcmp(a[left].name, a[mid].name) > 0)
	{
		if (strcmp(a[mid].name, a[right].name) > 0)
		{
			return mid;
		}
		else if (strcmp(a[left].name, a[right].name) < 0)
		{
			return left;
		}
		else
		{
			return right;
		}
	}
	else
	{
		if (strcmp(a[left].name, a[right].name) > 0)
		{
			return left;
		}
		else if (strcmp(a[mid].name, a[right].name) < 0)
		{
			return mid;
		}
		else
		{
			return right;
		}
	}
}

void  DP_QuickSort(PeoInfo* a, int left, int right)
{
	int end = right, begin = left;
	if (left >= right)
		return;
	//小区间优化:
	if ((right - left + 1) > 10)
	{
		//方案二:优化:三数取中:不是最小,最大的哪一个(优化更加明显)
		int midi = GerMidNumi(a, left, right);
		if (midi != left)
			Swap(&a[left], &a[midi]);

		int prev = left;
		int cur = prev + 1;
		int keyi = left;

		while (cur <= right)
		{
			if (strcmp(a[cur].name, a[keyi].name) < 0 && ++prev != cur)
				Swap(&a[cur], &a[prev]);
			cur++;
		}
		Swap(&a[prev], &a[keyi]);
		keyi = prev;

		DP_QuickSort(a, begin, keyi - 1);
		DP_QuickSort(a, keyi + 1, end);
	}
	else
	{
		InsertSort(a, right - left + 1);
	}
}

void InsertSort(PeoInfo* a, int n)
{
	for (int i = 1; i < n; i++)
	{
		int end = i - 1;
		PeoInfo tmp = a[i];
		// 将tmp插入到[0,end]区间中,保持有序
		while (end >= 0)
		{
			if (strcmp(tmp.name, a[end].name) < 0)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

void  Hide_InitContact(Contact* pc)
{
	assert(pc);
	pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * INIT_MAX);
	if (pc->data == NULL)
	{
		perror("Hide_malloc error");
	}
	pc->sz = 0;
	pc->capacity = INIT_MAX;

	//读取文件
	Hide_LondContact(pc);
}

void Hide_LondContact(Contact* pc)
{
	FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "rb");
	if (NULL == pf)
	{
		perror("Hide_LondContact error");
	}
	else
	{
		int i = 0;
		PeoInfo tmp = { 0 };
		while (fread(&tmp, sizeof(PeoInfo), 1, pf))
		{
			CapacityContact(pc);
			pc->data[i] = tmp;
			pc->sz++;
			i++;
		}
		fclose(pf);
		pf = NULL;
	}
}

void ShowHide()
{
	char arr1[] = "Welcome to Hide Room !!!";
	char arr2[] = "########################";

	int left = 0;
	int right = strlen(arr1) - 1;

	while (left <= right)
	{
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		printf("%s\n", arr2);
		Sleep(1000);
		system("cls");
		left++;
		right--;
	}
	printf("%s\n", arr1);
}

void Administrators(char* password)
{
	char newpassword[20];
	printf("请输入修改密码》:");
	scanf("%s", newpassword);
	strcpy(password, newpassword);
	printf("修改成功\n");
}

bool EncryptionContact()
{
	int i = 0;
	char password[20] = { 0 };
	char insure[20] = { "123456" };

	FILE* pf1 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "rb");
	if (NULL == pf1)
	{
		perror("password1 error");
	}
	else
	{
		char tmp[20] = { 0 };
		fread(&tmp, 20, 1, pf1);
		strcpy(insure, tmp);
		fclose(pf1);
		pf1 = NULL;
	}

	printf("请输入进入密码》:");
	for (i = 0; i < 3; i++)
	{
		scanf("%s", password);
		if (0 == strcmp(password, insure))
		{
			return true;
		}
		else if (0==strcmp(password,"管理员入口"))
		{
			Administrators(insure);
			FILE* pf2 = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\password.txt", "wb");
			if (NULL == pf2)
			{
				perror("password2 error");
			}
			else
			{
				fwrite(insure, 20, 1, pf2);
				fclose(pf2);
				pf2 = NULL;
				printf("保存成功\n");
			}
			printf("请输入进入密码》:");
		}
		else
		{
			printf("第%d次密码输入错误\n", i + 1);
			if (i < 2)
				printf("请重新输入》:");
		}
	}
	//linux操作系统实现
	printf("密码输入三次错误!请在24小时后重试\n");
	return false;

}

void Hide_SaveContact(const Contact* pc)
{
	FILE* pf = fopen("D:\\class\\c学\\上传c学\\c-science\\text.txl.c\\text.txl.c\\hide_contact.txt", "wb");
	if (NULL == pf)
	{
		perror("Hide_SaveContact error");
	}
	else
	{
		int i = 0;
		for (i = 0; i < pc->sz; i++)
		{
			fwrite((pc->data + i), sizeof(PeoInfo), 1, pf);
		}
		fclose(pf);
		pf = NULL;
		printf("保存成功\n");
	}
}

4.代码缺陷,以及优化:

4.1 内存泄漏:

内存泄漏是必须注意的,这里开始malloc了空间,如果没有释放则会影响项目的速度,举个例子:

  • 这里是一个死循环,用来模拟长期在线的服务器,当出现内存泄漏问题会有什么后果:
    在这里插入图片描述
  • 开始运行代码:
    在这里插入图片描述
    可以注意vs2019所占得内存以及多了这么多,这些没用的空间,会影响项目整体性能,当然在这里只需要把黑匣子关掉,就马上恢复了,这是结束的时候自动释放了。如果未来我们从事的是24小时在线的服务器(比如各种app),出现这种内存泄漏可是及其危险的。所以我们需要手动释放。
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
	pc->capacity = 0;
	pc->sz = 0;
	pc = NULL;
}

代码简单不累,相当实惠哈哈,所以这是要养成的习惯,在申请空间后一定记住手动free多余空间;

4.2 代码可读性维护:

  • 有句流传江湖的话:程序员写完代码,只有自己和上帝认识!
  • 在项目合作过程中的,代码可读性十分重要
  • 比如函数命名、Switch语句的case选项可以枚举代替、以及增加必要注释。增加代码可读性,这里就举case这个例子

在这里插入图片描述
是不是还是有些区别的呢?

4.3 代码的可调式性:

我们往往可以发现我们在写类似“项目”的时候,发现代码一长,是真的难调,一调就是一天,所以我们就要用一些技巧:

  • 1.善用const关键字,对于一些参数无需修改的函数,大胆加上这个关键字,比如通讯录的打印函数
  • 2.会用assert()函数,使用函数我们通常成为暴力检查,这个函数会让你的调试找到方向,明白什么地方错了,便于调试。
  • 3.perror()函数也是如此,若不清楚可以自行查询。

PS:好久没写博客咯,后续会抓紧的哈哈!美图献上(夹带私货),一起加油!
在这里插入图片描述

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

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

相关文章

从零开始学习JVM--初识Java虚拟机

1 虚拟机与Java虚拟机 1.1 基本介绍 所谓虚拟机&#xff08;Virtual Machine&#xff09;。就是一台虚拟的计算机。它是一款软件&#xff0c;用来执行一系列虚拟计算机指令。大体上&#xff0c;虚拟机可以分为系统虚拟机和程序虚拟机。 系统虚拟机&#xff1a;完全对物理计算…

树莓派(主)与STM32(从)使用SPI通信(持续更新中)

1.实验目的 使用树莓派作为主机向 STM32 从机发送数据&#xff0c;STM32 收到数据后通过串口的方式将数据打印到电脑上&#xff0c;同时返回给树莓派数据。树莓派接收到数据后打印在控制台上。 2.SPI 简介 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接…

进程控制下(程序替换部分)

目录&#xff1a; 1. 进程程序替换的原理 2.将磁盘的数据和代码加载进物理内存 3.程序替换函数的基本使用 ----------------------------------------------------------------------------------------------------------------------------- 1. 进程程序替换的原理 蓝色框内…

图解LeetCode——48. 旋转图像

一、题目 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 二、示例 2.1> 示例 1&#xff1a; 【输入】matrix [[1,2,3],[…

AVL树的实现

文章目录 AVL树前言1. AVL树的概念2. AVL树的结构2.1 AVL树节点的定义2.2 AVL树的结构 3. AVL树的操作3.1 AVL树的插入3.2 AVL树的旋转(重要)3.2.1 左单旋过程代码 3.2.2 右单旋过程代码 3.2.3 左右双旋过程代码 3.2.4 右左双旋过程代码 旋转整体代码 3.3 AVL树的验证3.4 AVL树…

Day967.团队拓扑学 -遗留系统现代化实战

团队拓扑学 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于团队拓扑学的内容。 看看最近这几年来新诞生的组织结构模型——团队拓扑学&#xff08;Team Topologies&#xff09;。 一、团队拓扑 尽管组件团队、特性团队和 Spotify 模型&#xff0c;都为团队的组成提…

JavaScript实现输入年份判断是否为闰年的代码

以下为实现输入年份判断是否为闰年的程序代码和运行截图 目录 前言 一、输入年份判断是否为闰年 1.1 运行流程及思想 1.2 代码段 1.3 JavaScript语句代码 1.4 运行截图 前言 1.若有选择&#xff0c;您可以在目录里进行快速查找&#xff1b; 2.本博文代码可以根据题目要…

阿里云 aliplayer 加密的视频 key解密解密下载过程实现

第一步&#xff1a;打开开发者工具 打开需要下载的视频链接&#xff0c;按F12打开开发者工具&#xff0c;然后强制刷新&#xff08;ctrlf5&#xff09; 第二步&#xff1a;定位key加密 内存搜索&#xff0c;关键词&#xff1a;_sce_dlgtqred 进入第二个结果&#xff1a;https…

Map在循环中修改自己的key与value

Map在循环中修改自己的key与value 1.解决方案2.深入了解 1.解决方案 使用ConcurrentHashMap package com.company.newtest;import java.util.*; import java.util.concurrent.ConcurrentHashMap;public class test30 {public static void main(String[] args) {Map<String…

【Linux】进程信号详解(一)信号概念信号产生

文章目录 前言信号概念信号入门1.查看所有信号2.信号处理常见方式3. 发送信号过程信号是谁发送的&#xff1f; 信号产生介绍signal函数来捕捉进程1.通过键盘产生例子&#xff1a;Core Dump核心转储 2.程序出现异常&#xff0c;导致收到信号空指针异常浮点数异常 3. 调用系统函数…

1_1torch基础知识

1、torch安装 pytorch cuda版本下载地址&#xff1a;https://download.pytorch.org/whl/torch_stable.html 其中先看官网安装torch需要的cuda版本&#xff0c;之后安装cuda版本&#xff0c;之后采用pip 下载对应的torch的gpu版本whl来进行安装。使用pip安装时如果是conda需要切…

【Linux】安装部署elasticsearch

安装 Java 在安装 Elasticsearch 之前&#xff0c;您需安装并配置好 JDK, 设置好环境变量 $JAVA_HOME。 众所周知&#xff0c;Elasticsearch 版本很多&#xff0c;不同的版本对 Java 的依赖也有所差别: Elasticsearch 5 需要 Java 8 以上版本&#xff1b;Elasticsearch 6.5 开…

旋转目标检测【1】如何设计深度学习模型

前言 平常的目标检测是平行的矩形框&#xff0c;“方方正正”的&#xff1b;但对于一些特殊场景&#xff08;遥感&#xff09;&#xff0c;需要倾斜的框&#xff0c;才能更好贴近物体&#xff0c;旋转目标检测来啦~ 一、如何定义旋转框 常见的水平框参数表达方式为&#xff0…

PMP项目管理-[第九章]资源管理

资源管理知识体系&#xff1a; 规划资源管理&#xff1a; 估算活动资源&#xff1a; 获取资源&#xff1a; 建设团队&#xff1a; 管理团队&#xff1a; 9.1 规划资源管理 定义&#xff1a;定义如何估算、获取、管理和利用团队以及实物资源的过程 作用&#xff1a;根据项目类型…

Azure Data Lake Storage Gen2 简介

Azure Data Lake Storage Gen2 基于 Azure Blob 存储构建&#xff0c;是一套用于大数据分析的功能。 Azure Data Lake Storage Gen1 和 Azure Blob Storage 的功能在 Data Lake Storage Gen2 中组合在一起。例如&#xff0c;Data Lake Storage Gen2 提供规模、文件级安全性和文…

Cesium入门之三:隐藏Cesium初始化页面小部件的两种方法

上一级我们实现了第一个三维地球&#xff0c;但是在这个页面上有很多小部件&#xff0c;我们不想让其显示&#xff0c;应该如何设置呢&#xff1f;这一节我们通过两种方式来隐藏小部件 方法1&#xff1a;通过js代码实现 在js代码中&#xff0c;通过在new Cesium.Viewer(conta…

算法之路--直接插入排序算法

在介绍插入排序算法之前&#xff0c;先举证一个我们都熟悉不过的例子即可理解插入排序。我们在打牌的时候&#xff0c;由于每次抽到的牌大小不一&#xff0c;为了在出牌时了解自己手里都还剩什么牌型&#xff0c;所以每次对抽到的新牌都会做一个排序&#xff0c;怎么比较呢&…

AWS 中的另外一种远程工具 AWS Session Manager

作者&#xff1a;SRE运维博客 博客地址&#xff1a;https://www.cnsre.cn/ 文章地址&#xff1a;https://www.cnsre.cn/posts/230129126154/ 相关话题&#xff1a;https://www.cnsre.cn/tags/aws/ 背景需求 因为项目的安全性。为了避免项目的服务器暴露在公网中。很多时候我们…

设计原则之【迪米特法则】,非礼勿近

文章目录 一、什么是迪米特法则1、理解迪米特法则2、如何理解“高内聚、松耦合”&#xff1f; 二、实例1、实例12、实例2 一、什么是迪米特法则 迪米特原则&#xff08;Law of Demeter LoD&#xff09;是指一个对象应该对其他对象保持最少的了解&#xff0c;又叫最少知道原则&…

支付系统设计三:渠道网关设计01-总览

文章目录 前言一、开发框架二、E-R图三、管理后台配置四、运行时执行流程五、屏蔽渠道差异总结 前言 在《支付系统设计一&#xff1a;支付系统产品化》文章中&#xff0c;我们知道支付渠道网关主要具有以下功能&#xff1a; 统一支付出口&#xff0c;提供丰富的支付工具原子能…