【c语言进阶】常见的静态通讯录

news2024/10/7 16:21:11

在这里插入图片描述

🚀write in front🚀
📜所属专栏:c语言学习
🛰️博客主页:睿睿的博客主页
🛰️代码仓库:🎉VS2022_C语言仓库
🎡您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!
关注我,关注我,关注我你们将会看到更多的优质内容!!

在这里插入图片描述

文章目录

  • 😊前言:😊
  • 😉1.文件的建立:😉
  • 😃2.头文件contact.h的声明:😃
  • 🤐3.测试文件test.c的实现:🤐
    • 3.1菜单menu的打印:
    • 3.2通讯录contact函数:
      • 3.2.1通讯录的初始化:
      • 3.2.2 do while循环和switch语句实现用户选择
    • 3.3主函数:
  • 👻4.通讯录文件contact.c:👻
    • 4.1初始化通讯录函数:
    • 4.2增加联系人函数:
    • 4.3删除联系人函数:
      • 4.3.1查找姓名函数:
    • 4.4查找联系人函数:
    • 4.5修改联系人函数:
    • 4.6打印通讯录函数:
    • 4.7按名字排序通讯录函数:
  • 完整代码:
    • contact.h
    • test.c
    • contact.c
  • 🫠总结:🫠

😊前言:😊

  在前面的学习中,我们学习了结构体的相关知识常见结构体知识大全。为了更好的帮助各位小伙伴们理解和学会使用结构体,今天我们就来尝试通过使用结构体, 零基础 编写出我们自己的通讯录。我们知道,普通的通讯录功能就这几个:增加新联系人、删除联系人、查找联系人、修改联系人信息、对联系人信息进行打印,对联系人进行排序这六个功能,下面我们就来一一实现他们。

😉1.文件的建立:😉

我们还是按照标准工程格式,分别建立三个文件:
①.头文件Contact.h:
  该文件是用于包含其它头文件,并存放功能实现函数的函数声明。

②.函数定义文件Contact.c:
  这个文件主要是用于书写所有的程序功能实现的函数定义。一来将所有定义书写在一起便于我们进行阅读、修改;二来大大提升了程序的可移植性。第三点最重要,我们可以将其设置为静态库从而实现对我们函数代码的隐藏。

③.工程测试文件test.c:
   我们在这个文件里去书写我们的程序主体部分,并对程序进行执行逻辑的编辑和检查。结合前两个文件的使用,可以使得我们的程序逻辑变得清晰,极有利于我们进行程序的运行逻辑检查。

😃2.头文件contact.h的声明:😃

  首先我们要搞清楚我们的操作对象究竟是谁,我们可以想一想,我们平常在使用通讯录时,我们的操作对象应当是一个一个的联系人,以及每一个联系人的相关信息,于是在这里,我们使用结构体来进行实现:

typedef struct PeoInfo
{
	char name[MAX_NAME];
    //联系人信息:姓名
	char sex[MAX_SEX];
    //联系人信息:性别
	int age;
    //联系人信息:年龄
	char tele[MAX_TELE];
    //联系人信息:联系方式
	char addr[MAX_ADDR];
    //联系人信息:住址
}PeoInfo;

  我们可以在头文件中(全局的)定义一个名为 PeoInfo (译:个人信息)的结构体类型 struct PeoInfo,并使用 typedef 关键字将该类型重命名为 **PeoInfo **,接着我们在结构体内部创建了姓名、性别、年龄、联系方式与住址五个结构体成员,以用于存储结构体变量的信息。
  然而我们要知道一个通讯录里到底存了多少人,必须有一个变量来记录这个个数,所以我们可以再创建一个结构体用来封装这两个需要进行传参的数据:

typedef struct contact
{
	PeoInfo data[MAX];
	int sz;
}contact;

  并且为了以后便于对通讯录大小进行修改和维护,我们使用宏定义来确定来联系人各项信息的最大值:

#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 30

  最后,我们要对test.c在contact.c里引用的函数进行声明:(这里只是先声明函数,后面都会一一讲解)

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

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

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

//显示通讯录中的信息
void ShowContact(const Contact* pc);

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

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

//排序联系人
void sortContact(contact* con);

🤐3.测试文件test.c的实现:🤐

  首先我们自定义两个函数,menu 为菜单函数,负责向玩家打印游戏菜单;Contact 为通讯录功能函数,负责实现整个通讯录功能的逻辑实现:

#include<stdio.h>
 
void menu()
{
	...
}
 
void Contact()
{
    ...
}
 
int main()
{
	Contact();
 
	return 0;
}

3.1菜单menu的打印:

这个函数很容易实现,我们就不再多说:😘

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"


void menu()
{
	printf("**********************************\n");
	printf("**********************************\n");
	printf("******** 欢迎使用本通讯录 ********\n");
	printf("**********************************\n");
	printf("***** 本通讯录现提供以下功能 *****\n");
	printf("************ 1.Add ***************\n");
	printf("************ 2.Del ***************\n");
	printf("************ 3.Search ************\n");
	printf("************ 4.Modify ************\n");
	printf("************ 5.Print *************\n");
	printf("************ 6.sort **************\n");
	printf("************ 0.exit**************\n");
	printf("**********************************\n");
}

3.2通讯录contact函数:

3.2.1通讯录的初始化:

  首先我们要对通讯录初始化(* 初始化函数Initcontact会在contact.c文件中介绍 *)对创建好的初始通讯录进行初始化,否则内部的数据将为随机值而无法预测,导致程序的不合法:

void Contact()
{
	int input = 0;
	contact con;
	Initcontact(&con);

3.2.2 do while循环和switch语句实现用户选择

  那么,我们如何将菜单,使用者的选择结合在一起,并循环使用呢?
  我们通过使用 do…while 循环语句,保证了我们程序的多次执行。并且我们通过将 输入值 input 作为循环判断条件,既减少了变量的创建从而节省了空间,也避免了因输入错误导致直接跳出执行。同时,通过借助 switch 分支语句 ,我们也实现了对通讯录不同功能的调用和对输入选择的合法性检测:


	do
	{
		menu();
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			SeachContact(&con);
			break;
		case 4:
			ModifyContact(&con);
			break;
		case 5:
			PrintContact(&con);
			break;
		case 6:
			sortContact(&con);
			break;
		case 0:
			printf("已成功退出");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);

}

3.3主函数:

  主函数也很简单,没有什么说的😊

int main()
{
	Contact();
	return 0;
}

👻4.通讯录文件contact.c:👻

  接下来,我将带大家一一实现该文件的每个函数!

4.1初始化通讯录函数:

  使用memeset函数将p->data所指向的空间中的数据初始化为0
  操作的空间大小为sizeof函数所计算出的p->data所指向空间的大小,即整个联系人数据的结构体数组data所占的空间的大小

void Initcontact(contact* con)
{
	assert(con);
	con->sz = 0;
	memset(con->data, 0, sizeof(con->data));
}

4.2增加联系人函数:

  函数功能部分很简单,每次询问一项联系人信息,然后由用户输入该项信息,并向该联系人保存地址处存入该信息。但是在这个期间仍有很多的细节需要我们去注意。

  • 第一个要点是信息存入的地址,我们对于通讯录的访问是通过指针进行的,所以信息的存入地址一定是对应的存入地址,数组应当使用指针进行访问,变量则应当使用取地址操作符进行访问;
  • 第二点数组的下标恰好与我们初始化的统计变量 sz 相同,并且在每次存储完联系人信息后,我们对会将用于统计联系人数量的统计变量sz 加上一,这时它又变成了下一次需要访问时的结构体数组的下标。
  • 第三点我们在进行存储前还应当进行一次判断,即判断通讯簿内是否已经存满了联系人信息,如果已经存满了联系人信息,则应当提示用户没有足够的空间;
void AddContact(contact* con)
{
	assert(con);
	if (con->sz == 99)
	{
		printf("通讯录已经存满,请联系操作人员");
		return;
	}
	printf("请输入联系人姓名:>");
	scanf("%s", con->data[con->sz].name);
	printf("请输入联系人性别:>");
	scanf("%s",con->data[con->sz].sex);
	printf("请输入联系人年龄:>");
	scanf("%d", &(con->data[con->sz].age));
	printf("请输入联系人联系方式:>");
	scanf("%s", con->data[con->sz].tele);
	printf("请输入联系人住址:>");
	scanf("%s", con->data[con->sz].addr);
	printf("联系人信息添加成功!\n");
	con->sz++;
}

4.3删除联系人函数:

  在想要删除联系人信息时,我们首先应当对通讯录中的内容进行判断,如果此时通讯录中没有存储任何联系人的信息,则应当提示用户没有联系人信息(后面都会有这个判断,就不一一讲解了)

if (p->sz == 0)
{
    printf("当前通讯录为空!\n");
}

  查找联系人的逻辑很简单,我们只需要定义一个字符串,然后让用户输入想要查找的联系人的姓名,用一个函数来查找位置即可。
  当删除时,我们的实现方式是,让选中联系人的后一个联系人将其覆盖,并以此类推至后面的所有联系人,并在完成后,将统计变量减一,即缩短联系人信息数组。如果是最后一个人需要被删除,则不用管他。在循环中一定要注意是否越界!这是编程的好习惯!

printf("请输入要删除人名字:>");
	scanf("%s", name);
	int ret = FindByName(con, name);
	int i = 0;
	if (-1 == ret)
	{
		printf("没有找到此人\n");
		return;
	}
	else
	{
		for (i = ret; i < con->sz-1; i++)
		{
			con->data[i] = con->data[i + 1];
		}
		con->sz--;
		memset(&con->data[i], 0, sizeof(con->data[i]));
		printf("删除成功!\n");
	}
}

4.3.1查找姓名函数:

  接着我们就可以将通讯录中的联系人姓名与用户输入的姓名,使用遍历与 strcmp 函数进行比较.找到返回下标,没找到返回-1:(该函数后面也都会用到,后面就不一一讲解

int FindByName(contact* con, char name[])
{
	assert(con);
	int i = 0;
	for (i = 0; i < con->sz; i++)
	{
		if (strcmp(con->data[i].name,name) == 0)
		{
			return i;
		}
	}
	return -1;
}

4.4查找联系人函数:

  这个函数很简单,就是后面打印的时候要注意这些知识点:

  • %s,%d等在d前面加数字表示有多少位,如果这位置没有数字,就补为空格。
  • 数字为+数字表示右对齐,加-号表示左对齐。
  • 我们可以将字符串常量以%s形式打印出来,以此控制长度。
void SeachContact(contact* con)
{
	assert(con);
	char name[MAX_NAME];
	if (con->sz == 0)
	{
		printf("通讯录为空,无法输入\n");
		return;
	}
	printf("请输入查找人名字");
	scanf("%s", name);
	int ret = FindByName(con, name);
	if (ret == -1)
	{
		printf("您查找的人不存在!\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
	printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", con->data[ret].name, 
		con->data[ret].age, 
		con->data[ret].sex, 
		con->data[ret].addr, 
		con->data[ret].tele);
}

4.5修改联系人函数:

此函数就是在找到相应联系人后修改即可

void ModifyContact(contact* con)
{
	assert(con);
	char name[MAX_NAME] = { 0 };
	if (con->sz == 0)
	{
		printf("通讯录为空,无法修改\n");
		return;
	}
	printf("请输入查找人名字");
	scanf("%s", name);
	int ret = FindByName(con, name);
	if (-1 == ret)
	{
		printf("您要修改的人不存在\n");
		return;
	}
	printf("请输入联系人姓名:>");
	scanf("%s", con->data[ret].name);
	printf("请输入联系人性别:>");
	scanf("%s", con->data[ret].sex);
	printf("请输入联系人年龄:>");
	scanf("%d", &(con->data[ret].age));
	printf("请输入联系人住址:>");
	scanf("%s", con->data[ret].addr);
	printf("请输入联系人联系方式:>");
	scanf("%s", con->data[ret].tele);
	printf("联系人信息修改成功!\n");
}

4.6打印通讯录函数:

  这个函数就是通过循环打印所有的消息即可,也非常简单:

void PrintContact(contact* con)
{
	printf("%-10s\t%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n","联系人", "姓名", "年龄", "性别", "地址", "电话");
	for (int i = 0; i < con->sz; i++)
	{
		printf("%-10d\t%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n",i+1, con->data[i].name,
			con->data[i].age,
			con->data[i].sex,
			con->data[i].addr,
			con->data[i].tele);
	}
}

4.7按名字排序通讯录函数:

  这里我们就可以用到我们所学的qsort函数了,忘记的家人们可以看看之前写的博客:qsort函数。这里需要注意的是,在写比较大小函数中时,强转的类型是PeoInfo,因为我们是对通讯录排序,对那个结构体数组排序,并且要是升序。这些知识点相信大家复习完就可以知道。

int cmp_con_by_name(const void* e1, const void* e2)
{
	return (strcmp(((PeoInfo *)e1)->name, ((PeoInfo*)e2)->name));
}
void sortContact(contact* con)
{
	assert(con);
	if (0 == con->sz)
	{
		printf("通讯录为空,无法排序\n");
		return;
	}
	qsort(con->data, con->sz, sizeof(con->data[0]), cmp_con_by_name);
	printf("排序成功");
}

完整代码:

contact.h


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

#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 20

typedef struct PeoInfo
{
	char name[MAX_NAME];
	char sex[MAX_SEX];
	int age;
	char addr[MAX_ADDR];
	char tele[MAX_TELE];
}PeoInfo;

typedef struct contact
{
	PeoInfo data[MAX];
	int sz;
}contact;

void Initcontact(contact *con);

void AddContact(contact *con);

void DelContact(contact *con);

void SeachContact(contact *con);

void ModifyContact(contact* con);

void PrintContact(contact* con);

void sortContact(contact* con);

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"


void menu()
{
	printf("**********************************\n");
	printf("**********************************\n");
	printf("******** 欢迎使用本通讯录 ********\n");
	printf("**********************************\n");
	printf("***** 本通讯录现提供以下功能 *****\n");
	printf("************ 1.Add ***************\n");
	printf("************ 2.Del ***************\n");
	printf("************ 3.Search ************\n");
	printf("************ 4.Modify ************\n");
	printf("************ 5.Print *************\n");
	printf("************ 6.sort **************\n");
	printf("************ 0.exit**************\n");
	printf("**********************************\n");
}
void Contact()
{
	int input = 0;
	contact con;
	Initcontact(&con);
	do
	{
		menu();
		printf("请选择>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			AddContact(&con);
			break;
		case 2:
			DelContact(&con);
			break;
		case 3:
			SeachContact(&con);
			break;
		case 4:
			ModifyContact(&con);
			break;
		case 5:
			PrintContact(&con);
			break;
		case 6:
			sortContact(&con);
			break;
		case 0:
			printf("已成功退出");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);

}
int main()
{
	Contact();
	return 0;
}

contact.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "contact.h"

int FindByName(contact* con, char name[])
{
	assert(con);
	int i = 0;
	for (i = 0; i < con->sz; i++)
	{
		if (strcmp(con->data[i].name,name) == 0)
		{
			return i;
		}
	}
	return -1;
}
void Initcontact(contact* con)
{
	assert(con);
	con->sz = 0;
	memset(con->data, 0, sizeof(con->data));
}

void AddContact(contact* con)
{
	assert(con);
	if (con->sz == 99)
	{
		printf("通讯录已经存满,请联系操作人员");
		return;
	}
	printf("请输入联系人姓名:>");
	scanf("%s", con->data[con->sz].name);
	printf("请输入联系人性别:>");
	scanf("%s",con->data[con->sz].sex);
	printf("请输入联系人年龄:>");
	scanf("%d", &(con->data[con->sz].age));
	printf("请输入联系人联系方式:>");
	scanf("%s", con->data[con->sz].tele);
	printf("请输入联系人住址:>");
	scanf("%s", con->data[con->sz].addr);
	printf("联系人信息添加成功!\n");
	con->sz++;
}

void DelContact(contact* con)
{
	assert(con);
	char name[100];
	if (con->sz == 0)
	{
		printf("通讯录为空,无法删除\n");
		return;
	}
	printf("请输入要删除人名字:>");
	scanf("%s", name);
	int ret = FindByName(con, name);
	int i = 0;
	if (-1 == ret)
	{
		printf("没有找到此人\n");
		return;
	}
	else
	{
		for (i = ret; i < con->sz-1; i++)
		{
			con->data[i] = con->data[i + 1];
		}
		con->sz--;
		memset(&con->data[i], 0, sizeof(con->data[i]));
		printf("删除成功!\n");
	}
}

void SeachContact(contact* con)
{
	assert(con);
	char name[MAX_NAME];
	if (con->sz == 0)
	{
		printf("通讯录为空,无法输入\n");
		return;
	}
	printf("请输入查找人名字");
	scanf("%s", name);
	int ret = FindByName(con, name);
	if (ret == -1)
	{
		printf("您查找的人不存在!\n");
		return;
	}
	printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
	printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", con->data[ret].name, 
		con->data[ret].age, 
		con->data[ret].sex, 
		con->data[ret].addr, 
		con->data[ret].tele);
}

void ModifyContact(contact* con)
{
	assert(con);
	char name[MAX_NAME] = { 0 };
	if (con->sz == 0)
	{
		printf("通讯录为空,无法修改\n");
		return;
	}
	printf("请输入查找人名字");
	scanf("%s", name);
	int ret = FindByName(con, name);
	if (-1 == ret)
	{
		printf("您要修改的人不存在\n");
		return;
	}
	printf("请输入联系人姓名:>");
	scanf("%s", con->data[ret].name);
	printf("请输入联系人性别:>");
	scanf("%s", con->data[ret].sex);
	printf("请输入联系人年龄:>");
	scanf("%d", &(con->data[ret].age));
	printf("请输入联系人住址:>");
	scanf("%s", con->data[ret].addr);
	printf("请输入联系人联系方式:>");
	scanf("%s", con->data[ret].tele);
	printf("联系人信息修改成功!\n");
}

void PrintContact(contact* con)
{
	printf("%-10s\t%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n","联系人", "姓名", "年龄", "性别", "地址", "电话");
	for (int i = 0; i < con->sz; i++)
	{
		printf("%-10d\t%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n",i+1, con->data[i].name,
			con->data[i].age,
			con->data[i].sex,
			con->data[i].addr,
			con->data[i].tele);
	}
}

int cmp_con_by_name(const void* e1, const void* e2)
{
	return (strcmp(((PeoInfo *)e1)->name, ((PeoInfo*)e2)->name));
}
void sortContact(contact* con)
{
	assert(con);
	if (0 == con->sz)
	{
		printf("通讯录为空,无法排序\n");
		return;
	}
	qsort(con->data, con->sz, sizeof(con->data[0]), cmp_con_by_name);
	printf("排序成功");
}

🫠总结:🫠

  到这里,我们的基础通讯录功能就得以实现啦,不过作为基础版本的它仍然存在着许多缺陷,而且他仅仅是一个静态的,一旦关闭exe,所有消息都会消失。在接下来的博客我会对于这个通讯录进行优化!
  更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

专栏订阅:
每日一题
c语言学习
算法
智力题
更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

在这里插入图片描述

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

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

相关文章

2.H3CNE-网络参考模型

OSI参考模型产生背景各大IT设备厂商只支持自己的私有协议&#xff0c;跨厂商设备兼容性差用户购买和维护成本高不利于网络技术发展概念定义了网络中设备所遵守的层次结构优点开放的标准化接口&#xff0c;协议不再封闭多厂商设备兼容易于理解、学习和更新协议标准实现模块化工程…

【Leetcode刷题】141、环形链表

原题链接&#xff1a;https://leetcode.cn/problems/linked-list-cycle/?favorite2cktkvj给你一个链表的头节点 head &#xff0c;判断链表中是否有环。如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的…

Python数据可视化(二)使用统计函数绘制简单图形

该文会讲解一些大家比较熟悉却又经常混淆的统计图形&#xff0c;掌握这些统计图形可以对数据可视化有一个深入理解&#xff0c;并正确使用。2.1 函数 bar()——用于绘制柱状图函数功能&#xff1a;在 x 轴上绘制定性数据的分布特征。调用签名&#xff1a;plt.bar(x,y)。参数说明…

day21|216.组合总和III、17.电话号码的字母组合

216.组合总和III 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k 3, n 7 输出: …

说说配置中心

什么是配置中心在微服务的环境下,将项目需要的配置信息保存在配置中心,需要读取时直接从配置中心读取,方便配置管理的微服务工具可以将部分yml文件的内容保存在配置中心一个微服务项目有很多子模块,这些子模块可能在不同的服务器上,如果有一些统一的修改,需要逐一修改这些子模块…

python数据可视化开发:Matplotlib库基础知识

文章目录前言01.工具栏组件02.图表数据03.设置字体字典&#xff08;1&#xff09;全局字体样式&#xff08;2&#xff09;常用中文字体对应名称&#xff08;3&#xff09;查询当前系统所有字体04.图像配置实例05.图表标题06.文本组件07.坐标轴标签组件08.网格组件09.绘制折线10…

【头歌】双向链表的基本操作

双向链表的基本操作第1关&#xff1a;双向链表的插入操作任务描述本关任务&#xff1a;编写双向链表的插入操作函数。相关知识双链表中用两个指针表示结点间的逻辑关系&#xff1a;指向其前驱结点的指针域prior&#xff0c;指向其后继结点的指针域next。双向链表的结点结构如图…

MySQL数据库面试题[万字汇总]

1) MySQL数据库相关错题本1、存储引擎相关1、MySql的存储引擎的不同MySQL存储引擎主要有InnoDB, MyISAM, Memory, 这三个区别在于:Memory是内存数据引擎, 会断电重启(在双M或者主从架构下会产生较多异常), 且不支持行级锁. 默认索引是数组索引, 支持B索引InnoDB和MyISAM的区别:…

流批一体计算引擎-5-[Flink]的Python Table API和SQL程序

参考Flink从入门到入土&#xff08;详细教程&#xff09; 参考flink的默认窗口触发机制 参考彻底搞清Flink中的Window 参考官方Python API文档 1 IDEA中运行Flink 从Flink 1.11版本开始, PyFlink 作业支持在 Windows 系统上运行&#xff0c;因此您也可以在 Windows 上开发和…

【数据结构】极致详解:树与二叉树(上)——结构与概念

目录 &#x1f6eb;前言&#x1f6eb;&#xff1a; &#x1f680;一、树&#x1f680;&#xff1a; 1.树的概念&#xff1a; 2.树的相关概念&#xff1a; 3.树的表示&#xff1a; 4.树的实际使用场景&#xff1a; &#x1f6f0;️二、二叉树&#x1f6f0;️&#xff1a;…

acwing-Diango项目 (后半)

acwing-Django项目 文章目录acwing-Django项目前言5. 创建账号系统5.1用户名密码登录写登录界面写注册界面写动作 实现三个函数 register login logout5.2 Web端acapp一键登录在django中集成redis(准备工作)首先 pip install django_redis配置一下缓存启动redis-serverredis在d…

特征工程——文本特征

文本特征 expansion编码 consolidation编码 文本长度特征 标点符号特征 词汇属性特征 特殊词汇特征 词频特征 TF-IDF特征 LDA特征 下面的文章主要是梯度提升树模型展开的&#xff0c;抽取的特征主要为帮助梯度提升树模型挖掘其挖掘不到的信息&#xff0c;本文介绍的所…

NodeJS Web 框架 Express 之中间件

NodeJS Web 框架 Express 之中间件参考描述中间件next()一个简单的中间件函数使用全局中间件局部中间件共享注意事项位置next()分类错误级中间件内置中间件express.urlencoded()express.json()第三方中间件参考 项目描述哔哩哔哩黑马程序员搜索引擎Bing 描述 项目描述Edge109…

从0-1开始 测试ZLMediaKit推拉流性能、延时性能

流媒体开发系列文章 文章目录流媒体开发系列文章前言一、环境准备&#xff1f;二、拉流测试过程三、推流测试过程三、延时测试总结前言 目前、比较有名的流媒体服务器有ZLMediaKit、srs、live555、eadydarwin等。因为srs是单线程服务、对于多核服务器的支持需要通过部署多个服…

pytorch深度学习基础(十一)——常用结构化CNN模型构建

结构化CNN模型构建与测试前言GoogLeNet结构Inception块模型构建resNet18模型结构残差块模型构建denseNet模型结构DenseBlocktransition_block模型构建结尾前言 在本专栏的上一篇博客中我们介绍了常用的线性模型&#xff0c;在本文中我们将介绍GoogleNet、resNet、denseNet这类…

APT之木马静态免杀

前言 这篇文章主要是记录手动编写代码进行木马免杀&#xff0c;使用工具也可以免杀&#xff0c;只不过太脚本小子了&#xff0c;而且工具的特征也容易被杀软抓到&#xff0c;指不定哪天就用不了了&#xff0c;所以要学一下手动去免杀木马&#xff0c;也方便以后开发一个只属于…

blender导入骨骼动画方法[psa动作]

先导入女性的psk文件 然后调整缩放大小和人物一样,包括角度朝向. ctrla应用所有改变 然后选择psk文件以及其他人物模型的全部 ,然后 在Layout-物体-父级 -附带空顶相点组 image.png之后会发现所有人物多了修改器,点击其中一个修改器 点添加修改器 -数据传递 勾选顶点数据-选择顶…

人员动作行为AI分析系统 yolov5

人员动作行为AI分析系统通过pythonyolo系列网络学习模型&#xff0c;对现场画面人员行为进行实时分析监测&#xff0c;自动识别出人的各种异常行为动作&#xff0c;立即抓拍存档预警同步回传给后台。 我们使用YOLO算法进行对象检测。YOLO是一个聪明的卷积神经网络(CNN)&#xf…

带滤波器的PID控制仿真-1

采用低通滤波器可有效地滤掉噪声信号&#xff0c;在控制系统的设计中是一种常用的方法。基于低通滤波器的信号处理实例设低通滤波器为&#xff1a;采样时间为1ms&#xff0c;输入信号为带有高频正弦噪声&#xff08; 100Hz&#xff09;的低频&#xff08;0.2Hz)正弦信号。采用低…

离散数学与组合数学-05树

文章目录离散数学与组合数学-05树5.1 认识树5.1.1 树的模型5.1.2 树的应用5.2 无向树5.2.1 定义5.2.2 树的性质5.2.3 性质应用5.3 生成树5.3.1 引入5.3.2 定义5.3.3 算法5.3.4 应用5.4 最小生成树5.4.1 引入5.4.2 定义5.4.3 算法5.5 根树5.5.1 根数定义5.5.2 倒置法5.5.3 树的家…