当前位置: 首页 > news >正文

【C语言进阶】结构体、位段、枚举、以及联合(共用体)的相关原理与使用

在这里插入图片描述

​📝个人主页:@Sherry的成长之路
🏠学习社区:Sherry的成长之路(个人社区)
📖专栏链接:C语言进阶
🎯长路漫漫浩浩,万事皆有期待

文章目录

  • 1.结构体
    • 1.1 概述:
    • 1.2 结构的声明:
    • 1.3 特殊声明:
    • 1.4 结构的自引用:
    • 1.5 结构的定义与初始化:
    • 1.6 `重点`结构体内存对齐:
    • 1.7 修改默认对齐数:
    • 1.8 结构体传参:
  • 2.位段
    • 2.1 位段概述:
    • 2.2 位段的内存分配:
    • 2.3 位段的跨平台问题:
  • 3.枚举
    • 3.1 定义:
    • 3.2 枚举类型的优点:
    • 3.3 枚举类型的使用:
  • 4.联合(共用体)
    • 4.1 联合类型的定义:
    • 4.2 联合类型的特点:
    • 4.3 联合类型大小的计算:
  • 5.总结:

1.结构体

1.1 概述:

C 语言允许用户自己指定这样一种数据结构,它由不同类型的数据组合成一个整体,以便引用,这些组合在一个整体中的数据是互相联系的,这样的数据结构称为结构体,它相当于其它高级语言中记录。结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

1.2 结构的声明:

以描述 “ 学生 ”为例:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
//结构体的声明:
struct student
{char name[20];int age;char sex[5];float score;
}s1,s2;
//定义结构体变量s1、s2
//此处定义的结构体变量是全局的
struct student s3, s4;
//定义结构体变量s3、s4
//此处定义的结构体变量等同于声明时定义,也是全局的
int main()
{struct student s5, s6;//定义结构体变量s5、s6//此处定义的结构体变量是局部的return 0;
}

1.3 特殊声明:

关于结构体的不完全声明,即匿名结构体类型

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct
//没有声明结构体标签,即为匿名结构体类型
{char name[20];int age;char sex[5];float score;
}student = { "Zhang",21,"Man",91.7 };
//匿名结构体类型必须在生声明的同时进行定义int main()
{printf("%s %d %s %.1f\n", student.name, student.age, student.sex, student.score);return 0;
}

我们把这种在声明时省略掉结构体标签的结构体称为匿名结构体类型,在使用这种方式进行声明时,由于没有声明结构体标签,导致一旦该结构体结束声明,将无法再次进行定义,所以对于该类型的结构体来说,就必须在声明结构体的同时进行定义(可以不初始化)
再来看下面这个例子:

//结构体类型1:
struct
{char name[20];int age;char sex[5];float score;
}x;//结构体类型2:
struct
{char name[20];int age;char sex[5];float score;
}*p;

在这个示例中,虽然两个结构体类型内的结构体成员完全一样,但因为两者都使用了匿名结构体的声明方式,编译器会把上面的两个声明当成完全不同的两个类型
于是在下面的代码中将被视为非法

p = &x; 
//一种类型的指针指向另一种不同类型,将被视为非法

1.4 结构的自引用:

结构的自引用就是指结构体在自己的声明中引用了自己的一种声明方式。

struct Test
{int data;struct Test n;
};
int main()
{struct Test n;return 0;
}

我们说这种引用方式是非法的。这是因为,当我们这样进行引用后,在我们定义结构体变量时,会进行自引用,但在自引用中又嵌套了对自身的引用,如此循环往复,而编译器并不知道该在何时停止自引用。

正确的自引用形式:

struct Test
{int data;struct Test* NEXT;//使用指针指向确定的引用空间
};
int main()
{struct Test n;return 0;
}

当我们在进行结构体变量的定义时同样进行了自引用,不同的是这一次我们使用了一个指针,指向了下一个结构体变量的空间,而在这次指向之后,指针指向的空间被固定,不再指向其它空间,如此就实现了真正的结构体自引用。
同时,我们还可以结合关键字 typedef 进行使用:

typedef struct Test
{int data;struct Test* NEXT;//但在这里必须仍使用struct Test//在结构体声明结束后才会进行重命名
}Test;
//使用tepydef关键字,将struct Test类型重命名为Test类型int main()
{Test n;//经过重命名,在进行定义时可以直接使用重命名后的类型名进行定义return 0;
}

我们可以结合关键字 typedef 来将我们声明的结构体变量进行重命名,方便我们对结构体变量定义与初始化。但要注意的是,在使用 typedef 时,在结构体声明内部进行自引用时,仍需写成完全形式,这是因为,只有在结构体声明结束后才会对我们声明的结构体类型进行重命名

1.5 结构的定义与初始化:

举个例子:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
struct student
{char name[20];int age;char sex[5];float score;}s1 = { "Zhang",21,"Man",98.4 };
//初始化结构体变量s1,此处的结构体变量是全局的struct student s2 = { "Wang",20,"Woman",99.5 };
//初始化结构体变量s2,此处初始化的结构体变量等同于声明时初始化,也是全局的int main()
{struct student s3 = { "Jiao",21,"Man",67.2 };//初始化结构体变量s3,此处的结构体变量是局部的printf("%s %d %s %.1lf\n", s1.name, s1.age, s1.sex, s1.score);printf("%s %d %s %.1lf\n", s2.name, s2.age, s2.sex, s2.score);printf("%s %d %s %.1lf\n", s3.name, s3.age, s3.sex, s3.score);return 0;
}

1.6 重点结构体内存对齐:

经过上面的学习,我们就已经基本掌握了结构体的使用了。接下来我们将要深入研究结构体大小的计算过程,即结构体内存对齐,而这也是近年来的热门考点。
先来看看下面这段计算结构体变量大小的代码:

#include<stdio.h>
struct test1
{char a;int b;char c;
}test1;
struct test2
{char d;char e;int f;
}test2;
int main()
{printf("The size of test1 is %d\n", sizeof(test1));printf("The size of test2 is %d\n", sizeof(test2));return 0;
}

我们将其编译运行起来看看结果:

The size of test1 is 12
The size of test1 is 8

我们看到,实际的计算结果与我们的猜想大相径庭,那么到底是哪里出现了问题呢?这就是我们在这里需要研究的内容:结构体内存对齐
要想弄清楚究竟是如何进行结构体变量大小计算的,我们首先得掌握

结构体的对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处。(偏移量:该成员的存放地址与结构体空间起始地址之间的距离)
  2. 其他成员变量要对齐到对齐数的整数倍的地址处。
  3. 对齐数 = 编译器默认的一个对齐数与该成员大小的较小值。
  4. 对齐数在VS中的默认值为8
  5. 结构体总大小为最大对齐数的整数倍
  6. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数的整数倍。

知晓了结构体的对齐规则,我们再回过头来分析上面的结构体变量大小计算过程。
分析如图:
在这里插入图片描述
但是我们发现,这样的方式造成了很大程度上的空间浪费,以 test1 为例,12个字节的大小中有六个字节的空间申请了但却没有被使用。那么为什么还要采用这样的办法呢?

主要有以下两个原因:

  1. 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  2. 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。通俗来说结构体的内存对齐就是一种用空间换时间的处理方法。而我们能做的,就只有以上面的 test1 与 test2 为例,尽可能的选取 test2 这样,使占用空间小的成员尽可能的集中在一起。

1.7 修改默认对齐数:

在我们的代码编写过程中,默认的对齐数可能会不够合适。而当这个时候,我们就可以通过使用下面这个预处理指令来修改我们的默认对齐数:

#pragma pack(8)
//修改默认对齐数为8

我们也可以通过该指令在修改过默认对齐数之后,取消设置的默认对齐数,将其还原:

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

1.8 结构体传参:

结构体传参与函数传参类似,我们直接来看下面的示例:

#include<stdio.h>
struct TEST
{int data[1000];int num;
};
struct TEST test = { {1,2,3,4}, 1000 };
//结构体传参
void Print1(struct TEST test)
{printf("%d\n", test.num);
}
//结构体地址传参
void Print2(struct TEST* p)
{printf("%d\n", p->num);
}
int main()
{Print1(test);  //传结构体Print2(&test); //传地址return 0;
}

而在上面这段代码中,我们一般认为 Print2 函数更为优秀。原因是当函数传参的时候,参数是需要压栈的,在这个过程中就会产生时间和空间上的系统开销。如果传递一个结构体对象时结构体过大,那么将会导致参数压栈的的系统开销较大,最终将会导致程序性能的下降。

2.位段

结构体实现位段

2.1 位段概述:

位段(bit-field)以位为单位来定义结构体(或联合体)中的成员变量所占的空间。含有位段的结构体(联合体)称为位段结构。采用位段结构既能够节省空间,又方便于操作

位段的声明和结构体十分相似,但同时有两个不同点:

  1. 位段的成员必须是 intsigned intunsigned intchar 类型。
  2. 位段的成员名后边有一个冒号和一个数字(该成员所占内存空间大小,单位为 bit位)。
#include<stdio.h>
struct test
{int _a : 2;//成员 a 只占用 2 个比特位signed int _b : 5;//成员 b 只占用 5 个比特位unsigned int _c : 10;//成员 c 只占用 10 个比特位char _d : 4;//成员 d 只占用 4 个比特位
};
int main()
{printf("The size of struct test is %d\n", sizeof(struct test));//4return 0;
}

优点:能够节省大量的空间,通过有条件地(根据实际使用需求)限制每个变量所占内存空间的大小,从而减少了整体结构的空间占用

2.2 位段的内存分配:

位段存在的意义便是最大程度上去减少空间的浪费,所以在进行存储时,位段不会进行内存对齐操作。那么位段的内存空间是如何进行分配的呢?
注意位段的内存分配并没有严格的规则,在不同的编译器上产生的结果可能不同,我们今天的讲解,将以Visual Studio 2019 为例进行研究。

首先需要知道位段进行内存分配的规则:
1. 位段的成员可以是 intunsigned intsigned int 或者是 char(属于整形家族)类型
2. 位段的空间上是按照需要以4个字节( int )或者1个字节( char )的方式来开辟的。
3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。
4. 位段的内存分配是逐4字节(一个 int 类型的大小)进行分配的。
5. 当字节内空间不足以放下下一个成员变量时,剩余的空间不再使用,而是再从内存中申请一个字节的空间继续分配。
6. 不同类型(charint类型)数据进行存储时将会另起4个字节(一个 int 类型的大小)进行存储。
#include<stdio.h>
struct test
{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;
}

分析如图:
在这里插入图片描述在这里插入图片描述

至此,该位段结构的内存分配结束,共占据3个char 类型数据的大小,即 3 个字节

2.3 位段的跨平台问题:

我们上面说过,位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段,并且在未来位段结构的使用过程中,我们一定要提前仔细地研究好位段在不同编译器下使用时,究竟是如何进行内存分配的,再结合我们的实际需求实现跨平台使用。

而在位段进行跨平台使用时,我们通常需要注意以下四个关键点:

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

总结下来,跟结构相比,位段可以达到跟结构相同的效果,并且可以更好的利用空间,但同时存在着跨平台问题

3.枚举

枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常但不总是重叠。是一个被命名的整型常数的集合。简单来说就将某种特定类型的对象一一进行列举。
枚举的声明与结构和联合相似, 其形式为:

enum 枚举名{
标识符(=整型常数),
标识符(=整型常数),

标识符(=整型常数)
} 枚举变量;

3.1 定义:

#include<stdio.h> 
//枚举类型1:
enum Sex
{MALE,FEMALE,SECRET
}s1 = MALE;
//声明时进行定义与初始化(全局)
enum Sex s2 = FEMALE;
//枚举类型2:
enum Day
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
int main()
{enum Day s3 = Mon;//定义与初始化(局部)return 0;
}

我们可以看到,枚举类型的声明、定义与初始化与结构十分类似。然后我们再来看一看枚举类型内部各成员的值,我们以日期为例:

#include<stdio.h>
enum Day
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};
int main()
{//打印各成员的值:printf("The value of Mon  is %d\n", Mon);printf("The value of Tues is %d\n", Tues);printf("The value of Wed  is %d\n", Wed);printf("The value of Thur is %d\n", Thur);printf("The value of Fri  is %d\n", Fri);printf("The value of Sat  is %d\n", Sat);printf("The value of Sun  is %d\n", Sun);return 0;
}

将上面这个示例编译运行起来看看结果的反馈:
在这里插入图片描述
我们看到,枚举类型内部各成员的默认值是从 0 开始依次递增的。
但是成员的值不仅限于默认值,同时也允许我们在定义时给各成员附合适的初值:

#include<stdio.h>
enum Day
{Mon,Tues=5,Wed,Thur,Fri,Sat=15,Sun
};
int main()
{printf("The value of Mon  is %d\n", Mon);printf("The value of Tues is %d\n", Tues);printf("The value of Wed  is %d\n", Wed);printf("The value of Thur is %d\n", Thur);printf("The value of Fri  is %d\n", Fri);printf("The value of Sat  is %d\n", Sat);printf("The value of Sun  is %d\n", Sun);return 0;
}

在这里插入图片描述
我们可以依照上面这种方式对枚举类型成员的初值进行修改:
我们看到,经过修改本应按序赋值为 1 的枚举成员 Tues 被赋值成了 5 ,于是接下来的成员就从 5 开始依次赋值,直到成员 Sat 被赋值为 15 后,接下来的成员就从 15 开始依次递增。

3.2 枚举类型的优点:

枚举类型的成员均为常量,不可在使用中被修改,那么我们同样可使用宏 #define 去定义常量,为什么非要使用枚举类型呢?
这是因为,相比于宏,枚举类型具有很多优点:

优点:

  1. 增加代码的可读性和可维护性。
  2. 和 #define 定义的标识符相比较,枚举有类型检查,更加严谨。
  3. 防止了命名污染(通过封装实现)。
  4. 便于调试。
  5. 使用方便,一次可以定义多个常量。

3.3 枚举类型的使用:

同时我们要注意,在使用枚举类型时只能用枚举常量给枚举变量赋值,只有这样才不会出现类型差异:

#include<stdio.h> 
//声明枚举类型
enum TEST
{test1,test2,test3
};
//其中test1、test2、test3为枚举常量
int main()
{//定义枚举变量:enum TEST t;//使用枚举常量给枚举变量赋值:t = test3;//验证赋值结果:printf("The value of t is %d\n", t);return 0;
}

4.联合(共用体)

在进行某些算法的编程的时候,需要将几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术使几个变量互相覆盖。这种几个不同的变量共同占用一段内存的结构,在C语言中,被称作 “ 联合体 ” 类型结构,简称联合,也叫共用体。

4.1 联合类型的定义:

联合是一种特殊的自定义类型,这种类型定义的变量也包含有一系列的成员,但不同的是这些成员共用同一块空间(也被称作共用体)
它的定义也基本与结构体一致:

#include<stdio.h>
union TEST
{char a;int b;
}test;
//在定义联合体的同时定义联合体变量test
int main()
{//查看联合体的占用空间:printf("The size of test is %d\n", sizeof(test));//查看联合体成员的存储地址:printf("The address of test is %p\n", &test);printf("The address of   a  is %p\n", &test.a);printf("The address of   b  is %p\n", &test.b);return 0;
}

在这里插入图片描述

但不同的是,我们编译运行后发现,联合体成员 char 类型变量 a 与 int 类型变量 b 共同占用同一片空间(一个 int 类型所占的空间):
这种方式定义的联合体结构,是三种结构中最节省空间的一种,但同时,极致的空间节省能力导致了它在使用时需要满足的条件极为苛刻。

4.2 联合类型的特点:

联合体最大的特点就是,联合体的成员是共用同一块内存空间的,则联合至少得有足够的空间容纳最大的成员,这样一个联合变量的大小就至少得是最大成员的大小。
既然联合体的大小会随着内部成员大小的变化而变化,那么是不是联合体类型也可以通过判断内容大小,来帮助我们判断机器的大小端存储模式呢?

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int check_sys()
{union CHECK{char check1;int check2;}check;check.check2 = 1;return check.check1;
}int main()
{if (1 == check_sys()){printf("您的机器采用小端存储模式!\n");}else{printf("您的机器采用大端存储模式!\n");}return 0;
}

在这里插入图片描述

我们将其编译运行发现,该思路可以帮助我们检查机器的大小端存储模式

4.3 联合类型大小的计算:

联合体类型的大小计算需要按照以下规则进行计算

  1. 联合的大小至少是最大成员的大小。
  2. 当最大成员大小不是最大对齐数的整数倍时,要对齐到最大对齐数的整数倍。
#include<stdio.h>
//联合体1:
union TEST1
{char c[5];int i;
};
//联合体2:
union TEST2
{short c[7];int i;
};
int main()
{//检查联合体的大小:printf("The size of TEST1 is %d\n", sizeof(union TEST1));printf("The size of TEST2 is %d\n", sizeof(union TEST2));return 0;
}

1.在联合体 TEST1 中,占用空间最大的成员是 char 类型数组 c ,且其中含有 5 个元素,则其所占空间大小为 5 个字节,而我们都知道 VS 的对齐数默认为 8 ,则将会对齐至默认对齐数的整数倍,即 8 个字节。
2.而联合体 TEST2 中,占用空间最大的成员是 short 类型数组 c ,且其中含有 7 个元素,则其所占空间的大小为 14 个字节,那么就将会对齐至对齐数的整数倍,即 16 个字节

5.总结:

今天我们对结构体的相关原理与使用等知识又有了新的了解,学习了结构体、位段、枚举、以及联合(共用体)的相关知识,完成了通过联合体类型判断机器的大小端存储模式,希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

在这里插入图片描述

相关文章:

【C语言进阶】结构体、位段、枚举、以及联合(共用体)的相关原理与使用

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C语言进阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录1.结构体1.1 概述&a…...

《蓝桥杯每日一题》哈希·AcWing 2058. 笨拙的手指

1.题目描述每当贝茜将数字转换为一个新的进制并写下结果时&#xff0c;她总是将其中的某一位数字写错。例如&#xff0c;如果她将数字 14 转换为二进制数&#xff0c;那么正确的结果应为 1110&#xff0c;但她可能会写下 0110 或 1111。贝茜不会额外添加或删除数字&#xff0c;…...

Linux 定时任务调度(crontab)

一、Crontab Crontab命令用于设置周期性被执行的指令。该命令从标准输入设备读取指令&#xff0c;并将其存放于“crontab”文件中&#xff0c;以供之后读取和执行。 可以使用Crontab定时处理离线任务&#xff0c;比如每天凌晨2点更新数据等&#xff0c;经常用于系统任务调度。…...

C进阶:6.C语言文件操作

目录 1.为什么使用文件 2.什么是文件 2.1程序文件 2.2数据文件 2.3文件名 3.文件的打开和关闭 3.1文件指针 4.文件的顺序读写 fputc()写入文件 fgetc()从文件中读取 fgets()读取一段字符串 fprintf格式化写入文件、fscanf格式化读出文件 4.1对比一组函数 5.文件…...

Linux环境变量

Linux环境变量孤儿进程进程优先级其他概念环境变量感性的理解环境变量常见的环境变量添加环境变量环境变量的组织形式通过代码如何获取环境变量再次理解环境变量命令行参数孤儿进程 概念:父进程先于子进程结束&#xff0c;这样的子进程就叫做“孤儿进程”&#xff1b; “孤儿”…...

Kotlin-委托、代理和单例对象

委托和代理 实现委托和代理&#xff0c;使用的是by关键字。 这里设计一个场景&#xff1a;假设某个演员被要求唱歌&#xff0c;但是不会唱歌&#xff0c;就委托一个会唱歌的歌手在后台唱歌。 如何实现这个需求&#xff0c;下面就开始直接写代码 首先定义一个唱歌能力接口 int…...

华为OD机试真题Python实现【报数】真题+解题思路+代码(20222023)

报数 题目 一百个人围成一圈,每个人有一个编码编号从一开始到一百。 他们从一开始依次报数,报道M的人自动退出圈圈, 然后下一个人接着从1开始报数一直到剩余人数小于M。 请问最后剩余人在原先的编码为多少? 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Py…...

MacOS:Error message “error:0308010C:digital envelope routines::unsupported“

命令行&#xff1a;export NODE_OPTIONS--openssl-legacy-provider 原帖&#xff1a;https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported...

Java 异常处理,超详细整理,适合新手入门

目录 前言 抛出异常 捕获异常 处理异常 finally块 总结 前言 当Java程序中出现错误或异常时&#xff0c;通常会抛出一个异常。Java的异常处理机制使得我们可以在程序运行过程中捕获这些异常并采取相应的措施&#xff0c;以便程序能够正常运行或者优雅地停止。 抛出异常 在…...

23年了,GOPATH和go.mod 还在冲突!

现在 新配了 go环境 设置了GOROOT&#xff0c;GOPATH &#xff0c;发现引用别的包会出问题。一直会报 package XX not in GOROOT &#xff08;xxxx&#xff09;我的目录&#xff1a;我的开发目录&#xff1a; /home/fate/go_projects/老样子&#xff0c;下面有 /home/fate/go_…...

Could not connect to Redis at 127.0.0.1:6379: 由于目标计算机积极拒绝,无法连接。(极简解决办法)

一、遇到问题。 在需要启动Redis客户端的时候&#xff0c;会发现会报这个错误。报这个错误的原因就是Redis的服务端没有开启&#xff0c;那Redis的客户端是访问不了的 二、解决办法。 1.解决的办法就是要启动服务端&#xff0c;让这个客户端可以访问到。启动服务端最简单不会…...

华为OD机试 - 优雅数组(Python)【2023-Q1 新题】

华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 优雅数组 | 华为…...

【概念辨析】数组指针指针数组

目录 一、数组指针 二、指针数组 三、 数组指针的数组名不是二级指针 再来说最关键的&#xff1a;数组指针为什么不是二级指针呢&#xff1f; 代码如下&#xff1a; 四、指针数组的数组名是二级指针 在复习&#xff0c;在考试&#xff0c;在焦虑。 又一次学习到了数组指针和指针…...

python实战应用讲解-【语法基础篇】字典的创建及建模(附示例代码)

目录 创建和使用字典 函数 dict 代码清单4-1列出了创建电话簿数据库的代码。...

华为OD机试真题Python实现【分糖果】真题+解题思路+代码(20222023)

分糖果 题目 小明从糖果盒中随意抓一把糖果 每次小明会取出一半的糖果分给同学们 当糖果不能平均分配时 小明可以从糖果盒中(假设盒中糖果足够)取出一个或放回一个糖果 小明至少需要多少次(取出放回和平均分配均记一次)能将手中糖果分至只剩一颗 🔥🔥🔥🔥🔥👉�…...

视频技术基础知识

一、视频图像基础 像素&#xff1a;图像的基本单元&#xff0c;即一个带有颜色的小块分辨率&#xff1a;图像的大小或尺寸&#xff0c;用像素个数来表示。原始图像分辨率越高&#xff0c;图像就越清晰位深&#xff1a;存储每位像素需要的二进制位数&#xff1b;位深越大&#…...

Windows应用之——设置定时关机

一 概述 本文介绍window设置自动关机的两种方式&#xff1a; cmd指令设置自动关机任务计划程序设置自动关机第三方定时关机软件 二 cmd指令设置自动关机—不推荐 2.1 自动关机-开启(管理员模式下) 依次点击‘“开始”&#xff0c;在“搜索程序和文件”中输入cmd&#xff0c…...

华为OD机试真题Python实现【 喊七】真题+解题思路+代码(20222023)

喊七 题目 喊 7,是一个传统的聚会游戏, N 个人围成一圈,按顺时针从1 - 7编号, 编号为1的人从1开始喊数, 下一个人喊得数字是上一个人喊得数字+1, 但是当将要喊出数字7的倍数或者含有7的话, 不能喊出,而是要喊过。 假定N个人都没有失误。 当喊道数字k时, 可以统计每…...

国产蓝牙耳机哪个好用?国产好用的蓝牙耳机推荐

现如今&#xff0c;国产蓝牙耳机越来越受到人们关注&#xff0c;国产蓝牙耳机近几年的发展愈发迅猛&#xff0c;配置上相对于非国产蓝牙耳机来说也毫不逊色。那么&#xff0c;国产蓝牙耳机哪个好用&#xff1f;下面&#xff0c;我来给大家推荐几款好用的蓝牙耳机&#xff0c;一…...

JAVA虚拟机JVM之内存模型

内存模型 java 内存模型 很多人将【java 内存结构】与【java 内存模型】傻傻分不清&#xff0c;【java 内存模型】是 Java Memory Model&#xff08;JMM&#xff09;的意思。 关于它的权威解释&#xff0c;请参考 https://download.oracle.com/otn-pub/jcp/memory_model-1.0…...

Java线程——常见方法

一、 常见方法 1.1 概述 ① start_vs_run&#xff1a;直接调用run方法并不会启动新的线程 import cn.itcast.n2.util.FileReader; import lombok.extern.slf4j.Slf4j;Slf4j(topic "c.Test") public class Test {public static void main(String[] args) {Thread t…...

机器学习:基于逻辑回归对某银行客户违约预测分析

机器学习&#xff1a;基于逻辑回归对某银行客户违约预测分析 文章目录机器学习&#xff1a;基于逻辑回归对某银行客户违约预测分析一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.逻辑回归2.业务理解3.读取数据4.数据理解5.数据准备6.逻辑回归模型训练7.模型评…...

MySQL数据库常用命令汇总(全网最全)

目录 数据库常用命令 数据库的创建 数据表的操作 表数据的增删查改 分组与函数查询 运算符&#xff1a;数学运算符 连接查询 多表查询 修改语句 删除语句 字符查询like MySQL练习 总结感谢每一个认真阅读我文章的人&#xff01;&#xff01;&#xff01; 重点&…...

Bulletproofs++

1. 引言 前序博客&#xff1a; Bulletproofs: Short Proofs for Confidential Transactions and More学习笔记Bulletproofs 代码解析Bulletproofs: Shorter Proofs for Privacy-Enhanced Distributed Ledger学习笔记Bulletproofs 代码解析 Liam Eagen 2022年3月论文《Bullet…...

毕业设计(1)-AFLGO的安装

AFLGO是一个模糊测试工具&#xff0c;在CSDN上的安装教程不多&#xff0c;自己在安装过程中也出现了很多教程之外的错误&#xff0c;最后反复安装了2天终于安装成功这里记录一下安装工程中的错误 使用的平台&#xff1a;Ubuntu18.04 配置&#xff1a; 内存&#xff1a;6G&…...

基于Opencv的缺陷检测任务

数据及代码见文末 1.任务需求和环境配置 任务需求:使用opencv检测出手套上的缺陷并且进行计数 环境配置:pip install opencv-python 2.整体流程 首先,我们需要定义几个参数。 图像大小,原图像比较大,首先将图像resize一下再做后续处理图像阈值处理的相应阈值反转阈值的…...

Android Gradle脚本打包

1、背景资料 1.1 Android-Gradle-Groovy-Java-JVM 之间的关系 1.2 Android Gradle Plugin Version版本 与 Gradle Version版本的对应关系 Android Gradle Plugin Version版本Gradle Version版本1.0.0 - 1.1.32.2.1 - 2.31.2.0 - 1.3.12.2.1 - 2.91.5.02.2.1 - 2.132.0.0 -…...

平滑KDJ指标公式,减少无效金叉死叉

软件自带的KDJ指标比较敏感&#xff0c;在震荡上涨或者震荡下跌时会反复出现金叉死叉信号&#xff0c;不利于指标的使用以及进一步开发。为了减少无效金叉死叉&#xff0c;本文对KDJ指标公式进行平滑处理。 一、KDJ指标对比 以下为软件自带的KDJ指标&#xff0c;加上了图标。本…...

大势前瞻!文旅还是短视频,你弯道超车风口在这了

三年前&#xff0c;新冠疫情的影响波及整个各行各业行业&#xff0c;互联网寒冬&#xff0c;房地产崩盘&#xff0c;教培团灭&#xff0c;在这样的背景下&#xff0c;行业都进入了发展“冰雪期”。老话说大疫后必有大变&#xff0c;如今风雪融化&#xff0c;万物复苏&#xff0…...

JAVA基础常见面试题

1.Java接口和抽象类的区别&#xff1f; 接口 接口中不能定义构造器 方法全部都是抽象方法&#xff0c;JDK8提供方法默认实现 接口中的成员都是public的 接口中定义的成员变量实际上都是常量 一个类可以实现多个接口 抽象类 抽象类中可以定义构造器 可以有抽象方法和具体…...