【数据结构】基于顺序表实现通讯录

世界会向那些有目标和远见的人让路。💓💓💓

目录

•🌙说在前面

🍋基于顺序表的通讯录

• 🌰1.技术要点

• 🌰2.通讯录流程设计

🍋通讯录基本量设计

 • 🌰1.定义联系人的数据结构

 • 🌰2.定义通讯录顺序表

 • 🌰3.通讯录菜单与主函数设计

🍋实现通讯录的基本功能

• 🌰1.通讯录初始化

 • 🌰2.判断是否需要申请空间

 • 🌰3.通讯录添加联系人

 • 🌰4.指定联系人

 • 🌰5.通讯录删除联系人

 • 🌰6.通讯录修改联系人

 • 🌰7.展示联系人数据

 • 🌰8.通讯录查找联系人

 • 🌰9.通讯录的销毁

🍋main函数构建

 • 🌰1.main函数优化

 • 🌰2.Contacts.h

 • 🌰2.Contacts.c

 • 🌰2.test.c

• ✨SumUp结语


•🌙说在前面

亲爱的读者们大家好!💖💖💖,我们又见面了,在上一文章中我们学习了顺序表的相关知识,探讨了如何用C语言实现顺序表增、删、查、改的基本操作。我们这一篇文章需要再顺序表的基础上,利用它的功能来实现通讯录的一个小项目。

如果你没有准备好的话,或者说你还没有办法独立完成顺序表功能的代码,希望你先回去看看顺序表部分的内容,确认自己没有问题之后再来看这篇文章。

  博主主页传送门:愿天垂怜的博客

 

🍋基于顺序表的通讯录

• 🌰1.技术要点

所需知识:顺序表(动态内存管理、指针、结构体...)

基本功能要求:

🎉至少要能够存储100个人的通讯信息

🎉能够保存用户信息:名字、性别、年龄、电话、地址等

🎉删除指定联系人

🎉查找指定联系人

🎉修改指定联系人

🎉显示联系人的信息

• 🌰2.通讯录流程设计

在今后的任何项目,不论项目大小,动手写代码之前我们可以先做个设计流程图,然后按照这个流程写代码,这是个好习惯,可以使项目过程清晰明了,事半功倍。 

🍋通讯录基本量设计

这一部分内容我们放在头文件Contacts.h中。

 • 🌰1.定义联系人的数据结构

联系人信息至少应该包含:名字、性别、年龄、电话、地址等

#define NAME_MAX 20
#define GENDER_MAX 10//male female
#define TEL_MAX 11
#define ADDRESS_MAX 10

typedef struct Person
{
	char name[NAME_MAX];
	char gender[GENDER_MAX];
	int age;
	char tel[TEL_MAX];
	char address[ADDRESS_MAX];
}PersonInfo;

 • 🌰2.定义通讯录顺序表

基于顺序表实现通讯录,顺序表的元素类型SLDatatype就不再是int,而是包含每个联系人信息的结构体PersonInfo。 

typedef PersonInfo SLDataType;

//通讯录顺序表
typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}Contact;

 • 🌰3.通讯录菜单与主函数设计

我们的通讯录肯定是需要有一个菜单的,这样用户才能选择对通讯录执行什么样的操作,这个菜单必须包含所有通讯录功能,也包含退出。

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

至于每一个选项具体是怎么实现的,在我们整个流程的第二大块,我们先把基本量设计完成。

现在已经把通讯录已经通讯录的元素联系人都已经定义好了,menu函数也有了,现在我们可以在test.c的main函数中把基本的框架搭建起来:

	do
	{
        menu();
        printf("请输入你要执行的操作->\n");
        scanf("%d", &input);
    
		switch (input)
		{
		case 1:
			//增加联系人
			break;
		case 2:
			//删除联系人
			break;
		case 3:
			//修改联系人
			break;
		case 4:
			//查找联系人
			break;
		case 5:
			//展示联系人
			break;
        case 0:
	        printf("退出通讯录...\n");
	        Sleep(500);
			break;
        default:
	        printf("输入有误,请重新输入正确的操作:\a\n");
            Sleep(500);
            break;
		}
	} while (input);
	

其中退出的情况我们已经可以很好的写出来了,Sleep(500)可以让程序停个0.5s,\a可以让程序发出蜂鸣声

🍋实现通讯录的基本功能

这一部分内容我们放在文件Contacts.c中。 

• 🌰1.通讯录初始化

通讯录的初始化基本和顺序表无异。

//通讯录的初始化
void Contacts_Init(Contact* pcon)
{
	pcon->arr = NULL;
	pcon->size = pcon->capacity = 0;
}

 • 🌰2.判断是否需要申请空间

和顺序表一样,像我们刚初始化完的通讯录是没有申请到空间的,或者说空间已经用完了,这些情况都需要在堆上申请动态内存,所以依然需要这个函数

static void Contact_CheckCapacity(Contact* pcon)
{
	if (pcon->size == pcon->capacity)
	{
		int NewCapacity = pcon->capacity == 0 ? 4 : 2 * pcon->capacity;
		SLDataType* temp = (SLDataType*)realloc(pcon->arr, NewCapacity * sizeof(SLDataType));
		if (temp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		else
		{
			pcon->arr = temp;
			pcon->capacity = NewCapacity;
		}
	}
}

需要注意的是,这个函数的功能并不是通讯录需要实现的功能,只在别的函数中判断空间时使用,所以我们用static修饰,让它隐藏在Contacts.c中,并对其他文件不可见。

 • 🌰3.通讯录添加联系人

添加联系人需要先获取联系人的数据,并用PersonInfo类型的变量接收,接收后接着要让他作为通讯录的元素,我们可以用顺序表中的尾插SLPushBack。

void Contacts_ADD(Contact* pcon)
{
	assert(pcon);
	Contacts_CheckCapacity(pcon);
	//创建info变量接收联系人数据
	SLDataType info;
	printf("请输入要添加的联系人姓名:\n");
	scanf("%s", info.name);

	printf("请输入要添加的联系人性别:\n");
	scanf("%s", info.gender);

	printf("请输入要添加的联系人年龄:\n");
	scanf("%d", &info.age);

	printf("请输入要添加的联系人电话:\n");
	scanf("%s", info.tel);

	printf("请输入要添加的联系人住址:\n");
	scanf("%s", info.address);

	//让info尾插成为通讯录的一个元素
	pcon->arr[pcon->size++] = info;
}

 • 🌰4.指定联系人

如果我们想先写删除联系人和查找联系人的代码,我们会发现一个问题,就是我们删除的是我们想要删除的联系人,而这个联系人我们没有定位到。所以我们此时需要一个函数用来定位到我们希望删除或者修改的联系人

static int Find_ByName(Contact* pcon, char name[])
{
	for (int i = 0; i < pcon->size; i++)
	{
		if (!strcmp(pcon->arr[i].name, name))
			return i;
	}
	return -1;
}

用for循环遍历通讯录,利用名字定位,如果定位到需要操作的联系人姓名,则返回下标i进行后续操作,反之则为-1,表示没有该联系人。由于不是通讯录需要实现的功能,依然用static进行修饰。

 • 🌰5.通讯录删除联系人

通过Find_ByName定位到指定联系人后,我们就可以对联系人进行删除操作,对应顺序表中指定位置删除数据的函数SLErase。

void Contacts_DEL(Contact* pcon)
{
	assert(pcon);
	char name[NAME_MAX];
	printf("请输入要添加的联系人姓名:");
	scanf("%s", name);

	int find = Find_ByName(pcon, name);
	assert(find >= 0 && find < pcon->size);
	if (find < 0)
	{
		printf("要删除的联系人数据不存在\n");
		return 1;
	}
	else
	{
		//指定位置删除数据
		for (int i = find; i < pcon->size; i++)
		{
			pcon->arr[i] = pcon->arr[i + 1];
		}
		pcon->size--;
	}
}

 • 🌰6.通讯录修改联系人

修改联系人也需要定位到需要修改的对象,所以依然需要用到Find_ByName函数,用名字定位到了之后对其进行修改就可以了。

void Contacts_Modify(Contact* pcon)
{
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:");
	scanf("%s", name);

	int find = Find_ByName(pcon, name);
	if (find < 0)
	{
		printf("要修改的联系人数据不存在\n");
		return 1;
	}
	else
	{
		printf("请输入新的姓名:\n");
		scanf("%s", pcon->arr[find].name);

		printf("请输入新的性别:\n");
		scanf("%s", pcon->arr[find].gender);

		printf("请输入新的年龄:\n");
		scanf("%d", &pcon->arr[find].age);

		printf("请输入新的电话:\n");
		scanf("%s", pcon->arr[find].tel);

		printf("请输入新的地址:\n");
		scanf("%s", pcon->arr[find].address);

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

 • 🌰7.展示联系人数据

理一下我们的基本量,我们的通讯录就是顺序表,联系人就是顺序表的元素,而联系人是一个结构体类型的变量,所以展示联系人数据就以为着把顺序表中的元素全部打印出来就可以了

void Contacts_Show(Contact* pcon)
{
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (int i = 0; i < pcon->size; i++)
	{
		printf("%s  %s  %d  %s  %s\n", pcon->arr[i].name,
			pcon->arr[i].gender,
			pcon->arr[i].age,
			pcon->arr[i].tel,
			pcon->arr[i].address);
	}
}

 • 🌰8.通讯录查找联系人

想要查找联系人,也需要定位联系人的位置,如果定位到,我们打印出这个联系人的信息

void Contacts_Find(Contact* pcon)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名:");
	scanf("%s", name);

	int find = Find_ByName(pcon, name);
	if (find < 0)
	{
		printf("要修改的联系人数据不存在!\n");
	}
	else
	{
		printf("%s %s %d %s %s\n", pcon->arr[find].name,
			pcon->arr[find].gender,
			pcon->arr[find].age,
			pcon->arr[find].tel,
			pcon->arr[find].address);
	}
}

 • 🌰9.通讯录的销毁

通讯录的销毁和顺序表如出一辙,只需要类比顺序表的销毁就可以了

void Contacts_Destroy(Contact* pcon)
{
	if (pcon->arr)
	{
		free(pcon->arr);
	}
	pcon->arr = NULL;
	pcon->size = pcon->capacity = 0;
}

🍋main函数构建

 • 🌰1.main函数优化

在第二部分我们已经完成了实现通讯录的基本功能的函数,现在我们需要将他们构建在main函数中。由于功能函数较多,像我们之前那样的switch语句会显得比较冗长,我们可以用函数指针数组的方式优化我们再第一部分构建的基本框架:

int main()
{
	void(*pf[6])(Contact*) = { 0,Contacts_ADD, Contacts_DEL, Contacts_Modify ,Contacts_Find ,Contacts_Show };
	Contact con;
	Contacts_Init(&con);
	int input = 0;
	do
	{
		menu();
		printf("请输入你要执行的操作->\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:case 2:case 3:case 4:case 5:
			pf[input](&con);
			Sleep(500);
			break;
		case 0:
			printf("退出通讯录...\n");
			Sleep(500);
			break;
		default:
			printf("输入有误,请重新输入正确的操作:\a\n");
			Sleep(500);
			break;
		}

	} while (input);

	return 0;
}

 这样做switch语句就比较简洁了,这样我们的通讯录就基本上完成了,以下给出完整代码

 • 🌰2.Contacts.h

#pragma once

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

//定义联系人的数据结构

#define NAME_MAX 20
#define GENDER_MAX 10//male female
#define TEL_MAX 11
#define ADDRESS_MAX 10

typedef struct Person
{
	char name[NAME_MAX];
	char gender[GENDER_MAX];
	int age;
	char tel[TEL_MAX];
	char address[ADDRESS_MAX];
}PersonInfo;

typedef PersonInfo SLDataType;

//定义通讯录顺序表
typedef struct SeqList
{
	SLDataType* arr;
	int size;
	int capacity;
}Contact;

//通讯录的初始化
void Contacts_Init(Contact* pcon);

//通讯录的销毁
void Contacts_Destroy(Contact* pcon);

//通讯录添加数据
void Contacts_ADD(Contact* pcon);

//通讯录删除数据
void Contacts_DEL(Contact* pcon);

//通讯录的修改
void Contacts_Modify(Contact* pcon);

//通讯录查找
void Contacts_Find(Contact* pcon);

//展示通讯录数据
void Contacts_Show(Contact* pcon);

 • 🌰2.Contacts.c

#include "Contacts.h"

//通讯录的初始化
void Contacts_Init(Contact* pcon)
{
	pcon->arr = NULL;
	pcon->size = pcon->capacity = 0;
}

//判断是否需要申请空间
static void Contacts_CheckCapacity(Contact* pcon)
{
	if (pcon->size == pcon->capacity)
	{
		int NewCapacity = pcon->capacity == 0 ? 4 : 2 * pcon->capacity;
		SLDataType* temp = (SLDataType*)realloc(pcon->arr, NewCapacity * sizeof(SLDataType));
		if (temp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		else
		{
			pcon->arr = temp;
			pcon->capacity = NewCapacity;
		}
	}
}

//通讯录添加数据
void Contacts_ADD(Contact* pcon)
{
	assert(pcon);
	Contacts_CheckCapacity(pcon);
	//创建info变量接收联系人数据
	SLDataType info;
	printf("请输入要添加的联系人姓名:\n");
	scanf("%s", info.name);

	printf("请输入要添加的联系人性别:\n");
	scanf("%s", info.gender);

	printf("请输入要添加的联系人年龄:\n");
	scanf("%d", &info.age);

	printf("请输入要添加的联系人电话:\n");
	scanf("%s", info.tel);

	printf("请输入要添加的联系人住址:\n");
	scanf("%s", info.address);

	//让info尾插成为通讯录的一个元素
	pcon->arr[pcon->size++] = info;
}

//指定联系人
static int Find_ByName(Contact* pcon, char name[])
{
	for (int i = 0; i < pcon->size; i++)
	{
		if (!strcmp(pcon->arr[i].name, name))
			return i;
	}
	return -1;
}

//通讯录删除数据
void Contacts_DEL(Contact* pcon)
{
	assert(pcon);
	char name[NAME_MAX];
	printf("请输入要添加的联系人姓名:");
	scanf("%s", name);

	int find = Find_ByName(pcon, name);
	assert(find >= 0 && find < pcon->size);
	if (find < 0)
	{
		printf("要删除的联系人数据不存在\n");
		return 1;
	}
	else
	{
		//指定位置删除数据
		for (int i = find; i < pcon->size; i++)
		{
			pcon->arr[i] = pcon->arr[i + 1];
		}
		pcon->size--;
	}
}

//通讯录的修改
void Contacts_Modify(Contact* pcon)
{
	char name[NAME_MAX];
	printf("请输入要修改的联系人姓名:");
	scanf("%s", name);

	int find = Find_ByName(pcon, name);
	if (find < 0)
	{
		printf("要修改的联系人数据不存在\n");
		return 1;
	}
	else
	{
		printf("请输入新的姓名:\n");
		scanf("%s", pcon->arr[find].name);

		printf("请输入新的性别:\n");
		scanf("%s", pcon->arr[find].gender);

		printf("请输入新的年龄:\n");
		scanf("%d", &pcon->arr[find].age);

		printf("请输入新的电话:\n");
		scanf("%s", pcon->arr[find].tel);

		printf("请输入新的地址:\n");
		scanf("%s", pcon->arr[find].address);

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

//展示通讯录数据
void Contacts_Show(Contact* pcon)
{
	printf("%s %s %s %s %s\n", "姓名", "性别", "年龄", "电话", "地址");
	for (int i = 0; i < pcon->size; i++)
	{
		printf("%s  %s  %d  %s  %s\n", pcon->arr[i].name,
			pcon->arr[i].gender,
			pcon->arr[i].age,
			pcon->arr[i].tel,
			pcon->arr[i].address);
	}
}

void Contacts_Find(Contact* pcon)
{
	char name[NAME_MAX];
	printf("请输入要查找的联系人姓名:");
	scanf("%s", name);

	int find = Find_ByName(pcon, name);
	if (find < 0)
	{
		printf("要修改的联系人数据不存在!\n");
	}
	else
	{
		printf("%s %s %d %s %s\n", pcon->arr[find].name,
			pcon->arr[find].gender,
			pcon->arr[find].age,
			pcon->arr[find].tel,
			pcon->arr[find].address);
	}
}

//通讯录的销毁
void Contacts_Destroy(Contact* pcon)
{
	if (pcon->arr)
	{
		free(pcon->arr);
	}
	pcon->arr = NULL;
	pcon->size = pcon->capacity = 0;
}

 • 🌰2.test.c

#include "Contacts.h"

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

int main()
{
	void(*pf[6])(Contact*) = { 0,Contacts_ADD, Contacts_DEL, Contacts_Modify ,Contacts_Find ,Contacts_Show };
	Contact con;
	Contacts_Init(&con);
	int input = 0;
	do
	{
		menu();
		printf("请输入你要执行的操作->\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:case 2:case 3:case 4:case 5:
			pf[input](&con);
			Sleep(500);
			break;
		case 0:
			printf("退出通讯录...\n");
			Sleep(500);
			break;
		default:
			printf("输入有误,请重新输入正确的操作:\a\n");
			Sleep(500);
			break;
		}

	} while (input);

	return 0;
}

• ✨SumUp结语

通讯录的项目需要大家深刻理解并掌握顺序表的基本知识,在此基础上实现对顺序表的应用,大家也可以自己试试看着头文件实现其中各种的功能

如果大家觉得有帮助,麻烦大家点点赞,如果有错误的地方也欢迎大家指出~

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

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

相关文章

PLM系统推荐:产品全生命周期管理最佳解决方案

PLM系统推荐&#xff1a;产品全生命周期管理最佳解决方案 在当今日益竞争激烈的市场环境中&#xff0c;企业如何高效管理其产品设计、开发和生命周期变得尤为重要。产品生命周期管理&#xff08;PLM&#xff09;系统正是为解决这一难题而诞生的。本文将为您详细介绍几款值得推荐…

HTTP免费升级到HTTPS攻略

HTTPS就是在HTTP的基础上加入了SSL&#xff0c;将一个使用HTTP的网站免费升级到HTTPS的关键就是申请一个免费的SSL证书 具体步骤如下 1 获取免费SSL证书 国内的JoySSL 提供不限量免费的SSL/TLS证书。根据自己的需求选择证书类型&#xff08;登录JoySSL官网&#xff0c;创建账号…

5.10开幕!虚拟动力多项数字人互动技术参展元宇宙生态博览会!

2024年5月10-12日&#xff0c;由广东鸿威国际会展集团有限公司、广州市虚拟现实行业协会主办的2024数字显示与元宇宙生态博览会将正式开幕。 亮点抢先看 虚拟动力 广州虚拟动力作为3D虚拟人全生态应用的产品技术开发与服务商&#xff0c;将携带无穿戴动捕技术、数字人穿戴式动…

【C++】Visual Studio 2019 给 C++ 文件添加头部注释说明

使用代码片段管理器&#xff0c;添加快捷插入代码文件说明 1. 效果 2. header.snippet 新建 header.snippet 文件&#xff0c;存放到某个文件夹 内容&#xff0c;自行更新 快捷名称&#xff0c;修改 Header 里面内容注释内容&#xff0c;修改 Code 里面内容 <?xml ver…

Linux中每当执行‘mount’命令(或其他命令)时,自动激活执行脚本:输入密码,才可以执行mount

要实现这个功能&#xff0c;可以通过创建一个自定义的mount命令的包装器&#xff08;wrapper&#xff09;来完成。这个包装器脚本会首先提示用户输入密码&#xff0c;如果密码正确&#xff0c;则执行实际的mount命令。以下是创建这样一个包装器的步骤&#xff1a; 创建一个名为…

Vue从入门到实战Day01

一、Vue快速上手 1. vue概念 概念&#xff1a;Vue是一个用于 构建用户界面的 渐进式 框架 构建用户界面&#xff1a;基于数据动态渲染页面渐进式&#xff1a;循序渐进的学习框架&#xff1a;一套完整的项目解决方案&#xff0c;提升开发效率 优点&#xff1a;大大提升开发效…

Garden Planner for Mac v3.8.62注册激活版:园林绿化设计软件

Garden Planner for Mac是一款专为苹果Mac OS平台设计的园林景观设计软件。这款软件的主要功能是帮助用户设计梦想中的花园&#xff0c;包括安排植物、树木、建筑物和其他物体。 Garden Planner for Mac提供了一个包含1200多种植物和物体符号的库&#xff0c;这些符号都可以进行…

torch教程

一 基本用法 1 torch.autograd.Function PyTorch 74.自定义操作torch.autograd.Function - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/344802526 虽然pytorch可以自动求导,但是有时候一些操作是不可导的,这时候你需要自定义求导方式。也就是所谓的 "Extending t…

图纸管理的高效策略与最佳实践

图纸管理的高效策略与最佳实践 在工程设计、产品研发和建筑行业中&#xff0c;图纸管理是一项至关重要的任务。随着项目规模的扩大和复杂性的增加&#xff0c;如何高效、有序地管理图纸已成为企业和团队关注的焦点。本文将为您介绍图纸管理的高效策略与最佳实践&#xff0c;帮助…

【iOS逆向与安全】网上gw如何自动登录与签到SM2,SM3,SM4算法加解密

1.下载 app 2.frida 调试 3.抓包查看接口 4.分析加密数据 5.易语言编写代码 1 .开始下载 下载好发现有越狱检测&#xff0c;检测点为&#xff1a; -[AppDelegate isJailBreak]; 于是编写插件xm代码 : %hook AppDelegate- (void)isJailBreak{NSLog("AppDelegate is…

【JavaEE初阶系列】——Servlet运行原理以及Servlet API详解

目录 &#x1f6a9;Servlet运行原理 &#x1f6a9;Servlet API 详解 &#x1f393;HttpServlet核心方法 &#x1f393;HttpServletRequest核心方法 &#x1f388;核心方法的使用 &#x1f534;获取请求中的参数 &#x1f4bb;query string &#x1f4bb;直接通过form表…

免费思维13招之二:第三方思维

思维02:第三方思维 第三方思维又叫第三方资费思维。是一种可以使你的产品免费但是你却依然赚钱的思维。 大家还记得之前讲的“餐厅免费吃饭却年赚百万”的案例吗?这个案例运用了多种免费思维的子思维,其中也用到了第三方资费思维,怎么运用的呢?韩女士,与各行各业合作,…

电脑上如何设置闹钟提醒 电脑闹钟提醒设置方法

在这个信息爆炸的时代&#xff0c;我们每个人每天都面临着无数的任务和约定。繁杂的工作与生活&#xff0c;让我时常感到应接不暇&#xff0c;一不小心就会遗漏某些重要事务&#xff0c;这给我带来不小的困扰。我相信&#xff0c;很多人都有过这样的经历&#xff0c;面对一堆待…

Jmeter性能测试(四)

一、遇到问题解决思路 1、检查请求头是否正确 2、检查请求参数是否正确 3、检查鉴权信息是否正确 4、检查变量作用域 5、检查数据提取是否正确(正则/json提取器) 二、请求头检查 1、在Http信息头管理器查看 2、注意这里的变量作用域是全局的 三、请求参数检查 1、在查看结…

演唱会新风:允许部分歌手闭麦,让观众先唱

演唱会市场的热度从2023年延续至今&#xff0c;出现了一些“倒反天罡”的现象。 例如&#xff1a;让歌迷在台下给歌手唱歌。 5月6日抖音娱乐榜第一的消息是“第一次见辟谣观众没假唱的”。原因是凤凰传奇在常州和北京鸟巢先后举办两场演唱会&#xff0c;其中鸟巢演唱会被认为…

2024年开抖音小店需要多少钱?你真的知道吗?最新入驻条件及费用

大家好&#xff0c;我是电商花花。 现在仍然有很多想开抖店&#xff0c;想做抖音小店&#xff0c;但是很多人都不知道投资一家抖音小店需要多少钱&#xff0c;今天花花就给大家讲一下做一家抖音小店需要投入多少资金&#xff0c;以及具体投入到哪些方面。 我们就说一下个体店…

信息安全-古典密码学简介

目录 C. D. Shannon: 一、置换密码 二、单表代替密码 ① 加法密码 ② 乘法密码 ③密钥词组代替密码 三、多表代替密码 代数密码 四、古典密码的穷举分析 1、单表代替密码分析 五、古典密码的统计分析 1、密钥词组单表代替密码的统计分析 2、英语的统计规…

2024年数维杯数学建模A题思路

文章目录 1 赛题思路2 比赛日期和时间3 竞赛信息4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

无人机+垂直起降:微型共轴双旋翼无人机技术详解

微型共轴双旋翼无人机技术是一种独特的无人机设计&#xff0c;它结合了垂直起降&#xff08;VTOL&#xff09;能力和微型无人机的灵活性。这种设计允许无人机在无需跑道的情况下垂直起降&#xff0c;并具备在空中悬停和执行各种飞行动作的能力。 适用于集群控制&#xff0c;荷载…

vitis 2020.1 Up date XSA文件后,编译不通过

原来是可以编译通过的&#xff0c;升级XSA文件后&#xff0c;出现各种问题&#xff0c;pmufw没法编译通过 xpfw_config.h:14:10: fatal error: xparameters.h: No such file or directory Vitis 2020.2 - fatal error: xparameters.h: No such file or directory (xilinx.com)…