<C语言> 自定义类型

1.结构体

结构体是一种用户自定义的数据类型,允许将不同类型的数据项组合在一起,形成一个更大的数据结构。结构体可以包含多个成员变量,每个成员变量可以是不同的数据类型,如整数、字符、浮点数等,甚至可以包含其他结构体作为其成员。

复杂对象人:名字+年龄+电话+住址

结构体struct-描述复杂对象

1.1 结构体的声明

struct tag
{
 	member-list;
}variable-list;
  1. struct是关键字,用于声明一个结构体类型。tag是给这个结构体类型起的标识符,用于在后续代码中引用这个结构体类型。
  2. member-list表示结构体的成员列表,每个成员用一个数据类型和标识符定义。这些成员在结构体内部依次存储。
  3. variable-list 这个部分不是结构体的必须组成部分,但是可以用来在定义结构体的同时创建结构体变量。如果在定义结构体时不创建变量,可以忽略这部分。

例如描述一个人:

#include <stdio.h>

// 定义结构体类型
struct Person {
    char name[50];
    int age;
    float height;
} person1, person2; // 创建两个结构体变量 person1 和 person2,注意分号不可以缺少

int main() {
    // 初始化结构体变量
    struct Person person3 = {"John Doe", 30, 1.75};
    
    // 访问结构体成员
    printf("Name: %s\n", person3.name);
    printf("Age: %d\n", person3.age);
    printf("Height: %.2f meters\n", person3.height);
    
    return 0;
}

1.2 匿名结构体

匿名结构体是指在定义结构体变量时,省略结构体的名称,直接声明结构体变量并定义其成员。这种形式适用于一些临时或简单的数据组织需求,不需要为结构体类型起一个独立的名字。匿名结构体的作用范围仅限于当前代码块。

例如:

#include <stdio.h>

int main() {
    // 定义匿名结构体变量,并直接初始化
    struct {
        float length;
        float width;
    } rectangle = {5.0, 3.0}; // 创建结构体变量并初始化
    
    // 计算矩形的面积
    float area = rectangle.length * rectangle.width;
    
    printf("Rectangle Length: %.2f\n", rectangle.length);
    printf("Rectangle Width: %.2f\n", rectangle.width);
    printf("Rectangle Area: %.2f\n", area);
    
    return 0;
}

问题,下面的代码合法吗?

struct
{
    char book_name[20];
    char author[20];
    int price;
    char id[15];
} sb1, sb2;

struct
{
    char book_name[20];
    char author[20];
    int price;
    char id[15];
} *ps;

int main() {
    ps=&sb1;  //err,编译器会把上面的两个声明当成完全不同的两个类型。所以是非法的。
    return 0;
}

警告: 编译器会把上面的两个声明当成完全不同的两个类型。 所以是非法的。

总结:

匿名结构体适用于一些临时的数据组织,特别是在某个作用域内部且仅在局部范围使用的情况下,这样可以省略给结构体起一个名称的步骤,使得代码更加简洁和清晰。然而,对于需要在多个函数或多个地方使用的复杂数据结构,还是推荐使用带有名称的结构体类型。

1.3 结构体的自引用

结构体的自引用指的是结构体中包含指向相同类型结构体的指针成员,从而创建一个自循环的数据结构

链表结构就要利用结构体的自引用来实现:

typedef struct Node { //对struct Node重命名为Node
    int data;
    struct Node *next; //指向下个结点的地址,这里的struct不能省略
} Node;

int main() {
    Node n;
    return 0;
}

1.4 结构体变量的定义和初始化

struct Point{
    int x;
    int y;
} p1;            //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2

//初始化:定义变量的同时赋初值。
struct Point p3 = {1, 2};

struct Stu {       //类型声明
    char name[15]; //名字
    int age;       //年龄
};
struct Stu s = {"zhangsan", 20}; //初始化

结构体还可以嵌套初始化:

struct Node {
    int data;
    struct Point p;                 //4,5
    struct Node *next;              //NULL
} n1 = {10, {4, 5}, NULL};          //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化 

不按顺序初始化:

struct S {
    char c;
    int a;
    float f;
};

int main() {
    struct S s = {'w', 20, 3.14f};      //顺序初始化
    printf("%c %d %f\n", s.c, s.a, s.f);
    struct S s2 = {s2.f = 3.14f, s2.c = 'w', s2.a = 10};   //不按顺序初始化
    printf("%c %d %f\n", s.c, s.a, s.f);
    return 0;
}

注意:不按顺序初始化,VS可以 gcc编译器不支持

1.5 结构体成员的访问

可以使用点操作符(.)来访问结构体的成员。点操作符允许我们通过结构体变量来访问结构体内部的成员变量,使得我们可以读取或修改这些成员的值。如果结构体是指针类型,我们可以使用箭头操作符(->)来访问指向的内容。

例如以下结构体成员:

struct Stu{
	char name[20];
	int age;
};

struct Stu s;

我们可以看到 s 有成员 nameage

那我们如何访问s的成员?

struct S s;
strcpy(s.name, "zhangsan");//使用.访问name成员
s.age = 20;//使用.访问age成员

结构体指针访问指向变量的成员

有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针。

那该如何访问成员

如下:

struct Stu {
    char name[20];
    int age;
};

void print(struct Stu *ps) {
    printf("name = %s   age = %d\n", (*ps).name, (*ps).age);
    //使用结构体指针访问指向对象的成员
    printf("name = %s   age = %d\n", ps->name, ps->age);
}

int main() {
    struct Stu s = {"zhangsan", 20};
    print(&s);//结构体地址传参
    return 0;
}

使用(*ps)解引用后.操作访问,或者->直接访问

1.6 结构体传参

结构体可以按值传递或按指针传递给函数。在按值传递时,函数将接收到结构体的副本,对副本的修改不会影响原始结构体。在按指针传递时,函数将接收到结构体的地址,可以直接修改原始结构体的内容。

例如:

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

void print1(struct S s) {
    //传值比较浪费空间,可能会栈溢出
    printf("%d %d %d %d\n", s.data[0], s.data[1], s.data[2], s.num);// 1 2 3 100
}

void print2(struct S *ps) {
    //两种写法  推荐第二个
    printf("%d %d %d %d\n", (*ps).data[0], (*ps).data[1], (*ps).data[2], (*ps).num);// 1 2 3 100
    printf("%d %d %d %d\n", ps->data[0], ps->data[1], ps->data[2], ps->num);        // 1 2 3 100
}

int main() {
    struct S ss = {{1, 2, 3, 4, 5}, 100};
    print1(ss);
    print2(&ss);
    return 0;
}

上面的 print1print2 函数哪个好些?

答案是:首选print2函数。

原因:

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。

如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的 下降。

1.7 结构体内存对齐

结构体的内存对齐是编译器根据特定的规则将结构体成员按照一定的字节边界进行排列的过程。对齐的目的是为了优化内存访问效率,避免因为数据未对齐而导致的性能损失。对齐原则因编译器和体系结构而异

如何计算?

首先得掌握结构体的对齐规则:

1.第一个成员在与结构体变量偏移量为0的地址处。

2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

对齐数 = 编译器默认的一个对齐数与该成员大小的较小值VS中默认的值为8

3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

观察下面的结果:

#include <stddef.h>
#include <stdio.h>
struct S1 {
    char c1;
    int i;
    char c2;
};

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

int main() {
    //S1的偏移量
    printf("%d\n", offsetof(struct S1, c1));//0  c1从0开始
    printf("%d\n", offsetof(struct S1, i)); //4	 i从4开始
    printf("%d\n", offsetof(struct S1, c2));//8  c2从8开始 8+1字节=9字节,按4字节对齐=12
    
    printf("%d\n", offsetof(struct S2, c1));//0  c1从0开始
    printf("%d\n", offsetof(struct S2, c2));//1  c2从1开始  
    printf("%d\n", offsetof(struct S2, i)); //4  i从4开始  4+4=8字节,按4字节对齐=8

    printf("%d\n",sizeof(struct S1)); //12
    printf("%d\n",sizeof(struct S2)); //8
    return 0;
}

offsetof宏-用来计算结构体成员相对于起始位置的偏移量,头文件#include

练习:

struct S3 {
    double d;// 0 - 7
    char c;  // 8
    int i;   // 12-15
};

struct S4 {
    char c1;     // 0
    struct S3 s3;// 8-20   s3
    double d;    // 24-31
};

int main() {
    printf("%d\n", sizeof(struct S3));// 16
    printf("%d\n", sizeof(struct S4));// 32
    return 0;
}

首先,我们有两个结构体 struct S3struct S4

struct S3 中包含了三个成员:

  1. double d:占用8个字节(通常情况下是64位浮点数的大小)。
  2. char c:占用1个字节。
  3. int i:占用4个字节。

由于结构体中的成员变量的对齐数通常是成员本身大小和编译器默认对齐数(在Visual Studio中默认是8字节)中较小的值,所以每个成员都需要对齐到8字节的整数倍地址处。

所以 struct S3 的总大小是 8 + 1 + 4 = 13 字节。但由于对齐的需要,结构体的总大小会被调整为最大对齐数的整数倍,所以 sizeof(struct S3) 的结果为 16 字节。

接下来,我们看 struct S4

struct S4 中包含了两个成员:

  1. char c1:占用1个字节。
  2. struct S3 s3:占用 sizeof(struct S3) = 16 字节。

struct S4 中,由于 struct S3 s3 的是16字节,编译器默认对齐数是8字节,所以 double d 需要对齐到8字节的整数倍地址处。因此,在 struct S4 中,double d 的偏移量为 24 字节。

总字节大小为32字节,是8的对齐数,所以结果就是8字节

为什么存在内存对齐?

  • 平台原因(移植原因):

    不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

  • 2.性能原因:

    数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
    原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访
    问。

总体来说:

结构体的内存对齐是拿空间来换取时间的做法。

那在设计结构体的时候,我们既要满足对齐,又要节省空间,如何做到:

让占用空间小的成员尽量集中在一起。

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

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

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

1.8 修改默认对齐数

可以通过预处理指令来修改结构体的默认对齐数。在大多数编译器中,可以使用#pragma pack指令来实现这一点。

#pragma pack 指令允许你指定对齐数的大小,从而改变结构体成员在内存中的对齐方式。通常情况下,对齐数是编译器默认的一个值和该成员大小的较小值,但通过#pragma pack,你可以设置一个不同的对齐数。

例如,假设将默认对齐数设置为4字节,可以这样做:

#pragma pack(4)

struct YourStruct {
    // 结构体成员
};

#pragma pack() // 重置为默认对齐数

注意,修改对齐数可能会影响结构体的内存布局和性能。通常情况下,编译器的默认对齐数是为了在不同平台上实现最佳的内存对齐和访问效率。如果不是很确定需要修改对齐数,最好还是使用编译器的默认设置。

如果需要修改对齐数,建议只在必要时进行,并且要确保所有的相关代码都知道这个修改,以免引起不必要的问题。在修改对齐数时,最好先了解你的编译器支持的具体语法和特性,以便正确地使用#pragma pack指令。

#include <stdio.h>
#pragma pack(8)//设置默认对齐数为8
//8和成员大小最小-对齐数4
struct S1 {
    char c1;   //0
    int i;     //4
    char c2;   //9    对齐4为12
};

#pragma pack() //取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为1

//对齐数为1,成员大小为4,对齐数为1
struct S2 {
    char c1;   //0
    int i;     //1
    char c2;   //5      对齐数为1表示不对齐,大小为0到5=6
};

#pragma pack()//取消设置的默认对齐数,还原为默认

int main() {
    //输出的结果是什么?
    printf("%d\n", sizeof(struct S1));  //12
    printf("%d\n", sizeof(struct S2));  //6
    return 0;
}

2.结构体位段

结构体位段是一种特殊的结构体成员,允许你以位为单位定义成员的长度。它们用于有效地使用内存,特别是在需要处理硬件寄存器或二进制数据的情况下。结构体位段可以在结构体声明中指定成员的位宽,从而使得这些成员只占用特定数量的位而不是整个字节。

位段的声明和结构是类似的,有两个不同:

1.位段的成员必须是 int、unsigned int或signed int 。

2.位段的成员名后边有一个冒号和一个数字。

比如:

struct S {
    int a;
    int b;
    int c;
    int d;
};

//A是位段-其中的位其实是二进制位
struct A {
    //先开辟了4byte - 32bit
    int _a : 2; // a成员只需要2个比特位  32-2 = 30
    int _b : 5; // b成员只需要5个比特位  30-5 = 25
    int _c : 10;// c成员只需要10个比特位 25-10 = 15    剩余的15个字节怎么使用由编译器决定
    int _d : 30;// d成员只需要30个比特位  还剩15 不够用 又开辟了四个字节的空间  一共8个字节
};

int main() {
    printf("%d\n", sizeof(struct S));// 16
    printf("%d\n", sizeof(struct A));// 8
    return 0;
}

2.1 位段的内存分配

  • 位段的成员可以是 int/unsigned int/signed int 或者是 char (属于整型家族)类型
  • 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
  • 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

一个例子:

struct S
{
    char a : 3;  //一个字节8个比特  8-3 = 5 还有五个比特
    char b : 4;  //5-4  还剩1个比特  再开辟一个字节空间
    char c : 5;  //5  //还剩下3个比特  又开辟一个空间
    char d : 4;  //4
};

int main()
{
    printf("%d\n", sizeof(struct S)); // 3
    struct S s = {0};
    s.a = 10;  //10的二进制 1010  但是a位段位3   只能放三位  00000010
    s.b = 12;  //1100  1字节变成01100010 = 十六进制62
    s.c = 3;   //0011    00000011 - 03
    s.d = 4;   //0100    00000100 - 04
    //内存中对应62 03 04 
    return 0;
} 

在这里插入图片描述

2.2 位段的跨平台问题

  1. int位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的。

总结:

跟结构相比,位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。

3.枚举

枚举(Enum)是一种用户定义的数据类型,用于表示一组具名的整数常量。枚举允许程序员为不同的值指定有意义的名字,使得代码更加清晰和易读。

比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举。

性别有:男、女、保密,也可以一一列举。

月份有12个月,也可以一一列举

3.1 枚举类型的定义

语法如下:

enum enumName {
    value1,
    value2,
    value3,
    // more values...
};

在枚举中,enumName 是枚举类型的名称,value1, value2, value3, … 是枚举常量。每个常量都隐式地被赋予一个整数值,其值默认从0开始递增。当然在定义的时候也可以赋初值。

例如:

enum Color//颜色
{
    RED = 1,
    GREEN = 2,
    BLUE = 4
};

枚举类型的大小?

枚举类型在C语言中的大小取决于编译器的实现和平台的架构。虽然C标准没有规定具体的枚举类型大小,但大多数编译器将枚举实现为整数类型(通常是intunsigned int),以便能够容纳枚举中定义的所有常量值。

通常情况下,枚举类型的大小是整数类型的大小,即通常为4个字节(32位平台)或8个字节(64位平台)。

3.2 枚举类型的优点

为什么使用枚举?

我们可以使用 #define 定义常量,为什么非要使用枚举?

#define Red 5
#define Green 7
#define Blue 10
int main(){
	int num = Red;
	return 0;
}

define预处理后define命令就消失了替换成了数字 ,不方便调试

枚举的优点:

1.增加代码的可读性和可维护性

2.和#define定义的标识符比较枚举有类型检查,更加严谨

3.便于调试

4.使用方便,一次可以定义多个常量

5.防止命名污染(封装)

3.3 枚举的使用

enum Color {
    //枚举的可能取值
    //每一个可能的取值是常量
    Red,
    Green,
    Blue
    //Red = 5
    //Red = 9
    //Red = 10
};

int main() { 
    enum Color color = Blue;   //只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
    //enum Color color = 5;    //C语言支持, C++会有警告
    //Red = 2;   //常量不可修改
    int num = Red;
    printf("%d\n", num);               //0
    printf("%d\n", Red);               //0
    printf("%d\n", Green);             //1
    printf("%d\n", Blue);              //2
    int sum = Red + Blue;              //可以相加,但是有些编译器不支持
    printf("%d\n", sum);               //2
    printf("%d\n", sizeof(enum Color));//VS中为4
    
    return 0;
}

注意:枚举常量不可修改

4.联合体(共用体)

联合体(Union)是一种特殊的数据类型,允许在同一块内存空间中存储不同类型的数据。与结构体不同,联合体的成员共享同一块内存,但每次只有一个成员是有效的。联合体的大小取决于其成员中最大的成员大小。

定义联合体的语法如下:

union unionName {
    memberType member1;
    memberType member2;
    // more members...
};

在联合体中,unionName 是联合体类型的名称,member1, member2, … 是联合体的成员。每个成员都可以是不同的数据类型,但它们共享相同的内存空间。

4.1 联合体的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

实例如下:

#include <stdio.h>
union Un {
    char c;
    int i;
    double d;
};


int main() {
    union Un un;
    printf("%p\n", &un);    //000000000061FE18
    printf("%p\n", &(un.c));//000000000061FE18
    printf("%p\n", &(un.i));//000000000061FE18
    printf("%p\n", &(un.d));//000000000061FE18
    //地址相同
    printf("%d\n", sizeof(union Un));//8个字节
    return 0;
}

下面输出的结果是什么?

un.i = 0x11223344;
un.c = 0x55;
printf("%x\n", un.i); 

结果:11223355

在这个代码中,首先将0x11223344赋给了un.i,这将整数的所有4个字节设置为十六进制的11 22 33 44。然后,将0x55赋给了un.c,这只会将整数的第一个字节设置为十六进制的55。由于整数的第一个字节先前已设置为11,因此在赋值后它变为了55。因此,当打印出un.i的值时,它将等于十六进制的11223355

4.2 联合体大小计算

  • 联合体的大小取决于它包含的成员中最大的数据类型的大小。
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

比如:

union Un {
    char arr[5];//5 对齐数为1
    int i;      //4
};

union Un1 {
    short s[7];//14
    int i;     //4
};

int main() {
    printf("%zu\n", sizeof(union Un)); //联合体大小为5,对齐4的倍数为8
    printf("%zu\n", sizeof(union Un1));//联合体大小为14,对齐4的倍数为16
    return 0;
}

4.3 联合体求大小端

一个数值,存储时需要的内存空间只要超过1个字节,就涉及顺序的问题

0x 11 22 33 44

联合体求大小端

int check_sys() {
    union {
        char c;
        int i;
    } u;

    u.i = 1;   //联合体公用一块空间 i的空间小端存储为 01 00 00 00
    return u.c;//return返回 c  c为1个字节 就是1  如果是大端返回0
}

int main() {
    int ret = check_sys;
    if (ret == 1)
        printf("小端\n");
    else
        printf("大端\n");
}

成员中最大的数据类型的大小。

  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

比如:

union Un {
    char arr[5];//5 对齐数为1
    int i;      //4
};

union Un1 {
    short s[7];//14
    int i;     //4
};

int main() {
    printf("%zu\n", sizeof(union Un)); //联合体大小为5,对齐4的倍数为8
    printf("%zu\n", sizeof(union Un1));//联合体大小为14,对齐4的倍数为16
    return 0;
}

4.3 联合体求大小端

一个数值,存储时需要的内存空间只要超过1个字节,就涉及顺序的问题

0x 11 22 33 44

联合体求大小端

int check_sys() {
    union {
        char c;
        int i;
    } u;

    u.i = 1;   //联合体公用一块空间 i的空间小端存储为 01 00 00 00
    return u.c;//return返回 c  c为1个字节 就是1  如果是大端返回0
}

int main() {
    int ret = check_sys;
    if (ret == 1)
        printf("小端\n");
    else
        printf("大端\n");
}

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

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

相关文章

数据可视化——根据提供的数据,将数据经过处理后以折线图的形式展现

文章目录 前言处理数据获取数据筛选数据将JSON数据转换为Python数据筛选出横坐标数据和纵坐标数据 根据处理后的数据绘制折线图整体代码展示 前言 前面我们学习了如何使用 pyecharts 模块绘制简单的折线图&#xff0c;那么今天我将为大家分享&#xff0c;如何根据提供的数据将…

Python+Qt窗体或Django网页支付宝收款码-扫码付款实例

程序示例精选 PythonQt窗体或Django网页支付宝收款码-扫码付款实例 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<PythonQt窗体或Django网页支付宝收款码-扫码付款实例>>编写代…

Nautlius Chain主网正式上线,模块Layer3时代正式开启

Nautilus Chain 是在 Vitalik Buterin 提出 Layer3 理念后&#xff0c; 对 Layer3 领域的全新探索。作为行业内首个模块化 Layer3 链&#xff0c;我们正在对 Layer3 架构进行早期的定义&#xff0c;并有望进一步打破公链赛道未来长期的发展格局。 在今年年初&#xff0c;经过我…

【7天学GO】第1章 开发环境

1.1 开篇介绍(必看) A. Why choose the go language B. 学语言阶段 1.2 环境搭建前戏 A. 学习一门语言步骤 B. 编译型与解释型 1.3 mac系统Go开发环境搭建 (略) 1.4 linux系统Go开发环境搭建 (略) 1.5 windows系统Go开发环境搭建 A. 开发环境搭建 Stage 1&#xff1a…

Spring整合Junit

Spring整合Junit 在之前文章中Spring的测试方法几乎都能够看到如下的代码&#xff1a; ApplicationContext context new ClassPathXmlApplicationContext("xxx.xml"); XXX xxx context.getBean(XXX.class);它的作用是创建Spring容器&#xff0c;最终获取到对象&…

【前端知识】React 基础巩固(二十六)——Portals 的使用

React 基础巩固(二十六)——Portals 的使用 Portals 通常&#xff0c;组件会渲染到 root 节点下。可使用 Portals 将组件渲染至其他节点。 添加 id 为 more、modal 的 div 元素 <div id"root"></div> <div id"more"></div> &l…

第六章:U-Net——医学图像分割的卷积神经网络

0.摘要 大多数人都认为成功训练深度网络需要成千上万个注释训练样本。在本文中&#xff0c;我们提出了一种网络和训练策略&#xff0c;依靠强大的数据增强来更有效地利用现有的注释样本。该架构由一个收缩路径和一个对称扩展路径组成&#xff0c;收缩路径用于捕捉上下文…

如何下载SRA存放在AWS的原始数据

通常&#xff0c;我们都是利用prefetch从NCBI上获取数据&#xff0c;然后用fasterp-dump/fastq-dump 转成fastq。但遗憾的SRA的数据是原数据的有损压缩&#xff0c;比如说我19年参与发表的文章里单细胞数据上传的是3个文件&#xff0c;但是当时的faster-dump/fastq-dump只能拆出…

Qt与Web混合开发:实现双向通信

引言 在当今的软件开发中&#xff0c;将Qt和Web技术结合起来进行混合开发变得越来越流行。Qt作为强大的C框架&#xff0c;提供了丰富的图形界面和功能库&#xff0c;而Web技术则提供了灵活性和跨平台的优势。结合这两种技术&#xff0c;我们可以开发出功能强大、具有吸引力的应…

自动驾驶代客泊车AVP摄像头与ECU交互需求规范

目录 1 文档范围及控制方法... 5 1.1 目的.... 5 1.2 文档授权... 5 1.3 文档变更管理... 5 1.4 缩写.... 5 1.5 术语.... 5 2 系统组成... 6 2.1 系统框图... 6 2.2 电源供应和时序要求... 7 2.2.1 摄像头供电控制... 7 2.2.2 摄像头上电时序要求…

数据结构--图的基本操作

数据结构–图的基本操作 使用的存储模式&#xff1a; 图的基本操作&#xff1a; • Adjacent(G,x,y)&#xff1a;判断图G是否存在边<x, y>或(x, y)。 • Neighbors(G,x)&#xff1a;列出图G中与结点x邻接的边。 • InsertVertex(G,x)&#xff1a;在图G中插入顶点x。 • …

【贪心算法Part03】| 1005.K次取反后最大化的数组和、134.加油站、135.分发糖果

目录 &#x1f388;LeetCode1005.K次取反后最大化的数组和 &#x1f388;LeetCode134.加油站 &#x1f388;LeetCode135.分发糖果 &#x1f388;LeetCode1005.K次取反后最大化的数组和 链接&#xff1a;1005.K次取反后最大化的数组和 给你一个整数数组 nums 和一个整数 k…

深入篇【C++】谈vector中的深浅拷贝与迭代器失效问题

深入篇【C】谈vector中的深浅拷贝与迭代器失效问题 Ⅰ.深浅拷贝问题1.内置类型深拷贝2.自定义类型深拷贝 Ⅱ.迭代器失效问题1.内部迭代器失效2.外部迭代器失效 Ⅰ.深浅拷贝问题 1.内置类型深拷贝 浅拷贝是什么意思&#xff1f;就是单纯的值拷贝。 浅拷贝的坏处&#xff1a; ①…

java项目之班级同学录网站(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的班级同学录网站。技术交流和部署相关看文章末尾&#xff01; 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&a…

基于STM32的homeassistant(采用FreeRTOS操作系统)【第一、二章优化拓展:Wifi、服务器连接验证以及UASRT串口区分】

第一、二章优化拓展开发环境&#xff1a; 主控STM32F103C8T6WIFI模块ESP01S开发语言C开发编译器 KEIL 组网方式WIFI服务器协议MQTT 硬件连接 STM32ESP01S3.3V3.3V GND GND GPIO2 (USRAT2-TX) RXGPIO3 (USART3-RX)TX 本章要点&#xff1a; 对ESP01S的AT指令的反馈指令进…

Kafka消息监控管理工具Offset Explorer的使用教程

1、kafka监控管理工具 Offset Explorer是一款用于监控和管理Apache Kafka集群中消费者组偏移量的开源工具。它提供了一个简单直观的用户界面&#xff0c;用于查看和管理Kafka消费者组偏移量的详细信息。 Offset Explorer具有以下主要功能和特点&#xff1a; 实时监控&#x…

Java开发中使用sql简化开发

引语&#xff1a; 在Java开发中&#xff0c;我们更希望数据库能直接给我们必要的数据&#xff0c;然后在业务层面直接进行使用&#xff0c;所以写一个简单的sql语句有助于提高Java开发效率&#xff0c;本文由简单到复杂的小白吸收&#xff0c;还请多多指教。 使用MySQL数据库…

微服务系列文章 之 SpringCloud中遇到的一些bug

1、There was a problem with the instance info replicator 错误原因&#xff1a; 该服务尝试将自己作为客服端注册解决办法&#xff1a; 在application.yml配置文件中&#xff0c;设置 # 注册Eureka服务 eureka:client:# Eureka服务注册中心会将自己作为客户端来尝试注册它自…

Unity基础 弹簧关节SpringJoint

弹簧关节 在游戏开发中&#xff0c;物体之间的交互性是非常重要的。为了模拟现实世界中的弹性特性&#xff0c;Unity提供了弹簧关节&#xff08;Spring Joint&#xff09;组件。通过弹簧关节&#xff0c;我们可以轻松实现物体之间的弹性交互效果。本文将详细介绍Unity中的弹簧…

OpenCv之Canny

目录 一、自适应阈值 二、边缘检测Canny 一、自适应阈值 引入前提:在前面的部分我们使用是全局闻值&#xff0c;整幅图像采用同一个数作为闻值。当时这种方法并不适应与所有情况&#xff0c;尤其是当同一幅图像上的不同部分的具有不同亮度时。这种情况下我们需要采用自适应闻…