C++入门——引用|内联函数|auto关键字|基于范围的for循环|指针空值

前言

C++入门专栏是为了补充C的不足,并为后面学习类和对象打基础。在前面我们已经讲解了命名空间、输入输出、缺省参数、重载函数等,今天我们将完结C++的入门。

下面开始我们的学习吧!

一、引用

1、引用是什么呢?为什么C++添加了引用?

(1)引用的概念: 引用是给已存在变量取了一个别名,不是重新定义一个新变量。编译器不会为引用变量开辟内存空间,它和它引用的变量一起用同一块内存空间。(就如西游记中孙悟空,也叫齐天大圣,你不管叫他那个名字,都是代表一个人。)

(2) 在C语言中,我们要改变一个变量的值可以取一个变量的地址通过解引用来改变,但是这是一种间接的玩法。总结:简单的说就是指针是间接的,而引用相当于它的别名还是它自己,更直接,更方便了。 所以以后我们大多都是使用引用了。下面让我们详细了解引用的魅力!

2、引用的语法

引用的语法:

类型& 引用变量名(对象名) = 引用实体。

tip:

(1)引用的理解:

①C++觉得添加太多新符号不太好,所以就会在某些地方共用一些符号。例如这里的‘&’。

②‘&’这个符号用法的区分:‘&’在变量名之前,代表取地址;‘&’在类型之后代表引用(取别名)。

③引用在语法逻辑上不会开辟新空间,它和它引用的实体共用一块内存空间。

④引用就是取别名,不管怎样还是共用一块内存空间。

⑤代码示例:

//引用的理解:
#include<iostream>using namespace std;int main()
{int a = 10;//b是a的引用(别名)int& b = a;//打印a与b的地址cout << &a << endl;cout << &b << endl;return 0;
}

运行结果:
在这里插入图片描述

(2)引用的特性:

①引用在定义的时候必须初始化(就如你给谁取别名,肯定是有一个明确的指向,是给谁取的)。

②一个变量可以有多个别名(就像孙悟空就有多个别名)。

③引用一旦引用了一个实体,就不能再引用其他实体了(从这里就能看出C++的革命是不彻底的,引用并没有将指针完全替代)。

④代码示例:

//引用的特性:
#include<iostream>using namespace std;int main()
{int a = 10;//①必须初始化;//int& b;//编译报错,引用必须初始化//②一个变量可以有多个引用int& b = a;//b是a的引用(别名)int& c = b;//c是b的引用(别名的别名也是可以的)//③引用一旦引用了一个实体,就不能在引用其他实体了int x = 9;//int& b = x;//编译报错,"b"重定义,多次初始化b = x;//注意这里b不是x的引用,而是x赋值给b,b仍是a的别名。return 0;
}

(3)常引用——引用的权限

①引用过程中,权限可以平移或者缩小,但是不可以放大。

②算术转化:如果操作符的操作数类型不一致,会发生类型转化,只有类型一致,才能进行运算。

③类型转化:生成一个临时变量,临时变量具有常性,即临时变量不可改变,是常变量。图示:

在这里插入图片描述

④为什么类型转化会生成临时变量——因为变量a类型不会改变,所以需要生成一个中间变量来进行类型转化。

⑤当引用的实体是一个常变量的时候,我们就要使用常引用,因为权限不可以放大。

⑥常引用的应用:常引用做参数——如果函数中只是使用参数,不改变参数的值,建议使用常引用。

⑦代码示例:

//常引用——引用的权限
#include<iostream>using namespace std;int main()
{//1、引用过程中,权限可以平移或者缩小int a = 10;int& b = a;//权限平移,a/b可读可写//如a能++,b也可以b++;a++;const int& c = a;//权限的缩小,a可读可写c可读不可写//a能++,c不可以a++;//c++;//编译报错,c不能改变//2、引用过程中,权限不可以放大double x = 9;//int& y = x;//因为类型不一致,x生成const int的临时变量可读不可写,而y可读可写,引用权限不可以放大,所以报错。const int& y = x;//权限平移return 0;
}

3、引用的应用

(1)引用做参数

引用做参数的意义:

①做输出型参数:形参的改变要影响实参。

代码示例:交换两个整数

#include<iostream>using namespace std;
//使用引用做输出参数交换两个整数
void Swap(int& x, int& y)
{int temp = x;x = y;y = temp;
}int main()
{int a = 3;int b = 5;//调用函数交换a bSwap(a, b);cout << "交换后:a=" << a << " b=" << b << endl;return 0;
}

tip:在C语言的时候,我们交换两个整数,要使形参的改变影响实参,我们用的指针来实现,现在C++里面我们可以使用引用实现。

②引用做参数,减少拷贝提高了效率。(特别是对于大对象和深拷贝类对象)

代码示例:

//2.调高效率,建议大对象/深拷贝对象使用引用做参数#include<iostream>
#include<time.h>using namespace std;//定义一个大结构体
struct A
{int a[10000];
};//定义函数:以值作为函数参数
void Func1(A a){}
//定义函数:以引用作为函数参数
void Func2(A& a){}//定义函数:分别计算两个函数运行结束后的时间
void TestRefAndValue()
{//struct A a;//C中定义结构体类型变量的方式,Cpp也可以这样(兼容C)A a;//Cpp中定义类对象的方式,因为在Cpp中struct升级为类了//以值作为函数参数size_t begin1 = clock();//开始时间for (size_t i = 0; i < 10000; ++i){Func1(a);}//调用10000次Func1函数size_t end1 = clock();//结束时间//以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i){Func2(a);}size_t end2 = clock();//分别输出两个函数运行结束后的时间cout << "Func1(A)_time:" << end1 - begin1 << endl;cout << "Func1(A&)_time:" << end2 - begin2 << endl;
}int main()
{//调用函数TestRefAndValue分别计算以值为参数和以引用为参数的运行时间TestRefAndValue();return 0;
}

运行结果:

在这里插入图片描述

(2)引用做返回值

①引用做返回值的第一个意义:减少拷贝提高效率。

代码示例:

//①减少拷贝提高效率
#include<iostream>
#include<time.h>using namespace std;struct A 
{ int a[10000];
};
//创建一个大对象
A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }
void TestReturnByRefOrValue()
{// 以值作为函数的返回值类型size_t begin1 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc1();size_t end1 = clock();// 以引用作为函数的返回值类型size_t begin2 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc2();size_t end2 = clock();// 计算两个函数运算完成之后的时间cout << "TestFunc1 time:" << end1 - begin1 << endl;cout << "TestFunc2 time:" << end2 - begin2 << endl;
}int main()
{TestReturnByRefOrValue();return 0;
}

运行结果:

在这里插入图片描述

②为什么会减少拷贝提高效率呢?

答案是:函数的返回类型是传值返回,就会将返回值拷贝到一个临时变量中,最后再拷贝回主调函数。当函数的返回类型是引用返回时,就不会生成临时变量通过拷贝返回,而是直接返回返回值的别名。图示:

在这里插入图片描述

③局部变量与静态变量传引用返回。

代码示例1:局部变量传引用返回

//局部变量传引用返回
#include<iostream>using namespace std;int& Count()
{int n = 0;//局部变量n++;//……return n;
}int main()
{//ret也是n的别名int& ret = Count();//调用完Count直接输出retcout << ret << endl;printf("sss\n");//调用完printf,再次输出retcout << ret << endl;return 0;
}

运行结果:

在这里插入图片描述

为什么ret的值不一样呢——因为局部变量随栈帧销毁而销毁。如果Count函数结束,栈帧不清理,那么ret的结果侥幸正确;如果Count函数结束,栈帧清理,那么ret的结果是随机值。图示:

在这里插入图片描述

代码示例2:静态变量传引用返回

//静态变量传引用返回
#include<iostream>using namespace std;int& Count()
{static int n = 0;//静态变量n++;//……return n;
}int main()
{//ret也是n的别名int& ret = Count();//调用完Count直接输出retcout << ret << endl;printf("sss\n");//调用完printf,再次输出retcout << ret << endl;return 0;
}

运行结果:

在这里插入图片描述

为什么这里ret的值一样呢——静态变量存储在静态区,不随栈帧的销毁而销毁。

tip:谨慎用引用做返回值,出了函数作用域,对象不在了,就不能用引用返回,还在就可以用引用返回。

④引用做返回值的第二个意义:获取返回值与修改返回值。

代码示例:静态顺序表获取pos位置值与修改pos位置值

//代码示例:静态顺序表获取pos位置值与修改pos位置值
#include<iostream>
#include<assert.h>using namespace std;//定义静态顺序表类型
struct SeqList
{int a[100];//顺序表大小int size;//有效数据个数
};//C实现——获取pos位置值
int SLGet(SeqList* ps, int pos)
{//断言pos位置是否合理assert(pos >= 0 && pos < 100);//返回pos位置值return ps->a[pos];
}//C实现——修改pos位置值
void SLModify(SeqList* ps, int pos, int x)
{//断言pos位置是否合理assert(pos >= 0 && pos < 100);//修改pos位置值ps->a[pos] = x;
}//C++使用引用做返回值实现——修改&获取pos位置值
int& SLAt(SeqList& ps, int pos)
{//断言pos位置是否合理assert(pos >= 0 && pos < 100);//返回pos位置的别名return ps.a[pos];
}int main()
{SeqList s;//调用C的实现,来获取与修改pos位置SLModify(&s, 1, 2);cout << SLGet(&s, 1) << endl;//调用C++的实现,来获取与修改pos位置SLAt(s, 0) = 1;//修改cout << SLAt(s, 0) << endl;//获取return 0;
}

总结

1、引用做参数:①做输出型参数;②减少拷贝提高效率;③基本任何场景都可以用引用做参数。

2、引用做返回值:①减少拷贝提高效率;②可以读写返回值;③谨慎用引用做返回值,出了函数作用域,对象不在了,就不能用引用返回,还在就可以用引用返回。

4、引用与指针的区别

(1)语法层面: 引用不开空间,是对实体取别名;指针开空间,是存储实体地址。

代码示例:

//引用与指针的区别
#include<iostream>using namespace std;int main()
{int a = 11;//引用在语法层面:不开空间,是对a的别名int& ra = a;ra = 13;//指针在语法层面:开空间,存储a的地址int* pa = &a;*pa = 14;return 0;
}

F10调试观察:

在这里插入图片描述

(2)底层层面: 从底层汇编指令实现的角度看,引用是类似指针的方式实现的。即在底层实现上引用实际是开空间的。

汇编代码图示:

在这里插入图片描述

(3)引用与指针不同点总结:

①在语法层面:引用不开空间是一个实体的别名,指针开空间,存储实体的地址。

②引用在定义时必须初始化,指针没有要求。

③引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。(即引用不可以修改指向,指针可以修改指向。)

④没有NULL引用,但有NULL指针。

⑤在sizeof中含义不同:引用结果为引用类型的大小,但是指针始终是地址空间所占字节个数。

⑥引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小。

⑦有多级指针,但没有多级引用。

⑧访问实体方式不同,指针需要显示解引用,引用编译器自己处理。

⑨引用比指针使用起来相对更安全。(如上面第四点。)

二、内联函数

1、回顾宏函数

我们都知道调用函数需要建立栈帧是有消耗的,所以对于一些代码少且频繁调用的函数,在C语言我们使用了宏函数优化。

(1)代码示例:两数相加的宏

错误形式1:

#define Add(x,y) x+y

解读:Add(10,20) * 20,宏预编译进行替换为10 + 20 * 20,我们发现因为操作符优先级的问题,不是先加后乘。

错误形式2:

#define Add(x,y) (x+y)

解读:Add(1 | 2 , 1 & 2),宏替换后为:(1 | 2 + 1 & 2),位操作符的优先级低于算术操作符,所以错误。

正确形式:

#define Add(x,y) ((x) + (y))

tip:宏参数的求值是在所有周围表达式的上下环境里,除非加上括号,否则邻近操作符的优先级可能会产生不可预料的后果,所以建议宏在书写的时候多写括号。(可以替换看一看。)

(2)宏的优缺点:

优点: 不需要建立栈帧,提高效率。

缺点: 因为宏在预编译阶段进行了替换,所以①不方便调试;②代码可读性差,可维护性差,容易出错;③没有类型的检查等等。

(3)宏函数有这么多缺点,我们C++祖师爷就看不下去了,所以就有了inline内联函数。

2、内联函数

(1)概念: 以inline修饰的函数叫做内联函数,编译时C++编译器会在调用函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

代码示例:

//内联函数
#include<iostream>
using namespace std;//inline修饰的函数
inline int Add(int x, int y)
{return x + y;
}int main()
{int ret = 0;ret = Add(1, 2);
}

tip: ①内联函数弥补了宏的缺点,继承了宏的优点。内联函数可读性高,可调试,不复杂等等。②在默认的debug模式下,inline不会起作用,否则不方便调试。

(2)内联这么好能不能都写成内联呢?

答案是: 不可以,因为inline的特性不支持所有函数都写成内联。

(3)内联函数的特性:

①inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺点:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。例如Func编译后是50行指令,如果Func不是inline,调用10000次Func合计指令为:10000+50(调用即call Func(地址),跳转到Func。);如果Func是inline,调用10000次Func合计指令为:10000*50(假设inline只是单纯展开,实际不是)。指令越多,目标文件越大。

inline对于编译器而言只是一个建议,最终是否成为inline,由编译器决定。一般来说,内联机制用于优化规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、流程直接(不递归)、频繁调用的函数。例如递归函数加了inline也会被编译器否决。

inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

代码示例:

//F.h
#include<iostream>
using namespace std;inline void f(int i);
//F.cpp
#include"F.h"void f(int i)
{cout << i << endl;
}
//Test.cpp
#include"F.h"int main()
{f(10);return 0;
}//链接错误:Test.obj:LNK2019:无法解析的外部符号 "void __cdecl f(int)" (? f@@YAXH@Z),函数 _main 中引用了该符号	

tip:不建议声明与定义分开,所以inline直接在.h文件中定义实现。

三、auto关键字(C++11)

1、auto简介

C++11之前: 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量(限定变量的作用域及生命周期),但是没有人去使用,因为局部变量默认是auto修饰的。如下:

int a = 10;//自动存储类型
auto int b = 10;//自动存储类型

这样的话,auto没有用了。

C++11中: 标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

简单来说,在C++11中auto可以根据右边的表达式自动推导变量的类型

代码示例:

#include<iostream>
using namespace std;int main()
{auto a = 13;auto b = 0.14;//打印类型cout << typeid(a).name() << endl;cout << typeid(b).name() << endl;return 0;
}

运行结果:

在这里插入图片描述

注意:使用auto定义变量时必须对其进行初始化,在编译阶段需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法。

2、auto的应用场景

随着程序越来越复杂,程序中用到的类型也越来越复杂。类型复杂,我们不仅容易写错还难于拼写。所以这个时候使用auto来帮我们自动推导变量的类型,就非常方便了。

代码示例:

#include<iostream>
#include<map>int main()
{std::map<std::string, std::string> dict;//std::map<std::string, std::string>::iterator it = dict.begin();//等价于auto it = dict.begin();return 0;
}

tip:auto在实际中最常见的优势用法就是跟C++11提供的新式for循环,还有lambda表达式等进行配合使用。

3、auto的使用细则

(1)auto与指针和引用结合使用

代码示例:

#include<iostream>
using namespace std;int main()
{int x = 10;auto a = &x;auto* b = &x;//auto*指定必须是指针类型auto& c = x;cout << typeid(a).name() << endl;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;return 0;
}

运行结果:

在这里插入图片描述

tip:使用auto声明指针时,用auto和auto没有任何区别(auto指定必须是指针),但用auto声明引用类型时必须加&。

(2)auto在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同类型,否则编译器将报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

代码示例:

int main()
{auto a = 1, b = 2;auto c = 3, d = 13.14;//编译失败,因为c和d的初始化表达式类型不同return 0;
}

在这里插入图片描述

4、auto不能推导的场景

(1)auto不能作为函数的参数

void TestAuto(auto a){}

此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导。

(2)auto不能直接用来声明数组

void TestAuto()
{auto a[] = {1, 2};
}

编译失败,auto不能声明数组,因为auto类型不能出现在顶级数组类型中。

四、基于范围的for循环(C++11)

1、范围for的语法

在以前(C++98),如果要遍历一个数组,我们是按照下面的方式实现:

#include<iostream>
using namespace std;int main()
{int arr[] = { 1, 2, 3, 4, 5 };//通过下标访问for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){arr[i] *= 2;}//通过指针访问for (int* p = arr; p < arr + sizeof(arr) / sizeof(arr[0]); p++){cout << *p << endl;}return 0;
}

对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还容易犯错。因此C++11中引入了基于范围的for循环

范围for的语法格式如下:

for(auto e : array)

for循环后的括号由冒号“:”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

现在我们使用范围for来遍历数组,修改数组:

#include<iostream>
using namespace std;int main()
{int arr[] = { 1, 2, 3, 4, 5 };//范围for与引用结合:修改数组for (auto& e : arr){e *= 2;}//范围for:打印数组for (auto e : arr){cout << e << endl;}return 0;
}

总结:

①使用范围for遍历数组与以前相比,用起来非常方便,不易出错。所以范围for是一个语法糖。

②适用于数组,依次取数组中的数据赋值给变量e,自动迭代,自动判断结束。

③与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

2、范围for的使用条件

(1)for循环迭代的范围必须是确定的

对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

错误演示:以下代码中for的范围是不确定的

void TestFor(int arr[])
{for (auto e : arr){cout << e << endl;}
}

解读:数组传参,实际只能接收数组的首元素地址,这里我们并不知道数组的范围,所以报错。

(2)迭代的对象要实现++和==的操作。(后期讲解,大家先知道即可)

五、指针空值nullptr(C++11)

1、C++98中的指针空值

在良好的C/C++编程习惯中,声明一个变量时最好给变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针。

如果一个指针没有合法的指向,我们就需要将其置为空。

代码演示:

int main()
{int* p1 = NULL;int* p2 = 0;return 0;
}

为什么0也可以将指针置为空呢?

答案是:NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL#ifdef __cplusplus#define NULL 0#else#define NULL ((void *)0)#endif
#endif

可以看到,NULL可能别被定义为字面常量0,或者被定义为无类型指针(void)的常量。

不论采用哪种定义,在使用空值的指针时,都不可避免的遇到一些麻烦,如下:

#include<iostream>
using namespace std;//参数类型是整形
void f(int)
{cout << "f(int)" << endl;
}
//参数类型是整形指针
void f(int*)
{cout << "f(int*)" << endl;
}int main()
{//调用f函数,观察f(0);f(NULL);f((int*)NULL);return 0;
}

运行结果:

在这里插入图片描述

解读:

①程序的本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序初衷相孛。

②在C++98中字面常量0即可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对齐进行强转(void*)0。

③形参因为我们只是观察参数匹配规则,所以可以只写形参类型。

NULL这样太尴尬,所以C++11引入了nullptr

2、nullptr

先看一段代码示例:

#include<iostream>
using namespace std;//参数类型是整形
void f(int)
{cout << "f(int)" << endl;
}
//参数类型是整形指针
void f(int*)
{cout << "f(int*)" << endl;
}int main()
{//调用f函数,观察f(NULL);f(nullptr);return 0;
}

运行结果:

在这里插入图片描述

总结:

①为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

②在使用nullptr表示空值时,不需要包含头文件,因为nullptr是C++11作为关键字引入的。

③在C++11中,sizeof(nullptr)与sizeof((void*)0)所占字节数相同。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kali安装nodejs、npm失败

更新apt-get再安装&#xff0c;更新时间比较久&#xff0c;看网速&#xff0c;中间有一些确认步骤 22 apt-get update23 apt-get upgrade24 apt-get install nodejs25 node26 npm27 apt-get install npm

第十届山东省大学生网络安全技能大赛【神秘的base】【小试牛刀】

神秘的base 题目描述 EvAzEwo6E9RO4qSAHq42E9KvEv5zHDt34GtdHGJaHD7NHG42bwd神奇密码&#xff1a; xbQTZqjN8ERuwlzVfUIrPkeHd******LK697o2pSsGDncgm3CBh/Xy1MF4JAWta解题思路 这个题&#xff0c;上午一直零解&#xff0c;后来放出了hint&#xff0c;提示了base64换表。 这…

新零售系统主要功能有哪些?新零售系统开发公司推荐

新零售系统是一套全面的数字化解决方案&#xff0c;旨在帮助实体零售店提升运营效率、优化用户体验并实现持续增长。以下是新零售系统的主要功能&#xff1a; l 用户画像&#xff1a;系统通过收集和分析顾客的行为、偏好、购买历史等数据&#xff0c;构建出完整的用户画像。这…

2023.10.19 关于设计模式 —— 单例模式

目录 引言 单例模式 饿汉模式 懒汉模式 懒汉模式线程安全问题 分析原因 引言 设计模式为编写代码的 约定 和 规范 阅读下面文章前建议点击下方链接明白 对象 和 类对象 对象和类对象 单例模式 单个实例&#xff08;对象&#xff09;在某些场景中有特定的类&#xff0c;…

XPS就是分一下峰没你想的那么简单!-科学指南针

还记得前一段时间的一篇刷屏的经典文章吗! 林雪平大学(Linkping University)的Grzegorz Greczynski和Lars Hultman二人发表观点性文章&#xff0c;对诺奖得主K. Siegbahn推荐的XPS校准方法可能存在的问题进行了阐述与批评&#xff0c;并提出建议。文章原标题为“Compromising S…

程序员的金饭碗在哪里?这几个网站建议收藏!帮助你一步登天

俗话说的好&#xff0c;一个趁手的工具抵过诸葛亮。尤其是在程序员这个领域&#xff0c;不仅是一个非常和科技挂钩的领域&#xff0c;而且更新速度非常的迅速。 连java python都在更新&#xff0c;手头上写码的工具却还是老三样怎可行&#xff1f;这就需要我们跟上时代的脚步&…

统信操作系统UOS上安装arm64版nginx

原文链接&#xff1a;统信操作系统UOS上安装arm64版nginx hello&#xff0c;大家好啊&#xff0c;今天给大家带来一篇在统信桌面操作系统UOS上安装arm64版nginx的文章&#xff0c;本篇文章主要是给大家提供一种下载离线nginx软件包的方法&#xff0c;拿到软件包可以去不能链接互…

众和策略:华为汽车概念活跃,圣龙股份斩获12板,华峰超纤涨10%

华为轿车概念23日盘中再度生动&#xff0c;到发稿&#xff0c;华峰超纤涨超10%&#xff0c;佛山照明、圣龙股份、隆基机械、银宝山新等涨停&#xff0c;赛力斯涨近6%。 值得注意的是&#xff0c;圣龙股份已接连12个交易日涨停。 昨日晚间&#xff0c;圣龙股份宣布前三季度成果…

contenteditable实现文本内容确认提示

功能需求&#xff1a; 列表进行批量查询&#xff0c;需要对输入的值做提交校验&#xff0c;分三种情况&#xff1a; 若部分字符串有误&#xff0c;部分字符串需要变更字体颜色做提示&#xff0c;再次点击确认则对部分正确数据执行批量查询 若全部数据有误则变更字体颜色做提示&…

win7录屏软件哪个好用?盘点3款实用软件

在当今科技迅猛发展的时代&#xff0c;录屏已经成为了教育、演示和内容创作的重要工具。对于使用windows 7操作系统的用户来说&#xff0c;选择合适的录屏软件至关重要。可是win7录屏软件哪个好用呢&#xff1f;在本文中&#xff0c;我们将介绍3款常用的win7录屏软件。通过比较…

鸿蒙状态栏设置

鸿蒙状态栏设置 基于鸿蒙 ArkTS API9&#xff0c;设置状态栏颜色&#xff0c;隐藏显示状态栏。 API参考文档 参考文档 新建项目打开之后发现状态栏是黑色的&#xff0c;页面颜色设置完了也不能影响状态栏颜色&#xff0c;如果是浅色背景&#xff0c;上边有个黑色的头&#…

忆联SR-IOV解决方案:助力云数据中心节能提效,向“绿”而行

随着AI时代的到来&#xff0c;云数据中心如何实现节能提效正成为热门话题。其中&#xff0c;SR-IOV技术凭借灵活度高以及可节约虚拟化业务算力等优势&#xff0c;是打造绿色低碳云数据中心的重要解决方案之一。 一、什么是SR-IOV 技术 SR-IOV 是由国际组织 PCI-SIG 组织定义的…

65%更小的APK和70%更少的内存:如何优化我的Android App的内存

65%更小的APK和70%更少的内存&#xff1a;如何优化我的Android App的内存 (Note: This is a translation of the provided title) 为什么应用程序内存很重要&#xff1f; 使用最少的内存的高效应用程序可以提升性能&#xff0c;节省设备资源并延长电池寿命。它们提供流畅的用…

同为科技(TOWE)机架PDU产品在IDC数据中心机房建设中的应用

当今社会互联网发展迅速&#xff0c; 随着带宽需求的提升&#xff0c; 网络的保密性、安全性的要求就越来越迫切。PDU(Power Distribution Unit) 是 PDU具备电源分配和管理功能的电源分配管理器。PDU电源插座是多有设备运行的第一道也是最为密切的部件&#xff0c; PDU的好坏直…

html内连框架

src:引用页面地址 name&#xff1a;框架标识名称 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <!--iframe src&#xff1a;地址 w-h&#xff…

电商行业常见信息化工具及电商API接口一体化解决方案

主流的电商行业随着市场趋势发展&#xff0c;企业管理需求也日渐增多&#xff0c;不同的业务管理又有不同的系统支撑&#xff0c;业务增长的同时&#xff0c;数据的交互、管理的难点也在频频而出&#xff0c;那么电商企业如何实现信息一体化&#xff1f;如何解决目前存在的多系…

JVM 基础篇:类加载器

一.了解JVM 1.1什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟计算机功能来实现的&#xff0c;JVM屏蔽了与具体操作系统平台相关的信息&#xff0c;Java程序只需…

【React】高频面试题

1. 简述下 React 的事件代理机制&#xff1f; React使用了一种称为“事件代理”&#xff08;Event Delegation&#xff09;的机制来处理事件。事件代理是指将事件处理程序绑定到组件的父级元素上&#xff0c;然后在需要处理事件的子元素上触发事件时&#xff0c;事件将被委托给…

Python —— hou.NetworkItem class

在一个network内&#xff0c;所有可见元素的基类&#xff1b; 此类没有方法&#xff0c;仅作为 hou.NetworkMovabelItem、hou.NodeConnection 基类存在&#xff0c;这两个子类在网络编辑器内均是可见的&#xff0c;是没有真正有意义的基类的&#xff1b;通过提供一个公共的基类…

deque的简单了解

介绍 deque是一种结合了list和vector两者优势的一种容器&#xff0c;它既可以支持下标的随机访问&#xff0c;并且头插头删的效率都不低&#xff0c;但相对也存在一定的缺陷&#xff0c;在中间插入和遍历上&#xff0c;消耗相对较大。 deque并不是真正连续的空间&#xff0c;…