肖恩带你拿捏结构体!

news2024/9/24 3:30:10

先赞后看,养成习惯(😁),几天不见,甚是想念,今天肖恩带大家拿捏结构体~~~
请添加图片描述

1. 结构体类型的声明

那首先,什么是结构体呢?
C语⾔已经提供了内置类型,如:char、short、int、long、float、double等,但是只有这些内置类型还是不够的,假设我想描述学⽣,描述⼀本书,这时单⼀的内置类型是不⾏的。描述⼀个学⽣需要名字、年龄、学号、⾝⾼、体重等;描述⼀本书需要作者、出版社、定价等。C语⾔为了解决这个问题,增加了结构体这种⾃定义的数据类型,让程序员可以自己创造适合的类型。、
结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:标量、数组、指针,甚至是其他结构体。
结构体的关键字是 struct

struct tag
{
member-list;
}variable-list;

eg描述⼀个学⽣:

struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
}; //分号不能丢

结构的特殊声明

在声明结构的时候,可以不完全的声明。
//匿名结构体类型

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

上⾯的两个结构在声明的时候省略掉了结构体标签(tag)。那么问题来了?

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

警告:
编译器会把上⾯的两个声明当成完全不同的两个类型,所以是非法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使用⼀次。

结构的自引用

在结构中包含⼀个类型为该结构本⾝的成员是否可以呢?
⽐如,定义⼀个链表(后面也会讲哦)的节点:

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

上述代码正确吗?如果正确,那 sizeof(struct Node) 是多少?
仔细分析,其实是不⾏的,因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的大小就会⽆穷的⼤,是不合理的。
正确的自引用方式:

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

2. 结构体变量的创建和初始化

给大家就两个例子大家一下就看明白了,这里不需要多做讲解,我们重点在后面呢
eg1

#include <stdio.h>
struct Stu
{
char name[20];//名字
int age;//年龄
char sex[5];//性别
char id[20];//学号
};
int main()
{
//按照结构体成员的顺序初始化
struct Stu s = { "张三", 20, "男", "20230818001" };
printf("name: %s\n", s.name);
printf("age : %d\n", s.age);
printf("sex : %s\n", s.sex);
printf("id : %s\n", s.id);
//按照指定的顺序初始化
struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .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;
}

eg2

//代码1:变量的定义
struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//代码2:初始化。
struct Point p3 = {10, 20};
struct Stu //类型声明
{
char name[15];//名字
int age; //年龄
};
struct Stu s1 = {"zhangsan", 20};//初始化
struct Stu s2 = {.age=20, .name="lisi"};//指定顺序初始化
//代码3
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化

3. 结构成员访问操作符

3.0 结构体指针

在前面,肖恩曾讲过指针点击链接查看,但是前面指针少讲了结构体指针,今天我们来补上,这个也不是很难哦,我们看看下面的就欧克了

  1. 结构体指针的定义:结构体指针是指向结构体变量的指针,可以通过结构体指针来访问和修改结构体的成员变量。
  2. 结构体指针的声明:结构体指针的声明方式为struct_name *ptr_name;,其中struct_name是结构体的名称,ptr_name是指针变量的名称。
  3. 结构体指针的初始化:结构体指针可以通过赋值给结构体变量的地址来进行初始化,例如ptr_name = &struct_var;。
  4. 通过结构体指针访问成员变量:可以使用->运算符通过结构体指针来访问结构体的成员变量,例如ptr_name->member_name。
  5. 动态分配内存:结构体指针通常与动态内存分配函数malloc()、calloc()和realloc()一起使用,以便在运行时为结构体分配内存空间。(这个肖恩在后面会更的,很快很快)
  6. 指针的指针:结构体指针也可以是指向指针的指针,这在需要修改指针本身指向的地址时非常有用。
  7. 指针的运算:结构体指针也可以进行指针运算,例如指针加法、指针减法等操作。
  8. 结构体指针作为函数参数:结构体指针可以作为函数的参数传递,这样可以在函数内部直接修改结构体变量的值。
#include <stdio.h>

struct Rectangle {
    int width;
    int height;
};

void calculateArea(struct Rectangle *ptr_rect) {
    int area = ptr_rect->width * ptr_rect->height;
    printf("Area of rectangle: %d\n", area);
}

int main() {
    struct Rectangle rect = {5, 10};
    calculateArea(&rect);

    return 0;
}

  1. 空指针检查:在使用结构体指针之前,最好进行空指针检查,以避免出现空指针异常。

3.1 结构体成员的直接访问

结构体成员的直接访问是通过点操作符(.)访问的。点操作符接受两个操作数。如下所⽰:

#include <stdio.h>
struct Point
{
	int x;
	int y;
}p = {1,2};
int main()
{
	printf("x: %d y: %d\n", p.x, p.y);
	return 0;
}

使用方式:结构体变量.成员名

3.2 结构体成员的间接访问

有时候我们得到的不是⼀个结构体变量,⽽是得到了⼀个指向结构体的指针。如下所⽰:

#include <stdio.h>
struct Point
{
	int x;
	int y;
};
int main()
{
	struct Point p = {3, 4};
	struct Point *ptr = &p;
	ptr->x = 10;
	ptr->y = 20;
	printf("x = %d y = %d\n", ptr->x, ptr->y);
	return 0;
}

使用方式:结构体指针->成员名
综合举例:

#include <stdio.h>
#include <string.h>
struct Stu
{
	char name[15];//名字
	int age; //年龄
};
void print_stu(struct Stu s)
{
	printf("%s %d\n", s.name, s.age);
}
void set_stu(struct Stu* ps)
{
	strcpy(ps->name, "李四");
	ps->age = 28;
}
int main()
{
	struct Stu s = { "张三", 20 };
	print_stu(s);
	set_stu(&s);
	print_stu(s);
	return 0;
}

接下来就是我们今天的重头戏
我们已经掌握了结构体的基本使⽤了。
现在我们深⼊讨论⼀个问题:计算结构体的⼤⼩。
这也是⼀个特别热⻔的考点: 结构体内存对⻬

4. 结构体内存对齐(重点)

4.1对齐规则

⾸先得掌握结构体的对⻬规则:

  1. 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
  2. 其他成员变量要对⻬到某个数字(对齐数)的整数倍的地址处。 对齐数=编译器默认的⼀个对齐数与该成员变量大小的较小值。 VS 中默认的值为 8 ,Linux中gcc(编译器)没有默认对齐数,对齐数就是成员自身的大小
  3. 结构体总大小为最大对齐数(结构体中每个成员变量都有⼀个对齐数,所有对齐数中最大的)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍。
    这么说大家看的也是有点懵吧,那通过下面几个练习,我来给大家一一画图讲解,相信大家看完后肯定会比我还明白!

4.2实战演练

例1:

struct S1
{
	char c1;
	int i;
	char c2;
};
printf("%d\n", sizeof(struct S1));

在这里插入图片描述

我想我画得这么好你肯定看明白了😎
那么大小是不是12字节呢?当然是了
在这里插入图片描述

那这个又是多少呢?
例2:

struct S2
{
	char c1;
	char c2;
	int i;
};
	printf("%d\n", sizeof(struct S2));

在这里插入图片描述
没有问题吧,你肯定明白了

在这里插入图片描述
后面这两个我就不给大家画图一一解释了,都会了我还讲干嘛哈哈哈请添加图片描述

例3:

struct S3
{
	double d;
	char c;
	int i;
};
	printf("%d\n", sizeof(struct S3));

你做对了吗?当然对了,讲这么好你肯定懂了
在这里插入图片描述

那这个呢?
例4:
结构体嵌套问题

struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
	printf("%d\n", sizeof(struct S4));

在这里插入图片描述

4.3为什么存在内存对齐?

存在内存对齐的主要原因是为了提高计算机系统的性能。内存对齐可以使数据在内存中的存储更加高效,减少内存访问的时间。当数据按照特定的字节边界对齐存储时,CPU可以更快地访问这些数据,而不需要额外的处理来处理未对齐的数据。这样可以减少内存访问的次数和提高数据读取的速度,从而提高系统的整体性能。
——GPT3.5

内存对齐的存在主要有以下几个原因:

提高访问效率:当数据按照对齐要求存储在内存中时,处理器可以更快地读取和存储数据,从而提高程序的执行效率。这是因为CPU每次寻址和访问内存都需要消耗时间,而且CPU访问内存时并不是逐个字节访问,而是以字长(word size)为单位访问。如果访问未对齐的内存,处理器可能需要进行额外的操作,比如两次内存访问,这会增加处理时间。而通过对齐内存访问,处理器只需要进行一次访问,从而提高访问效率。
满足硬件要求:许多硬件平台对数据的访问有对齐的要求。例如,某些处理器在读取未对齐的数据时可能会产生异常,导致程序崩溃或结果不正确。内存对齐可以避免这些问题,确保程序在各种硬件平台上的正确性和稳定性。
增强平台可移植性:不同硬件平台在访问内存数据时具有差异性。有些CPU可以访问任意地址上的任意数据,而有些CPU只能在特定地址访问数据。因此,为了确保代码在不同平台上的可移植性,通常在编译时会对分配的内存进行对齐处理。
综上所述,内存对齐是为了提高访问效率、满足硬件要求以及增强平台可移植性而存在的。
——文心一言3.5

总体来说:结构体的内存对齐是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满⾜对⻬,⼜要节省空间,如何做到:
让占用空间小的成员尽量集中在⼀起

//例如:
struct S1
{
	char c1;
	int i;
	char c2;
};
struct S2
{
	char c1;
	char c2;
	int i;
};

S1 和 S2 类型的成员⼀模⼀样,但是 S1 和 S2 所占空间的大小有了⼀些区别。

4.4修改默认对齐数

#pragma 这个预处理指令,可以改变编译器的默认对齐数。
(关于预处理肖恩在后面也会讲哦,很快的嘿嘿)

#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{
	//输出的结果是什么?
	printf("%d\n", sizeof(struct S));
	return 0;
}

在这里插入图片描述
是不是跟上面就不一样了

本章的重点可算讲明白了
接下来我们来看结构体的传参

5. 结构体传参

struct S
{
	int data[1000];
	int num;
};
struct S s = {{1,2,3,4}, 1000};
//结构体传参
void print1(struct S s)
{
	printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{
	printf("%d\n", ps->num);
}
int main()
{
	print1(s); //传结构体
	print2(&s); //传地址
	return 0;
}

上⾯的 print1 和 print2 函数哪个好些?
答案是:首选print2函数。
为什么捏?
传递⼀个结构体对象的时候,结构体过大,系统开销⽐较⼤,所以会导致性能的下降,传递一个地址是不是就方便多了。
结论:
结构体传参的时候,要传结构体的地址

6. 结构体实现位段*

结构体讲完就得讲讲结构体实现位段的能力

6.1什么是位段

位段是一种数据结构,用于在内存中按位对数据进行存储
位段的声明和结构是类似的,有两个不同:

  1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以
    选择其他类型。
  2. 位段的成员名后边有⼀个冒号和⼀个数字。
    ⽐如:
struct A
{
	int _a:2;
	int _b:5;
	int _c:10;
	int _d:30;
};

A就是⼀个位段类型。

那位段A所占内存的大小是多少?

printf("%d\n", sizeof(struct A));

在这里插入图片描述

6.2位段的内存分配

位段(bit-field)的内存分配涉及对结构体(或联合体)中成员变量的位级控制。位段允许开发者以位为单位来定义结构体中的成员变量所占的空间,从而既能够节省空间,又方便于操作。

位段的内存分配有以下几个关键要点:

  1. 成员类型:位段的成员可以是int、unsigned int、signed
    int或char类型,这些都属于整型家族。这些类型决定了位段的基本存储单元大小,通常是按照int(4个字节)或char(1个字节)的方式来开辟空间。
  2. 位段大小:位段中的成员变量会指定一个位数,用来限制该变量可以使用的二进制位数。例如,int
    a:3;表示变量a只使用3个位来存储数据。这意味着即使给a赋一个更大的整数值,它也会在存储时被截断到指定的位数。
  3. 内存布局:位段在内存中的布局是从低位到高位进行填充的。如果当前字节的剩余位数不足以存储下一个位段成员,则会开辟新的存储单元(按int或char的大小)来继续存储。这意味着位段可能会跨越多个存储单元,但每个成员仍然只使用其指定的位数。
  4. 未使用空间:由于位段是以位为单位进行分配的,因此可能会产生未使用的空间。这些未使用的空间在内存中并不会被其他变量使用,而是被浪费掉了。然而,相较于直接使用完整的int或char变量,使用位段通常仍然能够节省大量的空间。
  5. 平台依赖性:需要注意的是,位段的具体实现和内存布局可能因编译器和平台的不同而有所差异。不同的编译器可能会对位段进行不同的填充和对齐处理,这可能导致在不同的平台上,相同的位段定义可能会产生不同的内存布局和大小。因此,在编写需要跨平台运行的代码时,应谨慎使用位段,并进行充分的测试。

总的来说,位段的内存分配是一种灵活且有效的空间优化技术,但使用时需要注意其潜在的平台依赖性和内存布局问题。
——文心一言3.5
⼀个例子

struct S
{
char a:3;
char b:4;
char c:5;
char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;

空间是如何开辟的?
在这里插入图片描述

6.3位段的应用

位段(Bit-field)是一种在C语言中用于优化数据存储与处理的技术,它允许程序员在结构体中对成员进行位级别的操作和管理。位段的主要应用包括节省内存空间、简化位操作处理以及提高数据处理效率。

首先,位段可以有效地节省内存空间。通过将多个成员变量打包在一个字节或更大的存储单元中,位段能够显著减少结构体的总体大小。这对于需要处理大量数据的后端应用程序来说尤为重要,因为降低内存占用可以提高性能。

其次,位段可以简化对位操作的处理。在处理二进制数据、网络协议、文件格式等任务时,位段能够将相关的位操作封装在结构体中,使代码更加清晰、可读性更高。通过位段,程序员可以使用适当的位掩码和位运算来访问和修改特定的位,而无需手动进行繁琐的位操作。

此外,位段在处理控制信息时特别有用。在数据通信领域,控制信息往往只占一个字节中的一个或几个二进制位。通过使用位段,可以将这些控制信息紧凑地存储在一个结构体中,方便进行读取和修改。

需要注意的是,位段的具体实现和内存布局可能因编译器和平台的不同而有所差异。不同的编译器可能会对位段进行不同的填充和对齐处理,这可能导致在不同的平台上,相同的位段定义可能会产生不同的内存布局和大小。因此,在使用位段时,程序员需要了解目标平台的特性和编译器的行为,并进行充分的测试以确保代码的正确性和可移植性。

总的来说,位段是一种强大的工具,可以用于优化数据存储和处理,提高程序的性能和可读性。然而,使用时需要谨慎处理平台依赖性和内存布局问题。
——文心一言3.5

6.4位段使用的注意事项

位段的几个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位
置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的。
所以不能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊
放在⼀个变量中,然后赋值给位段的成员。

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	struct A sa = {0};
	scanf("%d", &sa._b);//这是错误的
	//正确的⽰范
	int b = 0;
	scanf("%d", &b);
	sa._b = b;
	return 0;
}

文心一言3.5{
使用位段(bit-field)时,需要注意以下关键事项:

  1. 类型限制:位段的类型只能是整型家族的一部分,如int、unsigned int、signed int、char、unsigned
    char和signed char。不能使用浮点型或其他非整型类型。
  2. 位数限制:位段所占的二进制位数不能超过其所属基本类型所能表示的最大位数。例如,如果int类型在特定编译器或平台上占4个字节(32位),那么一个int类型的位段最多只能有32位。
  3. 访问与操作:无名位段不能被直接访问,但它们会占据内存空间。此外,不能对位段进行取地址操作,因为位段通常不是连续的存储单元。
  4. 长度为零的位段:长度为零的位段在定义中是有意义的,它强制下一个位段从新的存储单元开始。这对于控制位段的存储布局特别有用。
  5. 整型升级:当位段出现在表达式中时,它们会自动进行整型升级,转换为int或unsigned
    int类型。这意味着在进行算术运算或比较时,位段的行为类似于它们升级后的整型。
  6. 赋值范围:对位段赋值时,应确保不超过其所能表示的最大范围。超出范围的赋值可能导致数据丢失或不可预测的行为。
  7. 跨平台问题:位段的具体实现和内存布局可能因编译器和平台的不同而有所差异。不同的编译器可能会对位段进行不同的填充和对齐处理,导致相同的位段定义在不同的平台上可能产生不同的结果。因此,在使用位段进行跨平台编程时,需要特别小心。
  8. 数组形式的限制:位段不能定义为数组形式。这意味着你不能创建一个包含多个位段的数组。
  9. 速度与空间的权衡:位段的主要优势在于节省空间,但可能牺牲一些速度。这是因为位段的操作通常涉及更复杂的位运算和内存布局管理。
  10. 可移植性:由于位段的具体实现可能因编译器和平台而异,因此使用位段可能会降低代码的可移植性。在编写需要跨多个平台运行的代码时,应谨慎考虑是否使用位段。

总的来说,位段是一种强大的工具,可用于优化数据存储和处理。然而,它们也有一些限制和潜在问题,需要在使用时仔细考虑和处理。}

GPT 3.5{

在使用位段时,需要注意以下几个方面:

  1. 内存对齐:位段中的字段通常是按照位数进行定义的,因此需要考虑字段在内存中的对齐情况。确保每个字段都从正确的内存位置开始存储,以避免访问数据时出现错误或性能下降。

  2. 字段大小:定义位段时需要确保每个字段的大小是合适的,不要超出字段所能表示的范围。过大的字段可能会导致内存浪费,而过小的字段可能无法满足数据存储需求。

  3. 字段顺序:位段中的字段顺序通常会影响内存布局和数据访问的效率。需要根据实际需求合理安排字段的顺序,以便提高数据访问的效率。

  4. 跨平台兼容性:由于不同平台对于位段的实现可能存在差异,因此在跨平台开发时需要谨慎使用位段,以避免出现不同平台之间的兼容性问题。

  5. 可读性和维护性:位段的代码通常比较复杂,需要注意代码的可读性和维护性。建议添加详细的注释说明每个字段的含义和用途,以便他人能够理解和维护代码。

综上所述,使用位段时需要注意以上几个方面,以确保数据的正确存储和访问,并提高代码的可维护性和可读性。

}
感谢大家的阅读❤️,那么本期文章就到这里咯~~~
期待与你的下次相见!
Looking forward to seeing you all next time!

请添加图片描述
在这里插入图片描述
下期预告(联合和枚举)~~~

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

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

相关文章

皮肤科医生护肤误区揭秘:不洗脸变美的真相?

在信息过剩的社会&#xff0c;大家不断被各种护肤秘籍、美容宝典所包围。最近&#xff0c;“一周不洗脸皮肤变好”的话题引起热议&#xff0c;而紧随其后关于“女子为护肤一个月不洗脸&#xff0c;结果脸上结满痂痕险严重毁容”的新闻再次引发广泛关注。这让大家纷纷产生了疑惑…

对象存储服务MinIO快速入门

对象存储服务MinIO快速入门 MinIO简介开箱使用快速入门封装MinIO为starter1 创建模块heima-file-starter2 配置类3 封装操作minIO类4 对外加入自动配置5 其他微服务使用 MinIO简介 官网文档 开箱使用 docker run -p 9000:9000 --name minio -d --restartalways -e "MINIO…

“李子园”上榜中国民营企业社会责任优秀案例

日前&#xff0c;由浙江省工商联、浙江工商大学主办&#xff0c;杭州市工商联协办的2024浙江民营企业社会责任暨浙商ESG研讨会在杭州召开&#xff0c;探索民营企业履行社会责任的方法路径和趋势。会上公布了2023年中国民营企业社会责任优秀案例&#xff08;浙江入选企业&#x…

在线接口文档预言方案

在线接口文档预言方案 要求&#xff1a; ​ 支持自动生成接口文档 ​ 能够支持在线测试(http&#xff0c;websocket) ​ 对代码没有侵入性 一、目前涉及的相关技术收集 sudo apt update #更新数据 sudo apt upgrade #更新软件 sudo apt install openssh-server #下载安装…

使用certbot为网站启用https

1. 安装certbot客户端 cd /usr/local/bin wget https://dl.eff.org/certbot-auto chmod ax ./certbot-auto 2. 创建目录和配置nginx用于验证域名 mkdir -p /data/www/letsencryptserver {listen 80;server_name ~^(?<subdomain>.).ninvfeng.com;location /.well-known…

类的定义与实例化

一.类的定义 1.1 格式 定义类的一般格式如下&#xff1a; class 类名{ public:公有成员列表; protected:保护成员列表; private:私有成员列表; }; 构成元素&#xff1a; &#xff08;1&#xff09;类头&#xff08;class head&#xff09; “class 类名”称为类头。 &…

Java学习记录第十三天

面向对象编程 核心思想就是OOP&#xff08;面向对象编程&#xff09; 面向过程&面向对象 面向过程思想 步骤清晰简单&#xff0c;第一步做什么&#xff0c;第二步做什么... 面对过程适合处理一些较为简单的问题 面向对象思想 物以类聚&#xff0c;分类的思维模式&…

Docker常见软件部署2

1 docker 安装redis集群 docker 安装redis集群&#xff0c;3主3从的配置。 1 创建一个redis通信网卡 #创建一个redis集群使用的网卡 docker network create redis --subnet 172.38.0.0/16 2 创建6个redis的配置文件 #通过脚本创建六个redis配置&#xff0c;复制下面命令直接…

VTK——自定义二维图像涂抹Widget(支持任意值涂抹),擦除,恢复 vtkCustomPaintWidget

通过鼠标控制 涂抹区域&#xff0c;可以进行&#xff0c;后退&#xff0c;可以进行二维标注&#xff0c;也可以进行回退&#xff0c;也可以任意值涂抹。 vtkCustomPaintWidget 1.标注&#xff1a; 2.擦除 视频&#xff1a; 2D标注 vtkPaint VTK 2D 标注 描绘 2D 擦除&#x…

酒店能源监测管理系统:实现节能减排与提升管理效率的利器

随着全球能源问题的日益突出和可持续发展理念的深入人心&#xff0c;酒店业也在积极探索节能减排的途径。在这一背景下&#xff0c;酒店能源监测管理系统应运而生&#xff0c;成为了酒店行业提升管理效率、降低能源消耗的重要工具。本文将从多个角度介绍酒店能源监测管理系统的…

QT控件之显示控件

Qt Designer显示窗口部件提供的面板中&#xff0c;提供了10种显示小部件 &#xff08;1&#xff09; Label标签 &#xff08;2&#xff09; Text Browser文本浏览器 &#xff08;3&#xff09; Graphics View图形视图 &#xff08;4&#xff09; Calendar Widget日历 &…

【Pytorch入门】小土堆PyTorch入门教程完整学习笔记(详细笔记并附练习代码 ipynb文件)

小土堆PyTorch入门教程笔记 最近在观看PyTorch深度学习快速入门教程&#xff08;绝对通俗易懂&#xff01;&#xff09;【小土堆】顺便做点笔记&#xff0c;方便回看&#xff0c;同时也希望记录的笔记能够帮助到更多在入门的小伙伴~ 【注】仅记录个人觉得重要的知识&#xff0c…

Java项目:79 springboot海滨体育馆管理系统的设计与实现

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 体育馆管理系统主要实现了管理员功能模块和学生功能模块两大部分 管理员功能模块&#xff1a; 管理员登录后可对系统进行全面管理操作&#…

android安卓看书APP课设

一、引言 随着移动设备的普及和网络的发展&#xff0c;手机阅读成为了现代人获取知识和娱乐的重要途径之一。为了满足用户的阅读需求&#xff0c;我们设计并开发了一款安卓看书APP。本文将介绍该APP的设计理念、功能特点以及技术实现。 二、功能描述 1. 主页底部导航栏 为了…

免费|Python|【需求响应】一种新的需求响应机制DR-VCG研究

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序对应文章《Contract Design for Energy Demand Response》&#xff0c;电力系统需求响应&#xff08;DR&#xff09;用来调节用户对电能的需求&#xff0c;即在预测的需求高于电能供应时&#xff0c;希…

rtthread studio 基于bsp生成代码stm32l475正点原子潘多拉,以及硬件配置

1、基于bsp生成代码 rtthread studio 很强大的一个功能就是可以根据芯片或者bsp 生成驱动代码&#xff0c;而且rtthread内核 已经集成到了代码中&#xff01;&#xff01;只需要关注于如何使用硬件和设备完成我们想要的功能就可以&#xff1b; 它的官网文档也特别详细&#x…

银行监管报送系统介绍(十二):非居民金融账户涉税信息报送

国家税务总局、财政部、中国人民银行、中国银行业监督管理委员会、中国证券监督管理委员会、国家金融监督管理总局2017年5月9日发布、2017年7月1日起施行的《非居民金融账户涉税信息尽职调查管理办法》。 一、《管理办法》出台的背景是什么&#xff1f;   受二十国集团&…

算法---动态规划练习-8(打家劫舍2)

打家劫舍2 1. 题目解析2. 讲解算法原理3. 编写代码 1. 题目解析 题目地址&#xff1a;点这里 2. 讲解算法原理 首先&#xff0c;给定一个非负整数数组 nums&#xff0c;其中 nums[i] 表示第 i 家的财物价值。 定义两个辅助数组 f 和 g&#xff0c;长度都为 n&#xff08;n 是…

Java智慧工地源码 智慧工地的价值体现 开发一套智慧工地系统需要多少钱

智慧工地是智慧地球理念在工程领域的行业具现&#xff0c;是一种崭新的工程全生命周期管理理念。它运用信息化手段&#xff0c;通过三维设计平台对工程项目进行精确设计和施工模拟&#xff0c;围绕施工过程管理&#xff0c;建立互联协同、智能生产、科学管理的施工项目信息化生…

亲身体验!人工智能对话无障碍 —— BRClient 使用指南

01 概述 BRClient 这个名字来源于“Bedrock Client”的简称&#xff0c;寓意是为用户提供一个坚实的基础。BRClient 作为一个开源的桌面应用&#xff0c;为用户提供了友好的图形界面&#xff0c;让每个人都能够轻松访问和使用 Claude 3 的强大功能。用户可以自定义 Claude 3 的…