【C语言】——结构体

【C语言】——结构体

    • 一、结构体类型的声明
      • 1.1、结构体的声明
      • 1.2、结构体变量的创建和初始化
      • 1.3、结构体的特殊声明
      • 1.4、结构体的自引用
      • 1.5、结构体的重命名
    • 二、 结构体的内存对齐
      • 2.1、对齐规则
      • 2.2、结构体对齐实践
      • 2.3、为什么存在内存对齐
      • 2.4、修改默认对齐数
    • 三、结构体传参
    • 四、结构体实现位段
      • 4.1、什么是位段
      • 4.2、位段的内存分配
      • 4.3、位段的跨平台问题
      • 4.4、位段的应用
      • 4.5、位段使用的注意事项

一、结构体类型的声明

  在前面,我们学习操作符时,我们已经简单介绍过了结构体类型(详情请看【C语言】——详解操作符(下))。本文,我们将继续深入讲解结构体。
  

1.1、结构体的声明

  
  首先,我们来简单回顾一下结构体的基本知识:

struct tag//结构体标签
{
	member-list;//成员列表
}variable-list;//结构体变量

  结构体就是某些值的集合,这些值被称为成员变量。结构体的成员可以是不同类型的变量
  
我们试着用结构体描述一位学生:

struct student
{
  int num;
  char name[32];
  float score;
}stu;
  • s t r u c t struct struct定义结构体的关键字
  • s t r u c t struct struct s t u d e n t student student用户定义的结构体类型
  • n u m num num s c o r e score score结构体的成员名
  • s t u stu stu变量名
      
      

1.2、结构体变量的创建和初始化

#include<stdio.>
int main()
{
	//按照结构体成员的顺序初始化
	struct Stu s = { "张三",20,"男", "20240000001" };
	printf("name: %s\n", s.name);
	printf("age : %d\n", s.age);
	printf("sex : %s\n", s.sex);
	printf("id  : %s\n\n", s.id);

	//按指定的顺序初始化
	struct Stu s2 = { .age = 18, .name = "lisi", .id = "20240000002" , .sex = "女" };
	printf("name: %s\n", s2.name);
	printf("age : %d\n", s2.age);
	printf("sex : %s\n", s2.sex);
	printf("id  : %s\n", s2.id);
	return 0;
}

  
运行结果:

在这里插入图片描述

  
  

1.3、结构体的特殊声明

  在声明结构体时,可以不完全声明,这种特殊的结构体叫匿名结构体

例如:

struct
{
	char c;
	int i;
	double c;
}s;

  这个结构体在声明时,并没有加上结构体标签 ( t a g ) (tag) tag,这种结构体被称为匿名结构体

  匿名结构体在声明时,必须定义变量

  匿名结构体只能使用一次,以后你想使用它,抱歉,没有这个类型名,无法使用

  一般我们创建这个结构体变量,只使用它一次时,才考虑使用匿名结构体
  

让我们看看下面的例子:

struct
{
	int a;
	char b;
	float c;
}x;

struct
{
	int a;
	char b;
	float c;
}a[20], *p;

//在上面代码的基础上,下面的代码合法吗?
p = &x;

警告:
  虽然上面两个匿名结构体的声明是一样的,但是编译器还是会认为他们是两个完全不同的类型,所以是非法的。

  匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使用一次

  正因为匿名结构体有多种限制不便,因此一般不使用匿名结构体。
  
  

1.4、结构体的自引用

  
  提及结构体的自引用,我们需先粗略地了解一下数据结构

  数据结构,简单来说就是数据在内存中的存储和组织结构
  
数据结构分为多种

  • 线性数据结构:顺序表、链表、栈、队列
  • 树形数据结构:二叉树
  • ······

  
下面,我们简单介绍顺序表和链表
  
  假设,我们要存:1、2、3、4、5 这五个数据,很自然的想法就是连续开辟一块空间将他们放进去。
  这种连续开辟空间的方式叫顺序表,其本质就是数组。它如一条线,把数据串联起来,是线性数据结构

在这里插入图片描述

  
  
  还有另外一种方式:五个数据的存储在物理上空间上并不连续,可能之间隔了十万八千里,但是呢,可以通过1找到2,通过2找到3······一直找到5
  
  他们虽然在内存中不是连续的内存空间,但我们可以通过设计,把他们串联在一起,使他们虽物理不连续,但逻辑连续
  
  这种结构体叫做链表,像链条一样把他们串起来
  
图示:

在这里插入图片描述

  
  我们将每个单独的内存块称为节点,不难发现,一个节点,除了要存储数据外,还要存储找到下一个节点的方法
  
  那这样链表的节点可不可以这样定义呢?

struct Node
{
	int data;
	struct Node next;
};

  struct Node这个节点,即存放了数据 d a t a data data,又包含了下个节点 n e x t next next,这样不就能实现链表了吗?

  这样的设计方式可不可以呢
  答案:不可以
  为什么呢?
  我们来想一个问题:如果这样的话,sizeof(struct Node)多大?
  

在这里插入图片描述

  由图可知,它可以无限套娃,是算不出具体大小的,它甚至可以无穷大,因此上面的定义方法是错的。
  
  那又该如何定义呢?
  
  正确的做法应该是让当前节点存放下一个节点的地址

struct Node
{
	int data;
	struct Node* next;
};

  
  每个节点都由两部分组成:数据域指针域

  这样,我们就可以通过指针找到下一个节点的地址,当为最后一个节点时,让其指向空即可

  同时,这样结构体的大小完全固定,可以计算
  

总结:

  • 结构体中包含自己同类型的结构体是不允许
  • 结构体中包含自己同类型的指针可行

  
  

1.5、结构体的重命名

  我们定义了一个结构体,觉得每次创建该结构体变量都要加上 s t r u c t struct struct 难免太过太麻烦,那有没有什么办法可以简化呢?
  我们可以用 t y p e d e f typedef typedef 对其进行重命名
  
例如:

typedef struct student
{
	char name[20];
	int age;
	char sex[5];
	char id[20];
}student;

struct student s1;
student s2;

  这样,创建该结构体变量时,可以将 s t r u c t struct struct 省去
  
  同时,值得一提的是,在结构体的自引用过程中,掺杂了 t y p e d e f typedef typedef 对结构体类型的重命名时,也容易出现错误,看看下面的代码,他是否可行呢?

typedef struct
{
	int data;
	Node* next;
}Node;

  很显然,是不对的。重命名是在结构体定义完后才重命名,你怎么在结构体内就给我使用重命名后的变量了呢?这时我还不认识 N o d e Node Node 这个符号呢。
  
正确写法应该是这样:

typedef struct
{
	int data;
	struct Node* next;
}Node;

  
  

二、 结构体的内存对齐

  我们已经掌握了结构体分基本用法,但我们有没有想过结构体的大小是这么计算的呢?成员与成员之间会像数组一样连续存放吗?让我们开启接下来的学习

2.1、对齐规则

  首先,我们要掌握结构体对齐的基本规则

  • 结构体的第一个成员对齐到和结构体变量起始位置 偏移量为 0 的地址处
      
  • 其他成员变量要对齐到某个数字 (对齐数)的整数倍地址处。
    对齐数 = 编译器默认对齐数与该成员变量的 较小值
    VS 中,默认对齐数为 8
    l i n u x linux linux 中, g c c gcc gcc 没有默认对齐数
      
  • 结构体总大小为最大对齐数的整数倍(结构体成员每个都有对齐数,取所有对齐数中最大的那个)。
      
  • 结构体如果嵌套了结构体的情况,结构体对齐到自己的成员最大对齐数整数倍数处。结构体的整体大小就是所有最大对齐数(包括嵌套结构体中成员的对齐数)的整数倍数的地址处。

  
  

2.2、结构体对齐实践

  
  看了上面的对齐规则,想来大家都是满脸问号,没关系,我们直接上题,在实践中出真知。
  
题一:

struct S1
{
	char c1;
	int i;
	char c2;
};

  
我们对照上面的规则一步步来分析

  • char c1:他是结构体的第一个成员,对齐到结构体起始位置,这个没啥问题。
  • int i:由第二条:要对齐到对齐数的整数倍数处。 i n t int int 大小为 4,VS 中默认对齐数为 8,取较小值,对齐数为 4。即 i n t int int 要对齐到偏移量为 4 的整数倍地址处。这里,对齐到偏移量为 4 地址处。
  • char c2:由第二条规则, c h a r char char 的对齐数为 1,可以直接接着 i i i 对齐到偏移量为 9 的地址处,不用空出地址。
  • 结构体总大小:总体结构体大小为最大对齐数的整数倍,该结构体成员中,最大对齐数为 i n t int int 的对齐数 4,因此要对到 4 点整数倍数处,此时 4 最小整数倍数为 12

  在这里插入图片描述

  

题二:

struct S2
{
	char c1;
	char c2;
	int i;
};

  
这题的成员类型与上面一题一样,那结构体大小有什么区别呢?

  • char c1:分析方法与上题一样,他为结构体第一个成员,对齐到结构体偏移量为 0 位置处。
  • char c2:由规则二: c h a r char char大小为 1,默认对齐数是 8,对齐数取较小值,为 1,所有整数都是一的整数倍数。因此对齐到偏移量为 1 地址处,即连续存放
  • int i:由规则二:算出 i n t int int 对齐数为 4,要对齐到 4 的整数倍数处,即偏移量为 8 地址处
  • 结构体总大小该结构体的最大对齐数为 4,由规则三:结构体总大小为其整数倍,此时 4 最小整数倍数为 8
      
      在这里插入图片描述

  不知大家注意到没有,两个结构体,成员类型一样,但顺序不一样,导致整个结构体的大小有了差异。
  所以,要想节省结构体所占用的空间,我们可以把对齐数较小的成员类型尽量集中创建

  
题三:

struct S3
{
	double d;
	char c;
	int i;
};

  
  这题的分析方法与前面的类似,这里就不过多赘述了,大家看图就一目了然
  

在这里插入图片描述

  

题四:

struct S4
{
	char c1;
	struct S3 s3;
	double d;
};

这题出现了嵌套结构体,那我们重点来讲一下嵌套结构。

  • struct S3 s3:前面,我们计算得出struct S3 s3大小 16,自己内部的成员最大对齐数是 d o u b l e double double8,即对齐到 8 的整数倍数处
  • 结构体总大小:总大小是所有最大对齐数(包括嵌套结构体中成员的对齐数)的整数倍数, c h a r char char c 1 c1 c1 的对齐数是 1 d o u b l e double double d d d 的对齐数的 8,那我们再来看struct S3 s3,其内部的成员最大对其数是 d o u b l e double double8,因此结构体总大小要是 8 的倍数
      
      在这里插入图片描述

  
  

2.3、为什么存在内存对齐

  

  1. 平台原因(移植原因)
      不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些出特定类型的数据,否则抛出硬件异常。
  2. 性能原因
      数据结构(尤其是栈)应该尽可能地在自然边界上对其。原因在于,为了访问未对齐的内存,处理器需要作两次访问;而对其的内存访问仅需要一次访问。假设一个处理器试从内存中区 8 个字节,则地址必须是 8 的倍数。如果我们能保证将所有的 d o u b l e double double 类型的数据的地址都对其成 8 的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个 8 字节块中。

  
  总体来说:结构体内存对齐是拿空间换时间的做法

  时间一去不复返,空间可循环利用
  
  

2.4、修改默认对齐数

  若是觉得默认对齐数,我们可以自己修改默认对齐数

  prama这个预处理指令,可以修改编译器的默认对齐数
  
例如:

#pragma pack(1)//设置默认对齐数为1
struct S
{
	char c1;
	int i;
	char c2;
};

#pragma pack()//取消设置的对其数,还原为默认
int main()
{
	printf("%d\n", sizeof(struct S));
	return 0;
}

  上面的输出结果是什么?
答案:6
  
  当然,修改对齐数不要随便给值,比如改成 3 就不合适了
  
  

三、结构体传参

  
  我们知道,传参有两种方式,一种是传值传参,一种是传址传参。我们一起来看看结构体这两种传参方式。

struct S
{
	int data[1000];
	int num;
};

struct S s = { {1,2,3,4}, 1000 };

//结构体传参
void Print1()
{
	printf("%d\n", s.num);
}
//结构体地址传参
void Print2(struct S* ps)
{
	printf("%d\n", ps->num);
}

int main()
{
	Print1(s);
	Print2(&s);
	return 0;
}

  那么上面两种传参方式哪个更好呢?
答案是:传址传参

  为什么呢?
  函数在传参的时候,参数是需要压栈的,会有时间和空间的系统开销

  如果传递的是结构体对象,参数过大时,参数压栈的系统开销比较大,会导致性能下降
  所以,结构体传参,最好为传址传参

  
  

四、结构体实现位段

  
  了解完结构体的基本知识,我们来了解一下用结构体实现段的能力。

4.1、什么是位段

  首先,我们来了解位段

  位段的声明与结构体类似,但有两个不同点:

  • 位段的成员类型必须是 c h a r char char i n t int int u n s i g n e d unsigned unsigned i n t int int 以及 s i g n e d signed signed i n t int int
  • 位段的成员名后边要有一个冒号和一个数字

例如:

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

  
  那么到底什么是位段呢?位段中的位是二进制位的意思。

  假设定义一个 i n t int int 类型变量,它共占 4 个字节即 32 个 b i t bit bit 位。

  现在假设有一种场景,每个变量的可能取值不多,只有: 0、1、2、3 这四种可能性。那么我们发现他们只需用 2 个二进制位就够了,这样就有 30 个二进制位被浪费了。

  这时,我们就可以通过设计,让每个变量只占 2 个 bit 位

  上面结构体定义的位段 A A A,意思是 a a a2 b i t bit bit 位, b b b5 b i t bit bit 位, c c c10 b i t bit bit 位, d d d30 b i t bit bit

  
  这里我问问大家,位段 A 它所占内存空间是多少呢?
   a a a 占 2 位, b b b 占 5 位、 c c c 占 10 位、 d d d 占 30 位,加起来一共 47 位,这样一共 6 个字节 48 个比特位就行,那大小是不是 6 呢?
  
我们实践来看看:

#include<stdio.h>
int main()
{
	printf("%d\n", sizeof(struct A));
	return 0;
}

  
运行结果:

在这里插入图片描述

  为什么会是 8 呢?让我们来了解一下位段的内存分配
  
  

4.2、位段的内存分配

  • 位段的成员必须是 c h a r char char i n t int int u n s i g n e d unsigned unsigned i n t int int 或者 s i g n e d signed signed i n t int int 类型
  • 位段的开辟是根据需要,一次性开辟 4 个字节 ( i n t ) (int) int1 个字节 ( c h a r ) (char) char 的方式来开辟的
  • C语言 中,对位段的定义并不明确,它设计很多不确定的因素,因此位段是不跨平台的,注重可移植性的程序应该避免使用位段
      
    下面,我们举个例子,了解一下位段在空间中说如何开辟内存的
struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	return 0;
}

  
在 VS 编译器中。位段的成员是从右向左分配的,

  • 先来看 a a a:10的二进制表示为 1010,因为 a a a 大小只有 3 b i t bit bit 位,舍去最高位的 1,从右存入 010
  • 再看 b b b:第一个字节中, a a a 占去 3 个 b i t bit bit 位,而 b b b4 b i t bit bit 位,可以继续存。12 的二进制位 1100,因为 VS 中是从右往左存,存在 010 左边
  • 再看 c c c,在 VS 中,当一个位段过大,无法容纳于前面位段所剩余的空间时,舍弃该空间
    前面位段 a a a 和位段 b b b 已经占用 7 个 b i t bit bit 位,剩下 1 个 b i t bit bit 位,无法容纳 c c c 所需的 5 个 b i t bit bit 位,因此另开一个字节空间
    3 的二进制表示为 00011,从右存入该字节
  • 再看 d d d:同理,剩余 3 个 b i t bit bit 位的空间,无法容纳 d d d 所需的 4 个字节,另开辟一个字节空间。4 的二进制表示 0100,从右存入新字节空间

  
图示:

  在这里插入图片描述
  
  在这里插入图片描述
  

  

4.3、位段的跨平台问题

  上面,我们提到位段有许多不确定性,导致位段不可跨平台,可移植性差。那具体是哪些不确定性呢?

  • i n t int int 位段,被当成有符号数还是无符号数,这个不确定
  • 位段中的最大数目不能确定(16位机器最大数为 16,32 位和 64 位机器最大数为 32,写成 27,在 16 位机器会出问题)
  • 位段中,成员在内存中是从左到右分配还是从右到左分配尚未定义。
    图:
  • 当一个结构包含两个位段,当第二个成员比较大,完全无法容纳于第一个位段的剩余位时,是舍弃剩余位还是利用,这是不确定的。

总结:位段能达到与结构体一样的效果。同时,位段能很好的节约空间,但是位段的可移植性差
  
  

4.4、位段的应用

  
  位段在实际生活中有什么应用呢,我们一起来了解一下。
  平时,与朋友聊微信时,我们的对话信息发送出去,如何确保对方能准确收到呢?

  其实,数据在网络上不是裸奔的,它是用数据包所包裹,以确保信息能准确送达。就像我们寄快递一样,并不是物件直接寄过来,还要进行层层包裹并标注地址等信息
  
下面是IP数据包的基本格式:

在这里插入图片描述

  可以看到,其中很多属性只需要用几个 b i t bit bit 位就能描述,这里使用位段,既能达到想要的效果,又能节省空间。
  数据包体积小,对网络的畅通是大有帮助的。
  想想,高速路上,全是小轿车和全是大货车,哪种畅通。
  
  

4.5、位段使用的注意事项

  位段是几个成员共用一个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位置处上没有地址的。内存中,每个字节分配一个地址,而一个字节内部的 b i t bit bit 位是没有分配地址的。
  
  所以,在使用位段时,不能对其成员进行取地址操作,这也意味着不能直接通过 s c a n f scanf scanf 给位段变量输入值,只能先放在一个变量中,再赋值给位段成员

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

int main()
{
	struct A sa = { 0 };
	int b = 0;
	scanf("%d", &b);
	sa._b = b;
	return 0;
}

  
  
  
  


  好啦,本期关于结构体的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在C语言的学习路上一起进步!

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

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

相关文章

数据结构------栈的介绍和实现

目录 1.栈的一些初步认识 2.栈的实现 3.相关的函数介绍 &#xff08;1&#xff09;栈的初始化 &#xff08;2&#xff09;栈的销毁 &#xff08;3&#xff09;栈的数据插入 &#xff08;6&#xff09;判断是否为空 &#xff08;7&#xff09;栈的大小 4.栈的实现完整…

C语言例题31:在屏幕上显示一个菱形

题目要求&#xff1a;在屏幕上显示一个菱形 #include <stdio.h>void main() {int i, j;int x;printf("输入菱形行数(3以上的奇数&#xff09;&#xff1a;");scanf("%d", &x);//显示菱形上面的大三角形for (i 1; i < (x 1) / 2; i) {for (…

【R语言数据分析】相关性分析:pearson与spearman

相关性分析是探寻两个变量之间关联关系的分析方法&#xff0c;注意相关性分析仅仅针对连续型变量和有序分类变量&#xff0c;对于无需分类变量就不存在相关性分析了&#xff0c;而是通过差异分析来间接反映相关性。比如性别和身高的关系就无法做相关性分析&#xff0c;虽然我们…

RHCE shell-第一次作业

要求&#xff1a; 1、判断当前磁盘剩余空间是否有20G&#xff0c;如果小于20G&#xff0c;则将报警邮件发送给管理员&#xff0c;每天检査- 次磁盘剩余空间。 2、判断web服务是否运行(1、查看进程的方式判断该程序是否运行&#xff0c;2、通过查看端口的方式 判断该程序是否运…

动态规划——最短编辑距离

一、问题描述 最短编辑距离(Minimum Edit Distance)&#xff0c;也被称为Levenshtein距离&#xff0c;是一种计算两个字符串间的差异程度的字符串度量(string metric)。我们可以认为Levenshtein距离就是从一个字符串修改到另一个字符串时&#xff0c;其中编辑单个字符&#xff…

从零开始学AI绘画,万字Stable Diffusion终极教程(二)

【第2期】关键词 欢迎来到SD的终极教程&#xff0c;这是我们的第二节课 这套课程分为六节课&#xff0c;会系统性的介绍sd的全部功能&#xff0c;让你打下坚实牢靠的基础 1.SD入门 2.关键词 3.Lora模型 4.图生图 5.controlnet 6.知识补充 在第一节课里面&#xff0c;我们…

CPP#类与对象4

友元 关键字&#xff1a;friend 友元的实现&#xff1a;全局函数做友元&#xff1b; 类做友元&#xff1b; 成员函数做友元。 .1全局函数做友元 class Point { private:double x, y; public:Point(double xx, double yy); friend int Distance(Point &a, Point &b)…

关于win平台c语言引入开源库的问题与解决

许久不写博客&#xff0c;五一还在加班&#xff0c;就浅浅写一篇吧 最近除了做物联网平台 还对网关二次开发程序做了修改&#xff0c;网关的二次开发去年年底的时候做过&#xff0c;但是当时的逻辑不是十分完善&#xff0c;差不多已经过了半年了&#xff0c;很多细节已经忘记了…

探索APP托管服务分发平台的魅力 - 小猪APP分发平台(APP托管)

什么是APP托管服务分发平台 APP托管服务分发平台是一个集成了代码托管、构建集成、测试、发布和监控等全面性服务的平台。让开发者可以专注于创作探索APP托管服务分发平台的魅力 - 小猪APP分发平台&#xff0c;而不必花费太多精力在app的维护和分发上。 为什么要选择APP托管服…

D3CTF2024

文章目录 前言notewrite_flag_where【复现】D3BabyEscapePwnShell 前言 本次比赛笔者就做出两道简单题&#xff0c;但队里师傅太快了&#xff0c;所以也没我啥事。然后 WebPwn 那题命令行通了&#xff0c;但是浏览器不会调试&#xff0c;然后就简单记录一下。 note 只开了 N…

绘图神器===draw.io

文章目录 前言打开看看版本总结 前言 看到一个好玩的神器&#xff0c;Draw.io 看到一个网页draw.io&#xff0c;打开一看&#xff0c;还不错&#xff0c;是一款网页端的绘图平台。支持各种各样的绘制需求&#xff0c;像类图&#xff0c;流程图&#xff0c;泳道图&#xff0c;…

OpenCV如何模板匹配(59)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇&#xff1a;OpenCV如何实现背投(58) 下一篇 &#xff1a;OpenCV在图像中寻找轮廓(60) 目标 在本教程中&#xff0c;您将学习如何&#xff1a; 使用 OpenCV 函数 matchTemplate()搜索图像贴片和输入…

李沐-46 语义分割和数据集【动手学深度学习v2】

在语义分割中&#xff0c;不是一张图片分配一个label&#xff0c;而是为图片的每一个像素点分配一个label。假设我们输入的是RGB三通道的图片&#xff0c;即每个像素点颜色可以表示为(x, y, z)&#xff0c;那么为了给像素点打上label&#xff0c;我们需要构建一个映射关系&…

这是一个简单的照明材料网站,后续还会更新

1、首页效果图 代码 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title>爱德照明网站首页</title><style>/*外部样式*/charset "utf-8";*{margin: 0;padding: 0;box-sizing: border-box;}a{text-dec…

24.哀家要长脑子了!

目录 1.594. 最长和谐子序列 - 力扣&#xff08;LeetCode&#xff09; 2.350. 两个数组的交集 II - 力扣&#xff08;LeetCode&#xff09; 3.554. 砖墙 - 力扣&#xff08;LeetCode&#xff09; 4.9. 回文数 - 力扣&#xff08;LeetCode&#xff09; 5.13. 罗马数字转整数 …

使用D3.js进行数据可视化

D3.js介绍 D3.js是一个流行的JavaScript数据可视化库&#xff0c;全称为Data-Driven Documents&#xff0c;即数据驱动文档。它以数据为核心&#xff0c;通过数据来驱动文档的展示和操作。D3.js提供了丰富的API和工具&#xff0c;使得开发者能够创建出各种交互式和动态的数据可…

Linux服务器常用命令总结

view查找日志关键词 注意日志级别&#xff0c;回车后等一会儿&#xff0c;因为文件可能比较大加载完需要时间 当内容显示出来后&#xff0c;使用“/关键词”搜索 回车就能搜到&#xff0c;n表示查找下一个&#xff0c;N表示查找上一个 find 查找 find Family -name book …

华为平板手机如何清理应用市场的存储空间

如何清理应用市场的存储空间 适用产品&#xff1a; 手机&#xff0c;平板 适用版本&#xff1a;不涉及系统版本 如果您的应用市场显示应用的数据较大&#xff0c;可能是下载的安装包没有安装成功&#xff0c;导致安装包未自动删除。&#xff08;可参考&#xff1a;应用市场下…

Delta lake with Java--将数据保存到Minio

今天看了之前发的文章&#xff0c;居然有1条评论&#xff0c;看到我写的东西还是有点用。 今天要解决的问题是如何将 Delta产生的数据保存到Minio里面。 1、安装Minio&#xff0c;去官网下载最新版本的Minio&#xff0c;进入下载目录&#xff0c;运行如下命令&#xff0c;曾经…

2024年第11届生物信息学研究与应用国际会议(ICBRA 2024)即将召开!

2024年第11届生物信息学研究与应用国际会议&#xff08;ICBRA 2024&#xff09;将于2024年9月13-15日在意大利米兰举行。生物信息学&#xff0c;作为连接生物学与信息技术的桥梁&#xff0c;正日益成为探索生命奥秘、推动生命科学发展的重要力量。ICBRA 2024的召开&#xff0c;…