C++之从C过渡(上)

news2024/11/15 13:48:51

C++之从C过渡

在这里插入图片描述

前言

暂时告别C语言,我们走进C++。对于有C语言基础,初学C++的我们来说,在正式学习C++的主体内容之前,我们需要先有一个过渡,本文中会总结过渡需要了解的零散知识,主要是语法。


正文

C++的第一个程序

C++兼容C语⾔绝⼤多数的语法,所以C语⾔实现的helloworld依旧可以运⾏,C++中需要把定义⽂件 代码后缀改为.cpp,vs编译器看到是.cpp就会调⽤C++编译器编译,linux下要⽤g++编译,不再是gcc。

// test.cpp
#include<stdio.h>

int main()
{
	printf("hello world\n");

    return 0;
}

然而C++有⼀套⾃⼰的输⼊输出,严格说C++版本的helloworld应该是这样写的。

// test.cpp
// 这⾥的std cout等看不懂,下面会依次讲解 
#include<iostream>
using namespace std;
int main()
{
	cout << "hello world\n" << endl;
 
	return 0;
}

命名空间

这个东西的出现是为了解决C语言中的一些问题。比如:

在这里插入图片描述

这是一段C语言代码,问题出在我们包含的stdlib.h这个头文件,我们知道头文件在预处理阶段会展开,也就是会将头文件拷贝过来,而在stdlib.h里有rand函数的定义,所以就与我们定义的变量命名冲突了。

也有可能是我们在与其他人协作时,代码合并后出现了很多冲突。可以说冲突就是C语言的一大问题。

所以我们在C++中有命名空间

namespace的定义

  • 定义命名空间,需要使⽤到namespace关键字,后面跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
  • namespace本质是定义出⼀个域,这个域跟全局域各自独立,不同的域可以定义同名变量,所以下面的rand不在冲突了。
  • C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/ 类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的生命周期命名空间域和类域不影响变量生命周期
#include<stdio.h>
#include<stdlib.h>

//域
namespace oct
{
	//命名空间中可以定义变量、函数和类型
	int rand = 10;
}//注意这里是没有分号的

int main()
{
	//编译报错:重定义
	printf("%d\n", rand);//此时rand已经被封起来了,这里的rand访问的是函数rand
    //这里如果真的想打印rand,改为%p更好
	return 0;
}

可以看出上面namespace定义中所说的,这个域跟全局域各自独立。

就近原则
int a = 0;
int main()
{
	int a = 1;
	printf("%d\n", a);

	return 0;
}

在这段代码中,全局和局部都有个a,那么我们打印时访问的是哪个a呢?答案是局部的,这是由于就近原则:先在局部找再去全局找。

那如果我们现在就想要访问全局的这个a,该怎么办呢?

这时候我们就需要用到**“域作用限定符”**,也就是两个冒号。

在这里插入图片描述

冒号左边不给东西,就默认去全局域查找了。

那现在我们想要访问namespace里的变量,怎么做呢?

在域作用限定符左侧给上命名空间的名字,也就是告诉编译器直接去这个命名空间中查找。

  • 查找不是运行时而是编译时,原则上C/C++编译的时候,用一个函数或者变量都得找到它的声明或者定义
  • 关于生命周期,namespace不影响生命周期,namespace中定义的变量也是全局变量。只不过是访问时只有指定才能找到的全局变量。
  • 我们不能在局部定义域(在main里面写namespace)。
在命名空间中定义函数和结构
namespace oct
{
	//命名空间中可以定义变量、函数和类型
	int rand = 10;

	int Add(int left, int right)
	{
		return left + right;
	}

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

注意,在命名空间中定义结构,我们要访问时的使用方式是这样的:

struct oct::Node p1;

namespace的定义

namespace的前三条定义我们就看完了,现在再看三个定义:

  • namespace只能定义在全局,当然他还可以嵌套定义
  • 项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。
  • C++标准库都放在⼀个叫std(standard)的命名空间中。
命名空间的嵌套定义

在一个公司中我们可能有多个项目组,不同组用不同的命名空间,就不会冲突了。但是对于在同一个项目组的不同人来说,各自在各自的电脑上写,然后要合代码,比如用git提交代码,合起来可能就冲突了。也就是说在一个命名空间内部的冲突。

namespace oct
{
	namespace october
	{
		int rand = 1;
		int Add(int left, int right)
		{
			return left + right;
		}
	}

	namespace octopus
	{
		int rand = 2;
		int Add(int left, int right)
		{
			return (left + right)*10;
		}
	}
}

当然还可以再往下嵌套。

那么嵌套的命名空间里的成员如何访问?

多文件同名namespace不会冲突

同一个命名空间我们可以在同一个文件中定义多份,也可以在多个文件中定义多份。

比如我们现在有栈、队列、链表的文件,将它们都封装在namespace oct中,逻辑上会将它们合并,而不是冲突。否则我们一个文件一个命名空间,得定义很多的命名空间,显然不合适。

比如我们现在在全局定义一个静态的栈,再在命名空间定义动态的栈,在使用时我们就可以通过域的隔离分别使用,不会冲突。

C++标准库都放在⼀个叫std(standard)的命名空间中

标准库也怕和别人冲突。

C++标准库也有很多个各自的文件,都用namespace std合并封起来。

命名空间的使用

命名空间的使用有三种方式

编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。所以下面程序会编译报错。所以我们要使⽤命名空间中定义的变量/函数,有三种⽅式:

  • 指定命名空间访问,项⽬中推荐这种⽅式。
  • using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
  • 展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。

上面我们使用的方式是指定命名空间访问。

而每次都指定命名空间还是挺麻烦的。

全展开

现在可以看到,我们就可以不用指定,直接使用命名空间里的a和b了。而这种写法是命名空间全展开

但是展开整个命名空间的风险是很大的。只适合我们平时写日常小练习程序。

某个成员展开

所以我们还有一种折中的方式:把命名空间中的某个成员展开

假如我们要频繁使用a,且a不存在冲突风险:

所以一般在项目中我们选择将前两种方法结合使用。

  • 注意,在展开头文件和展开命名空间中都提到“展开”,但二者并非同一个意思。展开头文件指的是将这个头文件内容拷贝过来。而展开命名空间相当于我们将用于隔离的墙拆除了。

C++输⼊&输出

  • 是Input Output Stream的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输出对象。
  • std::cin是istream类的对象,它主要面向窄字符(narrow characters(of type char))的标准输⼊流。
  • std::cout是ostream类的对象,它主要面向窄字符的标准输出流。
  • std::endl是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。

只有内存里才有整型、浮点型这样的概念,在其他的地方比如文件、网络都是字符流的概念。

整型有原码、反码、补码,浮点数也有自己的存储规则,这都是内存里的存储。内存中有这样的概念是为了方便运算。

不管我们用cout还是printf,整型其实都是转换成字符。比如1234被转换为4个字符然后再输出。-1234被转换成5个字符再输出。任何类型都要转换为字符再输出到控制台。

  • <<是流插⼊运算符,>>是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)
#include<iostream>
using namespace std;//一般选择展开,更方便

int main()
{
	int i = 1234;
	int j = -1234;
	cout << i << endl;

}
  • 使⽤C++输⼊输出更⽅便,不需要像printf/scanf输⼊输出时那样,需要⼿动指定格式,C++的输⼊ 输出可以自动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是 C++的流能更好的⽀持⾃定义类型对象的输⼊输出。

我们的插入可以一次写很多个连一起。

#include<iostream>
using namespace std;

int main()
{
	int a = 0;
	double b = 0.1;
	char c = 'x';

	cout << a << " " << b << " " << c << endl;

	return 0;
}

还可以这样写:

cout << a << " " << b << " " << c << "\n";

在C++中用"\n"也可以换行。

而这样写就不行:

cout << a " " ;

cout也就是流插入其实是函数调用,只能有一个参数。<<是二元操作符,只能有两个操作数。

可以看到,C语言需要指定类型,比较麻烦,而C++却可以自动识别。

我们再来试试输入(流提取)。

从控制台中提取然后转化成对应的类型。

可以看到可以一次输入多个。

endl比较复杂,是一个函数。它的底层不是一个换行符。其实cout和cin也很复杂。这些都需要日后学得更深入再具体了解。

  • IO流涉及类和对象,运算符重载、继承等很多面向对象的知识,这些知识我们日后讲解。

  • cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使⽤⽅式去⽤他们。

  • 这⾥我们没有包含<stdio.h>,也可以使⽤printf和scanf,在包含间接包含了。vs系列编译器是这样的,其他编译器可能会报错。

小细节:

关于C语言中的控制精度:

可以看到我们的C++是默认保留小数点后5位。也可以人为控制,但是不建议了解。在我们想要控制时,可以用回printf。

在用scanf时我们需要取地址,因为scanf是个函数,[形参的改变不会影响实参,所以我们要取地址。]而在C++中我们就无需取地址。

再次总结,io流函数的定义在iostream头文件里的std命名空间里,可以自动识别类型,可以一行多个输入输出。

补充:
#include<iostream>

using namespace std;

int main()
{
 // 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码 
 // 可以提⾼C++IO效率 
 ios_base::sync_with_stdio(false);
 cin.tie(nullptr);
 cout.tie(nullptr);
 return 0;
}

C++的IO流由于各种各样的原因比如要兼容C语言,而这种兼容会付出一些代价。IO输入输出是带缓冲区的,各自有各自的缓冲区,要兼容就得去关注对应的缓冲区。为了提高性能,除了换用printf、scanf,还可以选择把这三句代码加上。

缺省参数

• 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调用该函数时,如果没有指定实参则采⽤该形参的缺省值,否则使用指定的实参,缺省参数分为全****缺省半****缺省参数。(有些地方把缺省参数也叫默认参数

• 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。

• 带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参。

• 函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。

#include <iostream>

using namespace std;

void Func(int a = 0)//缺省参数
{
	cout << a << endl;
}

int main()
{
	Func(); // 没有传参时,使⽤参数的默认值 
	Func(10); // 传参时,使⽤指定的实参 
	return 0;
}

其实就是如果有传就用传的,没有就用默认的值(缺省值)。

#include <iostream>
using namespace std;

// 全缺省 
void Func1(int a = 10, int b = 20, int c = 30)
{
 cout << "a = " << a << endl;
 cout << "b = " << b << endl;
 cout << "c = " << c << endl << endl;
}

// 半缺省 
void Func2(int a, int b = 10, int c = 20)
{
 cout << "a = " << a << endl;
 cout << "b = " << b << endl;
 cout << "c = " << c << endl << endl;
}

int main()
{
 Func1();//一个都不传
 Func1(1);//传一个
 Func1(1,2)//传两个
 Func1(1,2,3);//全传
 Fun1(,2,);//这样传不可以
    
 Func2();//不能一个都不传
 Func2(100);//传一个
 Func2(100, 200);//传两个
 Func2(100, 200, 300);//全传
 return 0;
}

注意半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。

缺省参数在实践中的意义

之前我们在写栈的插入数据时,如果后续要插入很多数据我们就要多次扩容,效率低下,而如果初始化时一把开好,就可以避免扩容。我们可以使用缺省参数:

(test.cpp中)

#include<iostream>
using namespace std;

#include"Stack.h"

int main()
{
	// 确定知道要插入1000个数据,初始化时一把开好,避免扩容
	moon::ST s2;
	moon::STInit(&s2, 1000);

	for (size_t i = 0; i < 1000; i++)
	{
		moon::STPush(&s2, i);
	}

	return 0;
}

(stack.h中)

void STInit(ST* ps, int n = 4);

(stack.cpp中)

这样我们就一把开好,不需要扩容,效率就得到了提高。在我们不知道多大时,不传参数,默认就为缺省参数。

缺省参数是很好用的,日后就知道了。

函数重载

C++⽀持在同⼀作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调用就表现出了多态行为,使用更灵活。C语言是不⽀持同⼀作⽤域中出现同名函数的。

这个东西非常有用。可以说是C语言的一大缺陷。

#include<iostream>
using namespace std;
// 1、参数类型不同 
int Add(int left, int right)
{
 	cout << "int Add(int left, int right)" << endl;
 	return left + right;
}

double Add(double left, double right)
{
 	cout << "double Add(double left, double right)" << endl;
 	return left + right;
}

int main()
{
    Add(1,2);
    Add(1.1,2.2);
    
    return 0;
}

以上代码,C语言是无法做到的。这种情况能同名显然是更好的。

再如

void Swap(int* px,int* py)
{}

void Swap(double* px, double* py)
{}

交换函数,如果能够同名,显然是非常好。

// 2、参数个数不同 
void f()
{
 cout << "f()" << endl;
}

void f(int a)
{
 cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同(本质也是类型不同) 
void f(int a, char b)
{
 cout << "f(int a,char b)" << endl;
}

void f(char b, int a)
{
 cout << "f(char b, int a)" << endl;
}
坑:
// 下⾯两个函数构成重载,因为参数个数不同 
// f()但是调用时,会报错,存在歧义,编译器不知道调⽤谁 

void f1()
{
 cout << "f()" << endl;
}

void f1(int a = 10)
{
 cout << "f(int a)" << endl;
}

//返回值不同不能作为重载条件,因为调⽤时也⽆法区分 
void fxx()
{}

int fxx()
{
 return 0;
}

引用

这也是C++中非常好用的一个东西。

引用的概念和定义

引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间, 它和它引⽤的变量共⽤同⼀块内存空间。⽐如:⽔壶传中李逵,宋江叫"铁⽜",江湖上⼈称"黑旋风";林冲,外号豹⼦头;

类型&引用别名=引用对象;

C++中为了避免引⼊太多的运算符,会复⽤C语⾔的⼀些符号,⽐如前面的<<和>>,这⾥引⽤也和取地址使⽤了同⼀个符号&,从使⽤⽅法⻆度区分就可以。

#include<iostream>
using namespace std;

int main()
{
    int a = 0;
    // 引⽤:b和c是a的别名 
    int& b = a;
    int& c = a;
    // 也可以给别名b取别名,d相当于还是a的别名 
    int& d = b;
    ++d;
    // 这⾥取地址我们看到是⼀样的 
    cout << &a << endl;
    cout << &b << endl;
    cout << &c << endl;
    cout << &d << endl;
    return 0;
}

在这里插入图片描述

无论叫a b c还是d,都是同一块空间的名字。给其中一个名字加1,其他的名字的值也都加1。

引用的实践

以前我们要交换两个变量的值,得使用传地址的方式。

我们现在使用引用,就无需传地址也能交换两个变量的值。

理解这个我们不要去想底层(底层也是指针),在语法层面就是取别名。

也就是rx是x的别名,ry是y的别名。改变别名就能改变本身。这样并没有为形参开辟新的空间。

我们可能会见到以下的代码:

void STInit(ST& rs, int n = 4)
{
	rs.a = (STDataType*)malloc(n * sizeof(STDataType));
	rs.top = 0;
	rs.capacity = n;
}

这里就用别名来替换了指针。

再或者这样:

// 栈顶
void STPush(ST& rs, STDataType x)
{
	//assert(ps);

	// 满了, 扩容
	if (rs.top == rs.capacity)
	{
		printf("扩容\n");
		int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;
		STDataType* tmp = (STDataType*)realloc(rs.a, newcapacity *
			sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		rs.a = tmp;
		rs.capacity = newcapacity;
	}
	rs.a[rs.top] = x;
	rs.top++;
}

有了引用之后进入函数我们就不需要断言了。

还有原本下面的这个函数,我们是要用二级指针作为参数的,因为可能链表为空,push的这个就要成为头结点,那么plist就会改变,而如果参数为一级指针,phead改变无法改变plist,于是我们用二级指针。

void ListPushBack(LTNode*& phead, int x)
{
	PNode newnode = (PNode)malloc(sizeof(LTNode));
	newnode->val = x;
	newnode->next = NULL;
	if (phead == NULL)
	{
		phead = newnode;
	}
	else
	{
		//...

	}
}

int main()
{
    LTNode* plist = NULL;
    ListPushBack(plist,1);
    
    return 0;
}

而现在我们可以给指针取别名,就不用二级指针。所以我们现在改变指针phead,就是改变main中的指针plist。

typedef struct ListNode
{
 int val;
 struct ListNode* next;
}LTNode, *PNode;

//等价于
typedef struct ListNode* PNode;

PNode是指向LTNode类型的指针(结构体指针)。

所以上面函数也可以写成

void ListPushBack(PNode& phead, int x)

本文到此结束,但过渡内容没有结束,敬请期待下文=_=

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

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

相关文章

终于用PC串口显示出esp32 串口输出hello world

硬件&#xff1a; esp32模块 rs232 转ttl 3.3v 电平转换器 3.3v 外接电源 esp32 tx 脚接转换器rx, rx脚接转换器tx esp32 使用uart2 现在就可以用pc作为上位机通过串口控制esp32&#xff0c;用pc串口调试软件作为esp的输出监控器显示esp的各种运算结果。 #include &qu…

使用visual studio2019创建dll导出自定义类

系列文章目录 文章目录 系列文章目录前言一、具体操作步骤1.创建动态链接库工程(DLL)2.头文件声明3.实现文件定义4.生成dll工程5 使用dll总结 前言 程序对动态链接库dll、静态链接库lib想必都很熟悉了&#xff0c;网上也有很多的相关介绍。但网上介绍的一般都是C语言函数介绍&…

javascript 的奇技巧淫二

文章目录 1 、标记模板文字2、使用 Object.entries() 和 Object.fromEntries()3、用于唯一元素的 Set 对象4、对象中的动态属性名称5、使用 bind() 进行函数柯里化6、使用 Array.from() 从类似数组的对象创建数组7、可迭代对象的 for…of 循环8、使用 Promise.all() 实现并发 P…

SpringBoot下载resources目录下的文件

1.引入SpringBoot和hutool依赖 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.22</version></dependency>2.在项目resources目录下放入模版文件&#xff0c;结构如下&#xff1a…

JavaScript基础(30)_事件的冒泡、事件的委派

事件的冒泡(Bubble) 所谓的冒泡指的是事件的向上传导&#xff0c;当后代元素上的事件被触发时&#xff0c;其祖先元素的“相同事件”也会被触发。 取消事件冒泡 在开发中大部分情况冒泡都是有用的&#xff0c;如果不希望发生事件冒泡可以通过事件对象来取消冒泡。取消冒泡代码…

数字货币走势分析两点最关键,比特币BTC竞猜策略共享

目前虚拟货币市场成为各界关注的焦点&#xff0c;比特币的未来也会随着相关的决策和政策而产生变化&#xff0c;多位专家是看好这个市场的潜力的。如果比特币随后可以得到更多开采和推广的话&#xff0c;全球加密货币领域的高度还会提升。目前各方对于比特币和加密货币咨询和了…

OpenAI降低人们的期望值 今年秋季的DevDay不会公布GPT-5

去年&#xff0c;OpenAI 在旧金山举行了一场声势浩大的新闻发布会&#xff0c;会上该公司发布了一系列新产品和工具&#xff0c;其中包括类似 App Store 的GPT 商店。不过&#xff0c;今年的活动将更加低调。本周一&#xff0c;OpenAI 表示它将改变 DevDay 大会的形式&#xff…

使用visual studio code远程连接虚拟机

1. 安装Remote-SSH插件 打开vscode&#xff0c;在“扩展商店”中搜索“Remote-SSH”&#xff0c;然后点击“安装”即可&#xff0c;如图所示。 2. 配置SSH 如图所示&#xff0c;点击“远程资源管理器”&#xff0c;点击“新建远程”&#xff0c;然后在输入框中输入如下指令。…

革新出行体验:音频定位导航系统引领智能导航新时代

在科技日新月异的今天&#xff0c;出行方式正经历着前所未有的变革。从传统的纸质地图到GPS视觉导航&#xff0c;再到如今日益兴起的音频定位导航系统&#xff0c;每一次进步都极大地提升了人们的出行便捷性与安全性。音频定位导航系统&#xff0c;作为智能导航领域的创新之作&…

css仿el-tabs标签页效果

需求&#xff1a;el-tabs很多时候需要改间距或者下划线上还要加组件什么的比较麻烦&#xff0c;手写一个自己根据需求更改即可 1.效果 2.主要代码详解 主要代码如下&#xff1a;active是下划线&#xff0c;activeitem是选中后改变字体颜色&#xff0c; item- (index 1),用ite…

用.net core简易搭建webapi托管到IIS

1、从官网下载.NET Core 托管捆绑包 https://learn.microsoft.com/zh-cn/aspnet/core/tutorials/publish-to-iis?viewaspnetcore-8.0&tabsvisual-studio 2、新建ASP.NET Core WEB API项目 新建控制器TestController并生成GetInfo方法 3、发布 目标路径选择 2)显示所有…

花小钱、办大事的巴黎奥运会,能学点啥?|易搭云

“获得奥运会举办权的竞争几乎和体育赛事本身一样激烈。”众所周知&#xff0c;奥运会不仅能带来巨大的经济效益&#xff0c;更是国家实力和文化底蕴的彰显。时隔百年&#xff0c;奥运会的主会场又回到了巴黎&#xff0c;以浪漫著称的巴黎&#xff0c;奥运会突出的关键词却变成…

使用Cisco进行模拟RIP路由协议配置

实验四 RIP路由协议配置 文章目录 实验四 RIP路由协议配置1.实验目的2.实验流程3.RIPv1实验步骤4.RIPv2实验步骤 1.实验目的 1&#xff09;理解RIP路由的原理 2&#xff09;掌握RIP路由的配置方法 2.实验流程 开始→布置拓扑→配置IP地址→配置并验证RIPv1→配置并验证RIPv2…

SQL-锁

一.锁的介绍 锁是计算机协调多个进程或线程并发访问一资源的机制。在数据中,除传统的计算资源(CPU,RAM,I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性,有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因…

[io]进程间通信 -信号概念、分类、工作原理

概念、工作原理&#xff1a; 信号是一种异步通信机制&#xff0c;用于在不同进程之间传递事件信息 信号的产生&#xff1a;包括对前台进程用户输入&#xff08;CtrlC&#xff09;、系统状态变化硬件异常&#xff08;如内存访问错误&#xff09;、终端系统调用&#xff08;kil…

【JVM基础13】——垃圾回收-详细聊一下G1垃圾回收器

目录 1- 引言&#xff1a;G1垃圾回收器2- ⭐核心&#xff1a;详解 G1 垃圾回收器2-1 概述G1垃圾回收器2-2 新生代垃圾回收 Young Collection第一次新生代垃圾回收第二次新生代垃圾回收 2-3 并发标记阶段 Young Collection Concurrent Mark2-4 Mixed Collection&#xff08;混合…

中影国际影城使用的多联机空调集中管理系统

多联机空调集中管理系统 建筑能耗约占我国经济总能耗的30&#xff05;&#xff0c;而空调能耗占据建筑物总能耗的50%-70%&#xff0c;即中央空调的能耗约占国民经济能耗的两成。多联机集中控制管理系统&#xff0c;在节能降耗方面具有杰出的性能。 项目案例&#xff1a;中影国…

安卓控件RecyclerVieW

文章目录 导入依赖简单使用实现横向滚动瀑布式 RecyclerView是官方在5.0之后新添加的控件&#xff0c;推出用来替代ListView和GridView的列表控件。为了保证RecyclerView在所有Android系统版本上都能使用。Google将RecyclerView控件定义在了AndroidX中&#xff0c;只需要在项目…

三品PLM项目管理系统与CAD集成的实施指南

随着信息化技术的飞速发展&#xff0c;PLM产品生命周期管理系统与CAD三维计算机辅助设计软件的集成已成为企业研发创新的关键。本文将探讨PLM与三维CAD集成的重要性、实施要素、策略以及实际应用案例&#xff0c;为企业信息化建设提供参考。 PLM与三维CAD集成&#xff1a;信息化…

SQL进阶技巧:有序行转列问题如何保证不同字段内容有序性及内容一一对应?【collect_list函数有序性保证问题】

目录 0 问题描述【小红书面试题】 1 数据准备 2 问题分析 3 小结 0 问题描述【小红书】 有如下需求,需要将左边的表变换成右边的表,注意字段内容的顺序及对应内容的一致性。 第一个字段为name,第二个字段为subject,第三个字段为score,变换后要求subject按照语文、数学…