C语言 - 通讯录详解

news2025/1/16 3:49:18

通讯录

文章目录

  • 1. 基本思路
  • 2.代码实现
    • 2.1 定义各种**宏**和**结构体**。
    • 2.2 创建结构体并进行初始化
    • 2.3 打印菜单,模拟用户的选择
    • 2.4 增加联系人
    • 2.5 删除联系人
    • 2.6 查找联系人
    • 2.7 修改联系人
    • 2.8 对通讯录进行升序排序
    • 2.9 打印通讯录
    • 2.10 结束程序并销毁通讯录
  • 3. 文件改进版本
    • 3.1 每次关闭通讯录将信息保存到文件中
    • 3.2 每次初始化通讯录后将文件中信息加载到通讯录上
  • 4.程序整体代码

1. 基本思路

  1. 用宏定义经常出现的变量,如数组的大小,通讯录的初识容量等。
  2. 定义两个结构体,用一个结构体记录某一个联系人的所有信息,另外一个结构体记录所有的联系人,当前通讯录的大小以及通讯录能存多少人。
  3. 通讯录的功能有增删差改,排序,以及打印。
  4. 文章中文字解释较少,主要解释都在代码中。

2.代码实现

2.1 定义各种结构体

在这里插入图片描述


// 用宏替换后续经常出现的数字,便于程序的维护
#define NAME_MAX 20  // 名字的字符串的最大长度
#define SEX_MAX 20   // 性别的字符串的最大长度
#define TELE_MAX 20  // 电话的最大字符串的长度
#define ADDR_MAX 20  // 住址的最大字符串的长度

#define CON_INIT 3 // 通讯录的初识大小

// 定义每个人的信息为一个结构体,同时为了方便表示,采用typedef
typedef struct PeoInfo
{
	char name[NAME_MAX]; // 每个人的姓名
	char sex[SEX_MAX];   // 每个人的性别
	int age;             // 每个人的年龄
	char tele[TELE_MAX]; // 每个人的电话
	char addr[ADDR_MAX]; // 每个人的住址
}PeoInfo;


// 定义整个通讯录为一个结构体,同时为了方便表示,采用typedef
typedef struct Contact
{
	// 为了节省空间,采用动态内存分配的方法来获取整个通讯录的空间
	PeoInfo* data; // 结构体指针,可通过运算访问到所有人的信息
	int size; // 表示当前通讯录存了多少人的信息
	int capacity; // 表示该通讯录总共可以存多少人的信息
}Contact;

2.2 创建结构体并进行初始化

在这里插入图片描述

// 定义一个通讯录结构体
	Contact con;
	// 对该通讯录结构体进行初始化
	// 此后应该传结构体的地址而不是结构体,原因是要对结构体作出修改
	// 并且传结构体的地址节省空间且效率更高
	InitContact(&con); 

在这里插入图片描述


// 在这个函数内部对通讯录结构体进行初始化
void InitContact(Contact* pc)
{
	// 此时通讯录是空的,应先为通讯录分配空间
	pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * CON_INIT);

	// 如果分配成功,将通讯录的size设为0,capacity设为初识大小
	pc->size = 0;
	pc->capacity = CON_INIT;
}

2.3 打印菜单,模拟用户的选择

菜单如下:
在这里插入图片描述


void menu()
{
	printf("请输入你的选择\n");
	printf("***** 1. add     2. del    *****\n");
	printf("***** 3. search  4. modify *****\n");
	printf("***** 5. sort    6. print  *****\n");
	printf("*****        0. exit       *****\n");

	return;
}

用户的选择功能如下
在这里插入图片描述

// 定义input,用户输入input进行选择
	int input;
	do
	{
		menu(); // 打印菜单,提示用户进行选择
		scanf("%d", &input); // 用户输入input进行选择
		switch (input) // 用户选择后进入不同的功能
		{
		case ADD: // 增加联系人
			AddContact(&con);
			break;
		case DEL: // 删除联系人
			DeleteContact(&con);
			break;
		case SEARCH: // 查找联系人
			SearchContact(&con);
			break;
		case MODIFY: // 改变联系人
			ModifyContact(&con);
			break;
		case SORT:  // 对联系人进行排序
			SortContact(&con);
			break;
		case PRINT: // 打印所有联系人的信息
			PrintContact(&con);
			break;
		case EXIT: // 退出程序并销毁
			DestroyContact(&con);
			break;
		}
	} while (input);

用枚举常量来表示各种选项
在这里插入图片描述

2.4 增加联系人

在每次增加联系人前,都要进行检查是否需要扩容的操作,若需要则进行扩容

在这里插入图片描述

void AddContact(Contact* pc)
{
	// 判断通讯录是否已满,若满,进行扩容
	if (pc->size == pc->capacity)
	{
		PeoInfo* tmp = (PeoInfo*)realloc(pc, sizeof(PeoInfo) * 2);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			return;
		}
		pc->data = tmp;

		// 若扩容成功,增大capacity
		pc->capacity *= 2;
	}

	// 输入要添加的联系人的信息
	// 这里pc->data为结构体数组,pc->data[pc->size]为其中的元素,也就是某一个联系人的信息
	printf("请输入名字\n");
	scanf("%s", pc->data[pc->size].name);
	printf("请输入性别\n");
	scanf("%s", pc->data[pc->size].sex);
	printf("请输入年龄\n");
	scanf("%d", &pc->data[pc->size].age);
	printf("请输入电话\n");
	scanf("%s", pc->data[pc->size].tele);
	printf("请输入住址\n");
	scanf("%s", pc->data[pc->size].addr);

	pc->size++; // 将存入的联系人的数量加1

	// 添加成功后,向用户展示新的通讯录
	PrintContact(pc);
}

2.5 删除联系人

在这里插入图片描述


void DeleteContact(Contact* pc)
{
	printf("请输入要删除的联系人的名字\n");
	char name[20];
	scanf("%s", name);
	// 定义一个新函数find,用来查找是否有这个联系人
	// 如果有,返回联系人的下标,如果没有,返回-1
	int ret = find(pc, name);

	if (ret == -1)
	{
		printf("没有找到该联系人\n");
	}
	else
	{
		for (int i = ret; i < pc->size - 1; i++)
		{
			pc->data[i] = pc->data[i + 1];
		}
		pc->size--;
	}

	return;
}

这里还要定义一个find函数来找该联系人,如果找到返回该联系人的下标,如果找不到则返回-1。

在这里插入图片描述


int find(Contact* pc, char* name)
{
	for (int i = 0; i < pc->size; i++)
	{
		if (strcmp(name, pc->data[i].name) == 0)
		{
			return i;
		}
	}
	return -1;
}

2.6 查找联系人

查找时利用find函数来查找
在这里插入图片描述


void SearchContact(Contact* pc)
{
	printf("请输入要查找的联系人的名字\n");
	char name[20];
	scanf("%s", name);
	// 利用已经定义的find函数进行查找
	int ret = find(pc, name);

	if (ret == -1)
	{
		printf("没有找到该联系人\n");
	}
	else
	{
		// 如果找到,打印该联系人的信息,首先打印五个标题
		printf("%-10s\t%-10s\t%-5s\t%-15s\t%-10s\n", "姓名", "性别", "年龄", "电话", "住址");
		printf("%-10s\t%-10s\t%-5d\t%-15s\t%-10s\n",
			pc->data[ret].name,
			pc->data[ret].sex,
			pc->data[ret].age,
			pc->data[ret].tele,
			pc->data[ret].addr);
	}

	return;
}

2.7 修改联系人

在这里插入图片描述


void ModifyContact(Contact* pc)
{
	printf("请输入要修改的联系人的名字\n");
	char name[20];
	scanf("%s", name);
	// 利用find函数进行查找
	int ret = find(pc, name);
	if (ret == -1)
	{
		printf("没有找到该联系人\n");
	}
	else
	{
		printf("请输入名字\n");
		scanf("%s", pc->data[ret].name);
		printf("请输入性别\n");
		scanf("%s", pc->data[ret].sex);
		printf("请输入年龄\n");
		scanf("%d", &pc->data[ret].age);
		printf("请输入电话\n");
		scanf("%s", pc->data[ret].tele);
		printf("请输入住址\n");
		scanf("%s", pc->data[ret].addr);
	}

	return;
}

2.8 对通讯录进行升序排序

在这里插入图片描述

void SortContact(Contact* pc)
{
	// 这里采用升序排列
	// 且采用冒泡排序的方式进行排列
	for (int i = 0; i < pc->size; i++)
	{
		for (int j = 0; j < pc->size - 1 - i; i++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				char tmp[20];
				strcpy(tmp, pc->data[j].name);
				strcpy(pc->data[j].name, pc->data[j + 1].name);
				strcpy(pc->data[j + 1].name, tmp);
			}
		}
	}

	printf("排序成功\n");
}

2.9 打印通讯录

在这里插入图片描述


// 在这个函数内打印所有联系人的信息
void PrintContact(Contact* pc)
{
	// 首先打印五个标题
	printf("%-10s\t%-10s\t%-5s\t%-15s\t%-10s\n", "姓名", "性别", "年龄", "电话", "住址");
	// 然后用for循环打印所有联系人的信息
	for (int i = 0; i < pc->size; i++)
	{
		printf("%-10s\t%-10s\t%-5d\t%-15s\t%-10s\n",
			pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].age,
			pc->data[i].tele,
			pc->data[i].addr
		);
	}
}

2.10 结束程序并销毁通讯录

在这里插入图片描述

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

3. 文件改进版本

利用文件实现
当通讯录退出的时候,把信息写到文件。
当通讯录初始化后,加载文件的信息到通讯录中。

3.1 每次关闭通讯录将信息保存到文件中

在每次销毁通讯录之前将通讯录的信息保存到文件中
在这里插入图片描述
在这里插入图片描述

3.2 每次初始化通讯录后将文件中信息加载到通讯录上

在这里插入图片描述
在这里插入图片描述
CheckCapacity函数中的内容直接拷贝AddContact函数中的数组扩容即可
在这里插入图片描述

4.程序整体代码

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

// 用宏替换后续经常出现的数字,便于程序的维护
#define NAME_MAX 20  // 名字的字符串的最大长度
#define SEX_MAX 20   // 性别的字符串的最大长度
#define TELE_MAX 20  // 电话的最大字符串的长度
#define ADDR_MAX 20  // 住址的最大字符串的长度

#define CON_INIT 3 // 通讯录的初识大小

// 定义每个人的信息为一个结构体,同时为了方便表示,采用typedef
typedef struct PeoInfo
{
	char name[NAME_MAX]; // 每个人的姓名
	char sex[SEX_MAX];   // 每个人的性别
	int age;             // 每个人的年龄
	char tele[TELE_MAX]; // 每个人的电话
	char addr[ADDR_MAX]; // 每个人的住址
}PeoInfo;


// 定义整个通讯录为一个结构体,同时为了方便表示,采用typedef
typedef struct Contact
{
	// 为了节省空间,采用动态内存分配的方法来获取整个通讯录的空间
	PeoInfo* data; // 结构体指针,可通过运算访问到所有人的信息
	int size; // 表示当前通讯录存了多少人的信息
	int capacity; // 表示该通讯录总共可以存多少人的信息
}Contact;

// 使用枚举常量来表示用户的各种选择
enum Option
{
	EXIT,
	ADD,
	DEL,
	SEARCH,
	MODIFY,
	SORT,
	PRINT
};


void SaveContact(Contact* pc)
{
	// 以读的形式打开文件
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}

	// 将通讯录以二进制的形式保存到文件中
	// 由于联系人的信息有很多,所以这里可以采用for循环
	for (int i = 0; i < pc->size; i++)
	{
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}

	// 关闭文件
	fclose(pf);
	pf = NULL;
}

CheckCapacity(Contact* pc)
{
	// 判断通讯录是否已满,若满,进行扩容
	if (pc->size == pc->capacity)
	{
		PeoInfo* tmp = (PeoInfo*)realloc(pc, sizeof(PeoInfo) * 2);
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			return;
		}
		pc->data = tmp;

		// 若扩容成功,增大capacity
		pc->capacity *= 2;
	}
}

void LoadContact(Contact* pc)
{
	// 以读的形式打开文件
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return;
	}

	// 将文件中的内容加载到通讯录中
	// 这里用fread函数,当fread函数读取的联系人信息数为0时,说明读取结束
	PeoInfo tmp = { 0 }; // 定义一个联系人信息的结构体,便于读取
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	{
		CheckCapacity(pc); // 在这个函数中查看数组是否需要扩容,若需要,则扩容
		pc->data[pc->size] = tmp;
		pc->size++;
	}

	// 关闭文件
	fclose(pf);
	pf = NULL;
	return;
}

// 在这个函数内部对通讯录结构体进行初始化
void InitContact(Contact* pc)
{
	// 此时通讯录是空的,应先为通讯录分配空间
	pc->data = (PeoInfo*)malloc(sizeof(PeoInfo) * CON_INIT);

	// 如果分配成功,将通讯录的size设为0,capacity设为初识大小
	pc->size = 0;
	pc->capacity = CON_INIT;

	LoadContact(pc);

	return;
}

void menu()
{
	printf("请输入你的选择\n");
	printf("***** 1. add     2. del    *****\n");
	printf("***** 3. search  4. modify *****\n");
	printf("***** 5. sort    6. print  *****\n");
	printf("*****        0. exit       *****\n");

	return;
}

// 在这个函数内打印所有联系人的信息
void PrintContact(Contact* pc)
{
	// 首先打印五个标题
	printf("%-10s\t%-10s\t%-5s\t%-15s\t%-10s\n", "姓名", "性别", "年龄", "电话", "住址");
	// 然后用for循环打印所有联系人的信息
	for (int i = 0; i < pc->size; i++)
	{
		printf("%-10s\t%-10s\t%-5d\t%-15s\t%-10s\n",
			pc->data[i].name,
			pc->data[i].sex,
			pc->data[i].age,
			pc->data[i].tele,
			pc->data[i].addr
		);
	}
}

void AddContact(Contact* pc)
{
	CheckCapacity(pc);

	// 输入要添加的联系人的信息
	// 这里pc->data为结构体数组,pc->data[pc->size]为其中的元素,也就是某一个联系人的信息
	printf("请输入名字\n");
	scanf("%s", pc->data[pc->size].name);
	printf("请输入性别\n");
	scanf("%s", pc->data[pc->size].sex);
	printf("请输入年龄\n");
	scanf("%d", &pc->data[pc->size].age);
	printf("请输入电话\n");
	scanf("%s", pc->data[pc->size].tele);
	printf("请输入住址\n");
	scanf("%s", pc->data[pc->size].addr);

	pc->size++; // 将存入的联系人的数量加1

	// 添加成功后,向用户展示新的通讯录
	PrintContact(pc);
}

int find(Contact* pc, char* name)
{
	for (int i = 0; i < pc->size; i++)
	{
		if (strcmp(name, pc->data[i].name) == 0)
		{
			return i;
		}
	}
	return -1;
}

void DeleteContact(Contact* pc)
{
	printf("请输入要删除的联系人的名字\n");
	char name[20];
	scanf("%s", name);
	// 定义一个新函数find,用来查找是否有这个联系人
	// 如果有,返回联系人的下标,如果没有,返回-1
	int ret = find(pc, name);

	if (ret == -1)
	{
		printf("没有找到该联系人\n");
	}
	else
	{
		for (int i = ret; i < pc->size - 1; i++)
		{
			pc->data[i] = pc->data[i + 1];
		}
		pc->size--;
	}

	return;
}

void SearchContact(Contact* pc)
{
	printf("请输入要查找的联系人的名字\n");
	char name[20];
	scanf("%s", name);
	// 利用已经定义的find函数进行查找
	int ret = find(pc, name);

	if (ret == -1)
	{
		printf("没有找到该联系人\n");
	}
	else
	{
		// 如果找到,打印该联系人的信息,首先打印五个标题
		printf("%-10s\t%-10s\t%-5s\t%-15s\t%-10s\n", "姓名", "性别", "年龄", "电话", "住址");
		printf("%-10s\t%-10s\t%-5d\t%-15s\t%-10s\n",
			pc->data[ret].name,
			pc->data[ret].sex,
			pc->data[ret].age,
			pc->data[ret].tele,
			pc->data[ret].addr);
	}

	return;
}

void ModifyContact(Contact* pc)
{
	printf("请输入要修改的联系人的名字\n");
	char name[20];
	scanf("%s", name);
	// 利用find函数进行查找
	int ret = find(pc, name);
	if (ret == -1)
	{
		printf("没有找到该联系人\n");
	}
	else
	{
		printf("请输入名字\n");
		scanf("%s", pc->data[ret].name);
		printf("请输入性别\n");
		scanf("%s", pc->data[ret].sex);
		printf("请输入年龄\n");
		scanf("%d", &pc->data[ret].age);
		printf("请输入电话\n");
		scanf("%s", pc->data[ret].tele);
		printf("请输入住址\n");
		scanf("%s", pc->data[ret].addr);
	}

	return;
}

void SortContact(Contact* pc)
{
	// 这里采用升序排列
	// 且采用冒泡排序的方式进行排列
	for (int i = 0; i < pc->size; i++)
	{
		for (int j = 0; j < pc->size - 1 - i; i++)
		{
			if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0)
			{
				char tmp[20];
				strcpy(tmp, pc->data[j].name);
				strcpy(pc->data[j].name, pc->data[j + 1].name);
				strcpy(pc->data[j + 1].name, tmp);
			}
		}
	}

	printf("排序成功\n");
}

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

int main()
{
	// 定义一个通讯录结构体
	Contact con;
	// 对该通讯录结构体进行初始化
	// 此后应该传结构体的地址而不是结构体,原因是要对结构体作出修改
	// 并且传结构体的地址节省空间且效率更高
	InitContact(&con); 

	// 定义input,用户输入input进行选择
	int input;
	do
	{
		menu(); // 打印菜单,提示用户进行选择
		scanf("%d", &input); // 用户输入input进行选择
		switch (input) // 用户选择后进入不同的功能
		{
		case ADD: // 增加联系人
			AddContact(&con);
			break;
		case DEL: // 删除联系人
			DeleteContact(&con);
			break;
		case SEARCH: // 查找联系人
			SearchContact(&con);
			break;
		case MODIFY: // 改变联系人
			ModifyContact(&con);
			break;
		case SORT:  // 对联系人进行排序
			SortContact(&con);
			break;
		case PRINT: // 打印所有联系人的信息
			PrintContact(&con);
			break;
		case EXIT: // 退出程序并销毁
			//在销毁之前将通讯录内的信息保存到文件中
			SaveContact(&con);
			DestroyContact(&con);
			break;
		}
	} while (input);

	return 0;
}


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

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

相关文章

再度入榜 | 中睿天下入选《中国网络安全企业100强》

近日&#xff0c;国内权威网络安全媒体、第三方安全咨询机构安全牛发布第十版《中国网络安全企业100强》&#xff08;以下简称“百强”&#xff09;&#xff0c;中睿天下以强大的综合发展实力和强劲的发展势头再次荣登百强榜单。 安全牛作为国内网络安全行业权威媒体&#xff0…

能解决你80%关于存储的疑惑

概述 在计算机系统中&#xff0c;常用的存储介质包括寄存器、内存、SSD、磁盘等&#xff0c;寄存器的速写速度与CPU相同&#xff0c;一个时钟周期是0.3纳秒&#xff0c;而内存访问需要120纳秒&#xff0c;寄存器的读写速度比内存要快几百倍&#xff0c;固态硬盘访问需要50&…

Vue3基础(26)___defineProps、defineEmits、defineExpose组件通信

defineProps、defineEmits、defineExpose组件通信 在使用这个之前&#xff0c;我们需要知道setup的语法糖写法&#xff0c;因为上面的三个api需要在这个语法糖中才能使用&#xff1a; <script setup>console.log(LiuQing) </script>里面的代码会被编译成组件 set…

m分别通过GA遗传优化算法对企业不同产品订单生产进行时间优化

目录 1.算法概述 2.仿真效果预览 3.核心MATLAB代码预览 4.完整MATLAB程序 1.算法概述 首先介绍MATLAB部分的遗传算法的优化算法介绍&#xff1a; 遗传算法的原理 遗传算法GA把问题的解表示成“染色体”&#xff0c;在算法中也即是以二进制编码的串。并且&#xff0c;在执行…

WhatsApp营销引流-SendWS拓客系统功能后台介绍(五):WhatsApp素材管理

WhatsApp营销引流 很多新创的品牌想在海外推广自家产品&#xff0c;由于自己的品牌影响力不及其他老牌大牌&#xff0c;想在海外打开名气首先可以选择利用WhatsApp来进行营销引流&#xff0c;这是最简单最直接的方法&#xff0c;只需要低成本即可实现高回报。 据统计WhatsApp…

Python面向对象

目录 1.初识对象 2. 类的成员方法 3. 类和对象 4. 构造方法 5. 其它内置方法 6. 封装 7. 继承 7.1 继承的基础语法 7.2 复写和调用父类成员 8. 多态 1.初识对象 1. 生活中或是程序中&#xff0c;我们都可以使用设计表格、生产表格、填写表格的形式组织数据。 2. 进…

【2011】408联考操作系统真题整理

2011年 23 题目 满足短作业优先且不会发生饥饿现象的调度算法&#xff1a;高响应比优先 解析 24 题目 用户态执行的是命令解释程序 解析 法一&#xff1a;正向选择 DOS对应联机命令接口 法二&#xff1a;逆向排除 非用户态 -> 内核态 25 题目 在支持多线程的…

vs2019搭建与配置Qt,并实现影像显示

vs2019搭建与配置Qt&#xff0c;并实现影像显示 1.关于qt在vs2019的配置 主要参考了这个博客 其中有一个我在配置过程中出现的问题&#xff0c;在此记录一下 Qt Visual Studio Tools 在vs2019一直无法加载&#xff0c;一直在initializing,且提示"未能正确加载qtvstools…

数据库的基本操作(4)

先总结一下上一章的内容。 1.修改 update 表名 set 列名 值... where 条件&#xff1b; 2.删除 delete from 表名 where 条件&#xff1b; 3.mysql的约束 约束&#xff1a;数据库对数据本身有一些要求和限制。 NOT NULL 数据不能为空。 UNIQUE 数据唯一&#xff08;针…

【目标检测】目标检测的评价指标(七个)

目录&#xff1a;目标检测的评价指标一、正样本与负样本二、真正(TP)、假正(FP)、真负(TN)、假负(FN)&#xff08;1&#xff09;正确的正向预测&#xff08;True Positive&#xff0c;TP&#xff09;&#xff1a;正样本被正确检测的数量&#xff08;2&#xff09;错误的正向预测…

国际海运详解:国际海运的发货方式有哪些?区别是什么?

在跨境物流运输中&#xff0c;海运是一个种常用的运输方式&#xff0c;下面来重点介绍国际海运的几种发货方式和区别&#xff1a; 一、电放提单 是电报放货的缩写。提单信息以电子报纸或电子信息的形式发送给目的港船公司&#xff0c;收货人可以更换加盖电子印章的提单和电子保…

LeetCode-775-全局倒置与局部倒置

1、数学方法 根据题意&#xff0c;显然全局倒置的值大于等于局部倒置的值。因此我们不必求出具体的全局倒置的值和局部倒置的值&#xff0c;我们只需要证明全局倒置的值大于局部倒置的值即可。 因此我们可以从后往前进行查询&#xff0c;只要我们能够证明区间[i1,n−1][i1,n-…

小啊呜产品读书笔记001:《邱岳的产品手记-02》开篇词010203讲

小啊呜产品读书笔记001&#xff1a;《邱岳的产品手记-02》 开篇词&01&02&03讲一、今日阅读计划二、泛读&知识摘录1、开篇词 产品经理的世界没有对错2、01讲 验证码是个好设计吗&#xff1f;3、02讲 产品经理工具指南4、03讲 产品案例分析Trigraphy的设计哲学三…

VS2019编码修改为UTF-8的方法

1.修改windows系统配置 设置 时区和语言 语言 》 管理语言设置 2. 修改VS2019 在扩展里安装Force UTF-8(No BOM) 和 Fix File Encoding 插件 解决控制台中文乱码问题 1.按下winr&#xff0c;输出regedit&#xff0c;打开注册表编辑器 2.在注册表编辑器中打开路径HKE…

VBA调用宏的方式总结大全

文章目录背景方式一 : Excel菜单执行宏方式二 : 按钮绑定宏1. 插入按钮2. 绑定宏方式三 : 窗体绑定宏1. 插入窗体2. 拖入按钮3. 绑定按钮点击事件触发宏(写代码)方式四 : 事件绑定宏背景 很多小伙伴在拿到模型之后, 看着满屏的代码, 却不知道如何下手使用这些代码. 这篇文章就…

【DOTS学习笔记】面向数据设计DOD

目录前言程序设计方法ODD->DODCache的3C与3R面向数据设计需要思考的问题AOSSOADOTS面向数据设计原则前言 本文是Metaverse大衍神君的《DOTS之路》系列课程的学习笔记 程序设计方法 Instructional Programming 指令化编程 脱离指令打孔输入后&#xff0c;伴随着机器汇编语言…

操作系统4小时速成:进程同步,临界资源,互斥,信号量的作用,死锁产生的四个条件,安全状态,银行家算法

操作系统4小时速成&#xff1a;进程同步&#xff0c;临界资源&#xff0c;互斥&#xff0c;信号量的作用&#xff0c;死锁产生的四个条件&#xff0c;安全状态&#xff0c;银行家算法 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&am…

vhost dpdk 共享内存

struct kvm_memory_slot http://tinylab.org/kvm-intro-part1 https://www.cnblogs.com/LoyenWang/p/13943005.html &#xff08;免费订阅,永久学习&#xff09;学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂 更多DPDK相关学习资料有…

Mybatis-Plus——分页+模糊查询

建表&#xff1a; create table pms_brand (brand_id bigint not null auto_increment comment 品牌id,name char(50) comment 品牌名,logo varchar(2000) comment 品牌logo地址,descript longtext comment 介绍,sh…

使用ReentrantLock中的条件变量让多个线程顺序执行

一. 前言 近日壹哥的一个学生在参加某公司校招面试时&#xff0c;遇到一个多个线程顺序执行的面试题&#xff0c;特意记录下来和大家分享一下&#xff0c;这个题目的具体要求是这样的&#xff1a; 假设有3个线程 a,b,c&#xff0c;要求三个线程一起进入到就绪态&#xff0c;执…