【C语言】——结构体

news2024/5/18 11:53:38

【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语言的学习路上一起进步!

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

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

相关文章

数据库(MySQL)—— 多表查询

数据库&#xff08;MySQL&#xff09;—— 多表查询 多表关系一对多多对多一对一多表查询概述数据准备查询形式笛卡尔积 分类连接查询内连接外连接左外连接右外连接 自连接联合查询 今天我们来进入MySQL中一个非常重要的部分&#xff1a;多表查询&#xff1a; 多表关系 多表关…

【HM】DevEco Studio如何使用代码编程AI助手

大家可能都有用过或了解过github copilot插件&#xff0c;确实为我们编码智能、提升开发效率有很大的帮助。推荐两款国产的ai编程插件&#xff0c;分别是华为的CodeArts Snap和阿里的通义灵码。 DevEco 中如何安装通义灵码&#xff1f; 一、下载通义灵码离线安装包 打开官网…

数组邻接表+堆优化版dijkstra+蓝桥杯2022年第十三届决赛真题-出差

文章目录 邻接表数组实现堆优化版dijkstra蓝桥杯2022年第十三届决赛真题-出差 邻接表数组实现 idx是每条边的地址e保存终点的节点值w保存每条边的权值ne[idx]保存边表&#xff0c;idx的下一个顶点的地址h[a]保存顶点表&#xff0c;a是起点&#xff0c;h[a]是终点的地址 int e…

docker-compose单机容器集群编排工具

前言&#xff1a; docker-compose用来单机上编排容器&#xff08;定义和运行多个容器&#xff0c;使容器能互通&#xff09; Eg&#xff1a;前端和后端部署在一台机器上&#xff0c;现在直接通过编写docker-compose文件对多个服务&#xff08;可定义依赖&#xff0c;按顺序启…

conda环境安装的pyproj包报错

conda环境安装的pyproj包报错 文章目录 conda环境安装的pyproj包报错问题解决参考 问题 在conda创建的Python3.9虚拟环境中安装pyproj包3.6在运行时出现以下报错 UserWarning: pyproj unable to set database path. _pyproj_global_context_initialize()解决 先激活并进入创…

古典密码学简介

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

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

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

【数据库原理及应用】期末复习汇总高校期末真题试卷

试卷 一、填空题 1.________是位于用户与操作系统之间的一层数据管理软件。 2.数据库系统的三级模式结构是指________、________、________。 3.数据库系统的三种数据模型是________ 、________、________。 4.若关系中的某一属性组的值能唯一地标识一个元组&#xff0c;则…

【LinuxC语言】信号的基本概念与基本使用

文章目录 前言一、信号的概念二、信号的使用2.1 基本的信号类型2.2 signal函数 总结 前言 在Linux环境下&#xff0c;信号是一种用于通知进程发生了某种事件的机制。这些事件可能是由操作系统、其他进程或进程本身触发的。对于C语言编程者来说&#xff0c;理解信号的基本概念和…

使用 ORPO 微调 Llama 3

原文地址&#xff1a;https://towardsdatascience.com/fine-tune-llama-3-with-orpo-56cfab2f9ada 更便宜、更快的统一微调技术 2024 年 4 月 19 日 ORPO 是一种新的令人兴奋的微调技术&#xff0c;它将传统的监督微调和偏好校准阶段合并为一个过程。这减少了训练所需的计算…

8.MyBatis 操作数据库(进阶)

文章目录 1.动态SQL插入1.1使用注解方式插入数据1.2使用xml方式插入数据1.3何时用注解何时用xml&#xff1f;1.4使用SQL查询中有多个and时&#xff0c;如何自动去除多余and1.4.1方法一&#xff1a;删除and之后的代码如图所示&#xff0c;再次运行1.4.2方法二&#xff1a;加上tr…

C语言——文件相关操作

2.什么是文件 3.文件的打开和关闭 4.文件的顺序读写 5.文件的随机读写 6.文本文件和二进制文件 7.文件读取结束的判定 8.文件缓冲区 一、文件相关介绍 1、为什么使用文件 文件用于永久存储数据。通过使用文件&#xff0c;我们可以在程序关闭后保存数据&#xff0c;以便将来…

Springboot图片上传【本地+oss】

文章目录 1 前端组件页面2 本地上传3 上传到阿里云oss3.1申请开通账号&#xff0c;做好先导准备3.2 开始使用 1 前端组件页面 使用的VueElement组件 在线cdn引入&#xff1a; <script src"https://cdn.bootcdn.net/ajax/libs/vue/2.7.16/vue.js"></script&…

Simulink|【免费】虚拟同步发电机(VSG)惯量阻尼自适应控制仿真模型

目录 主要内容 仿真模型要点 2.1 整体仿真模型 2.2 电压电流双闭环模块 2.3 SVPWM调制策略 2.4 无功电压模块 2.5 自适应控制策略及算法 部分结果 下载链接 主要内容 该模型为simulink仿真模型&#xff0c;主要实现的内容如下&#xff1a; 随着风力发电、…

免费APP分发平台 - 一个指南和解析

数字化时代的APP分发平台 随着数字化进程的加速免费APP分发平台 - 一个指南和解析&#xff0c;移动应用&#xff08;APP&#xff09;市场正迅速扩大。在这个充满竞争的市场中免费APP分发平台 - 一个指南和解析&#xff0c;一个优秀的APP分发平台能够帮助开发者和商家更有效地触…

用keras识别狗狗

一、需求场景 从照片从识别出狗狗 from keras.applications.resnet50 import ResNet50 from keras.preprocessing import image from keras.applications.resnet50 import preprocess_input, decode_predictions import numpy as np# 加载预训练的ResNet50模型 model ResNet5…

网络知识点之—QoS

QoS&#xff08;Quality of Service&#xff0c;服务质量&#xff09;指一个网络能够利用各种基础技术&#xff0c;为指定的网络通信提供更好的服务能力&#xff0c;是网络的一种安全机制&#xff0c; 是用来解决网络延迟和阻塞等问题的一种技术。QoS的保证对于容量有限的网络来…

【matlab基础知识】(三)二维曲线绘制plot

x[-pi:0.0001:pi]; 选择较小步距 ysin(tan(x))-tan(sin(x));plot(x,y) 条件和函数值做一个点乘 x[-2:0.02:2];y1.1*sign(x).*(abs(x)>1.1)x.*(abs(x)<1.1);plot(x,y) 颜色&#xff0c;线形&#xff0c;曲线上的标志 由于0.01cosx波动太小&#xff0c;所以plotyy绘制多…

C语言 | Leetcode C语言题解之第64题最小路径和

题目&#xff1a; 题解&#xff1a; int minPathSum(int** grid, int gridSize, int* gridColSize) {int rows gridSize, columns gridColSize[0];if (rows 0 || columns 0) {return 0;}int dp[rows][columns];dp[0][0] grid[0][0];for (int i 1; i < rows; i) {dp[i…

【吃透Java手写】- Spring(上)-启动-扫描-依赖注入-初始化-后置处理器

【吃透Java手写】Spring&#xff08;上&#xff09;启动-扫描-依赖注入-初始化-后置处理器 1 准备工作1.1 创建自己的Spring容器类1.2 创建自己的配置类 ComponentScan1.3 ComponentScan1.3.1 Retention1.3.2 Target 1.4 用户类UserService Component1.5 Component1.6 测试类 2…