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

C++ Primer 标准库类型string

欢迎阅读我的 【C++Primer】专栏

专栏简介:本专栏主要面向C++初学者,解释C++的一些基本概念和基础语言特性,涉及C++标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级程序设计技术。希望对读者有帮助!

在这里插入图片描述
在这里插入图片描述

目录

  • 3.2标准库类型string
    • 定义和初始化string对象
    • 直接初始化和拷贝初始化
    • string对象上的操作
    • 读写string对象
    • 读取未知数量的string对象
    • string的empty和size操作
    • string::size_type类型
    • 比较string对象
    • 为string对象赋值
    • 两个string对象相加
    • 字面值和string对象相加
    • 处理string对象中的字符
    • 处理每个字符?使用基于范围的for语句
    • 使用范围for语句改变字符串中的字符
    • 使用下标执行随机访问

3.2标准库类型string

标准库类型string表示可变长的字符序列,使用string类型必须首先包含string头文件。作为标准库的一部分,string定义在命名空间std中。接下来的示例
都假定已包含了下述代码:

include < string >
using std::string;
本节描述最常用的string操作。C++标准一方面对库类型所提供的操作做了详细规定,另一方面也对库的实现做出一些性能上的需求。因此,标准库类型对于一般应用场合来说有足够的效率。

定义和初始化string对象

如何初始化类的对象是由类本身决定的。一个类可以定义很多种初始化对象的方式,只不过这些方式之间必须有所区别:或者是初始值的数量不同,或者是初始值的类型不同。下面是几个例子:

string s1;      //默认初始化,s1是一个空字符串
string s2 = s1; //s2是s1的副本
string s3("value"); //s3是该字符串字面值的副本
string s4(10,'c');//s4的内容是cccccccccc

可以通过默认的方式初始化一个string对象,这样就会得到一个守的string,也就是说,该string对象中没有任何字符。如果提供了一个字符串字面值,则该字面值中除了最后那个空字符外其他所有的字符都被拷贝到新创建的string对象中去。如果提供的是一个数字和一个字符,则string对象的内容是给定字符连续重复若干次后得到的序列。

表3.1:初始化string对象的方式

string s1 默认初始化,s1是一个空串
string s2(s1) s2是s1的副本
string s2 = s1 等价于s2(s1),s2是s1的副本
string s3(“value”) s3是宇面值"value"的副木,除了字面值最后的那个空字符外
string s3=“value” 等价于s3(“value”),s3是字面值"value"的副本
string s4(n,‘c’) 把s4初始化为由连续n个字符c组成的串

直接初始化和拷贝初始化

C++语言有几种不同的初始化方式,通过string我们可以清楚地看到在这些初始化方式之间到底有什么区别和联系。如果使用等号(=)初始化一个变量,实际上执行的是拷贝初始化(copy initialization),编译器把等号右侧的初始值拷贝到新创建的对象中去。与之相反,如果不使用等号,则执行的是直接初始化(direct initialization)。

当初始值只有一个时,使用直接初始化或拷贝初始化都行。如果像上面的s4那样初始化要用到的值有多个,一般来说只能使用直接初始化的方式:

string s5="hiyan"; // 拷贝初始化
string s6("hiya"); //直接初始化
string s7(10,"c"); //直接初始化,s7的内容是cccccccccc

对于用多个值进行初始化的情况,非要用拷贝初始化的方式来处理也不是不可以,不过需要显式地创建一个(临时)对象用于拷贝:

string s8 = string(10,'c'); //拷贝初始化,s8的内容是cccccccccc

s8的初始值是string(10,‘c’),它实际上是用数字10和字符c两个参数创建出来的一个string对象,然后这个string对象又拷贝给了s8。这条语句本质上等价于下面的两条语句:

string temp(10,'c'); //temp的肉容是cccccccccc
string s8=temp;      //将temp指贝给s8

其实我们可以看到,尽管初始化s8的语句合法,但和初始化s7的方式比较起来可读性较差,也没有任何补偿优势。

string对象上的操作

一个类除了要规定初始化其对象的方式外,还要定义对象上所能执行的操作。其中,类既能定义通过函数名调用的操作,就像Sales_item类的isbn函数那样,也能定义<<、+等各种运算符在该类对象上的新含义.表3.2中列举了string的大多数操作。

表3.2:string的操作


os<<s 将s写到输出流os当中,返回os

is>>s 从is中读取字符串赋给s,字符串以空白分隔,返回is

getline(is,8) 从is中读取一行赋给s,返回is

s.empty() s为空返回true,否则返回false

s.size() 返回s中字符的个数

s[n] 返回s中第n个字符的引用,位置n从0计起

s1+s2 返回s1和s2连接后的结果

s1=s2 用s2的副本代替s1中原来的字符

s1 == s2 如果s1和s2中所含的字符完全一样,则它们相等;string对象的相等性判断对字母的大小写敏感

<,<=,>,>= 利用字符在字典中的顺序进行比较,且对字母的大小写敏感

读写string对象

使用标准库中的iostream来读写int、double等内置类型的值。同样,也可以使用IO操作符读写stritng对象:

//注意:要想编译下面的代码还需要适当的#include语句和using声明
int main()
{string s;//空字符串cin >> s;//将string对象读入s,遇到空白停止cout << s<<endl;//输出sreturn 0;
}

这段程序首先定义一个名为s的空string,然后将标准输入的内容读取到s中。在执行读取操作时,string对象会自动忽略开头的空白〔即空格符、换行符、制表符等并从第一个真正的字符开始读起,直到遇见下一处空白为止。

如上所述,如果程序的输入是" HelloWor1ld!"(注意开头和结尾处的空格),则输出将是"Hello",输出结果中没有任何空格。

和内置类型的输入输出操作一样,string对象的此类操作也是返回运算符左侧的运算对象作为其结果。因此,多个输入或者多个输出可以连写在一起:

string s1,s2;
cin >> s1 >> s2; //把第一个输入读到s1中,第二个输入读到s2中
cout << sl << s2 << endl;//输出两个string对象

假设给上面这段程序输入与之前一样的内容"hello world!",输出将是 “HelloWorld”。

读取未知数量的string对象

下面编写程序用于读取string对象:

int main()
{string word;while(cin >> word)    //反复读取,直至到达文件末尾cout << word << endl; //逐个输出单词,每个单词后面絮跟一个换行return 0;
}

在该程序中,读取的对象是string而非int,但是while语句的条件部分和之前版本的程序是一样的。该条件负责在读取时检测流的情况,如果流有效,也就是说没遇到文件结束标记或非法,那么执行while语句内部的操作。此时,循环佛将输出刚刚从标准输入读取的内容。重复若干次之后,一旦遇到文件结束标记或非法输入循环也就结束了。

使用getline读取一整行

有时我们希望能在最终得到的字符串中保留输入时的空白符,这时应该用getline函数代替原来的>>运算符。getline函数的参数是一个输入流和一个string对象,函数从给定的输入流中读入内容,直到遇到换行符为止(注意换行符也被读进来了),然后把所读的内容存入到那个string对象中去(注意不存换行符)。getline只要一遇到换
行符就结束读取操作并返回结果,哪怕输入的一开始就是换行符也是如此。如果输入真的一开始就是换行符,那么所得的结果是个空string。

和输入运算符一样,getline也会返回它的流参数。因此既然输入运算符能作为判断的条件,我们也能用getline的结果作为条件。例如,可以通过改写之前的程序让它一次输出一整行,而不再是每行输出一个词了:

int main()
{string line;//每次读入一整行,直至到达文件未尾while(getline(cin,1ine))cout << line << endl;return 0;
}

因为 line中不包含换行符,所以我们手动地加上换行操作符。和往常一样,使用 endl 结束当前行并刷新显示缓冲区。

触发getline函数返回的那个换行符实际上被丢弃了,得到的string对象中并不包含该换行符。

string的empty和size操作

顾名思义,empty函数根据string对象是否为宇返回一个对应的布尔值。和Sales_item类的isbn成员一样,empty也是string的一个成员函数。调用该函数的方法很简单,只要使用点操作符指明是哪个对象执行了empty函数就可以了。

通过改写之前的程序,可以做到只输出非空的行:

    //每次读入一整行,遇到空行直接跳过while(getline(cin,1ine))if(line.empty())cout << line << endl;

在上面的程序中,if语句的条件部分使用了逻辑非运算符(!),它返回与其运算对象相反的结果。此例中,如果size不为空则返回真。

size函数返回string对象的长度(即string对象中字符的个数),可以使用size函数只输出长度超过80个字符的行:

string line;
//每次读入一整行,输出其中超过80个字符的行
while(getline(ctn,line))if(line.size()>80)cout<<line<<endl;

string::size_type类型

对于size函数来说,返回一个int是合情合理的。但其实size函数返回的是一个string::size_type类型的值,下面就对这种新的类型作解释。

string类及其他大多数标准库类型都定义了几种配套的类型。这些配套类型体现了标准库类型与机器无关的特性,类型size_type即是其中的一种。在具体使用的时候,通过作用域操作符来表明名字size_type是在类string中定义的。

尽管我们不太清楚string::size_type类型的细节,但有一点是肯定的:它是一个无符号类型的值而且能足够存放下任何string对象的大小。所有用于存放string类的size函数返回值的变量,都应该是string::size_type类型的。

过去,string::size_type这种类型有点儿神秘,不太容易理解和使用。在C++11新标准中,允许编译器通过auto或者decltype来推断变量的类型:

auto len=line.size(); //len的类型是string::size_type

由于size函数返回的是一个无符号整型数,因此切记,如果在表达式中混用了带符号数和无符号数将可能产生意想不到的结果。例如,假设n是-个具有负值的int,则表达式s.size()< n 的判断结果几乎肯定是true。这是因为负值n会自动地转换成一个比较大的无符号值。

如果一条表达式中已经有了size()函数就不要再使用int了,这样可以邀免混用int和unsigned可能带来的问题。

比较string对象

string类定义了几种用于比较字符串的运算符。这些比较运算符逐一比较string对象中的字符,并且对大小写敏感,也就是说,在比较时同一个字母的大写形式和小写形式是不同的。相等性运算符(==和!=)分别检验两个string对象相等或不相等,string对象相等意味着它们的长度相同而且所包含的字符也全都相同。关系运算符<、<=、>、>=分别检验一个string对象是否小于、小于等于、大于、大于等于另外一个string对象。上述这些运算符都依照(大小写敏感的)字典顺序:

1.如果两个string对象的长度不同,而且较短string对象的每个字符都与较长string对象对应位置上的字符相同,就说较短string对象小于较长string对象。
2.如果两个string对象在树些对应的位置上不一致,则string对象比较的结果其实是string对象中第一对相异字符比较的结果。

下面是string对象比较的一个示例:

string str="Hello";
string phrase="HelloWorld";
string slang="Hiya";

根据规则1可判断,对象str小于对象phrase:根据规则2可判断,对象slang既大于str也大于phrase。

为string对象赋值

一般来说,在设计标准库类型时都力求在易用性上向内置类型看齐,因此大多数库类型都支持赋值操作。对于string类而言,允许把一个对象的值赋给另外一个对象:

string st1(10,’c‘),st2;//st1的内容是cccccccccc;st2是一个空字符串
st1 = st2;  //赋值:用st2的副本替换st1的内容//此时st1和st2都是空字符串

两个string对象相加

两个string对象相加得到一个新的string对象,其内容是把左侧的运算对象与右侧的运算对象串接而成。也就是说,对string对象使用加法运算符(+)的结果是一个新的string对象,它所包含的字符由两部分组成:前半部分是加号左侧string对象所含的字符、后半部分是加号右侧string对象所含的字符。另外,复合赋值运算符(+=)负责把右侧string对象的内容追加到左侧string对象的后面:

string s1 = "hello", s2="world";  // 在s1 和 s2 中都没有标点符号
string s3 = s1 + ", " + s2 + ‘\n’;
string s3 = s1 + s2;              //s3的内容是hello,world
s1 += s2;//等价于s1=s1+s2

字面值和string对象相加

即使一种类型并非所需,我们也可以使用它,不过前提是该种类型可以自动转换成所需的类型。因为标准库允许把字符字面值和字符串字面值转换成string对象,所以在需要string对象的地方就可以使用这两种字面值来替代。利用这一点将之前的程序改写为如下形式:

string s1 = "hello", s2 = "world"; //在s1和s2中都没有标点符号
string s3 = s1+ "," + s2 + '\n';

当把string对象和孙符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符(+)的两侧的运算对象至少有一个是string:

string s4 = s1 + ",";     //正确:把一个string对象和一个字面值相加<20
string s5 = "hello"+",";  //错误:两个运算对象都不是string
//正确;每个加法远算符都有一个运算对象是string
string s6 = s1 + "," + "world";
string s7 = "hello"+","+s2; //错误:不能把字面值直接相加

s4和s5初始化时只用到了一个加法运算符,因此很容易判断是否合法。s6的初始化形式之前没有出现过,但其实它的工作机理和连续输入连续输出是一样的,可以用如下的形式分组:

string s6=(s1+",") + "world";

其中子表达式s1+","的结果是一个string对象,它同时作为第二个加法运算符的左侧运算对象,因此上述语句和下面的两个语句是等价的:

string tmp = s1+",";//正确:加法运算符有一个运算对象是string
s6 = tmp+"world"; //正确;加法运算符有一个运算对象是string

另一方面,s7的初始化是非法的,根据其语义加上括号后就成了下面的形式:

strings7=("hello"+",")+S2;//错误:不能把字面值直接相加

很容易看到,括号内的子表达式试图把两个字符串字面值加在一起,而编详器根本没法做到这一点,所以这条语句是错误的。

因为某些历史原因,也为了与C兼容,所以C++语言中的字符串字面值并不是标准库类型string的对象。切记,字符串字面值与string是不同的类型

处理string对象中的字符

我们经常需要单独处理string对象中的字符,比如检查一个string对象是否包含空白,或者把string对象中的字母改成小写,再或者查看某个特定的字符是否出现等。

这类处理的一个关键问题是如何获取字符本身。有时需要处理string对象中的每一个字符,另外一些时候则只需处理某个特定的字符,还有些时候遇到某个条件处理就要停下来。以往的经验告诉我们,处理这些情况常常要涉及语言和库的很多方面。

另一个关键问题是要知道能改变某个字符的特性。在cctype头文件中定义了一组标准库函数处理这部分工作,表3.3列出了主要的函数名及其含义。

表3.3:cctype头文件中的函数

isalnum©当c是字母或数字时为真
isalpha©当c是孙母时为真
iscntz1©当c是控制守符时为真
tsdigit©当c是数字时为真
isgraph©当c不是空格但可打印时为真
islower©当c是小写字母时为真
isprint©当c是可打印字符时为真〔即c是空格或c具有可视形式)
ispunct©当c是标点符号时为真(即c不是控制字符、数字、字母、可打印空自中的-种)
isspace©当c是空自时为真(即e是空格、横向制表符、纵向制表符、回车符、换行符、迹纸符中的一种)
isupper©当c是大写字母时为真
isxdigit©当c是十六进制数字时为真
tolower©如果c是大写字母,输出对应的小写字母;否则原样输出c
toupper©如果c是小写字母,输出对应的大写字母;否则原样输出c

建议:使用C++版本的C标准库头文件

C++标准库中除了定义C++语言特有的功能外,也兼容了C语言的标准库。C语言的头文件形如name.h,C++则将这些文件命名为cname。也就是去除了.h后缎,而在文件名name之前添加了字母c,这里的c表示这是一个属于C语言标准库的头文件。

因此。cctype头文件和ctype.h头文件的内容是一样的,只不过从命名规范上来讲更符合C++语言的要求。特别的,在名为cname的头文件中定义的名字从属于命名空间std,而定义在名为.h的头文件中的则不然。

一般来说,C++程序应该使用名为ename的头文件而不使用name.h的形式,标准库中的名字总能在命名空间std中找到。如果使用.h形式的头文件,程序员就不得不时刻牢记哪些是从C语言那儿继承过来的,哪些又是C++语言所独有的。

处理每个字符?使用基于范围的for语句

如果想对string对象中的每个字符做点儿什么操作,目前最好的办法是使用C++11新标准提供的一种语句:范围for(range for)语句。这种语句遍历给定序列中的每个元素并对序列中的每个值执行树种操作,其语法形式是:

for(declaration : expyession)
stalenzen

其中,expression部分是一个对象,用于表示一个序列。declaration部分负责定义一个变量,该变量将被用于访问序列中的基础元素。每次迭代,deciaration部分的变量会被初始化为expression部分的下一个元素值。

一个string对象表示一个字符的序列,因此string对象可以作为范围for语句其中的expression部分。举一个简单的例子,我们可以使用范围for语句把string对象中的字符每行一个输出出来:

string str("somestring")
//每行输出str中的一个字符
for(auto c:str)          //对于str中的每个字符cout << c << endl;   //输出当前字符,后面紧跟一个换行符

for循环把变量c和str联系了起来,其中我们定义循环控制变量的方式与定义任意一个普通变量是一样的。此例中,通过使用auto关键字让编译器来决定变量c的类型,这里c的类型是char。每次迭代,str的下一个字符被拷贝给c,因此该循环可以读作"对于字符串str中的每个字符c,"执行某某操作。此例中的"某某操作"即输出一个字符,然后换行。

举个稍微复杂一点的例子,使用范围for语句和ispunct函数来统计string对象中标点符号的个数:

string s("HelloWorld!!");
//punct_cnt的类型和s.size的返回类型一样
decltype(s.size())punct_cnt=0;
//统计s中标点符号的数量
for(auto c:s)        // 对于s中的每一个字符if(itspunct(e))  // 如果该字符是标焯符号++punct_cnt; // 将标点符号的计数值加1
cout<<punct_cnt<<"punctuation characters in" << s << endl;

程序的输出结果将是:
3 punctuation characters in Hello World!!

这里我们使用dec1type关键字声明计数变量punctcnt,它的类型是s.size函数返回值的类型,也就是string::size_type。使用范围for语句处理string对象中的每个字符并检查其是否是标点符号。如果是,使用递增运算符给计数变量加1。最后,待范围for语句结束后输出统计结果。

使用范围for语句改变字符串中的字符

如果想要改变string对象中字符的值,必须把循环变量定义成引用类型。记住,所谓引用只是给定对象的一个别名,因此当使用引用作为循环控制变量时,这个变量实际上被依次绑定到了序列的每个元素上。使用这个引用,我们就能改变它绑定的字符。

新的例子不再是统计标点符号的个数了,假设我们想要把字符串改写为大写字母的形式。为了做到这一点可以使用标准库函数toupper,该函数接收一个字符,然后输出其对应的大写形式。这样,为了把整个string对象转换成大写,只要对其中的每个字符调用toupper函数并将结果再赋给原字符就可以了:

    strings("Hello World!!!");//转换成大写形式for(auto &c:8)//对于s中的每个字符(注意:c是引用)c=toupper(c);//c是一个引用,因此赋值语句将改变s中字符的值cout << s << endl;

上述代码的输出结果将是:

Hello World!!!

每次迭代时,变量c引用string对象s的下一个字符,赋值给c也就是在改变s中对应字符的值。因此当执行下面的语句时,

c= toupper(c);//c是一个引用,因此赋值语句将改变s中字符的值

实际上改变了c绑定的字符的值。整个循环结束后,str中的所有字符都变成了大写形式。

只处理一部分字符?

如果要处理string对象中的每一个字符,使用范围for语句是个好主意。然而,有时我们需要访问的只是其中一个字符,或者访问多个字符但遇到某个条件就要停下来。例如,同样是将字符改为大写形式,不过新的要求不再是对整个字符串都这样做,而仅仅他把string对象中的第一个字母或第一个单词大写化。

要想访问string对象中的单个字符有两种方式:一种是使用下标,另外一种是使用迭代器。

下标运算符([])接收的输入参数是string::size_type类型的值,这个参数表示要访问的字符的位置;返回值是该位置上字符的引用。

string对象的下标从0计起。如果string对象s至少包含两个字符,则s[0]是第1个字符、s[1]是第2个字符、s[s.size()-1]是最后一个字符。

string对象的下标必须大于等于0而小于s.size()。
使用超出此范围的下标将引发不可预知的结果,以此推断,使用下标访问>空string也会引发不可预知的结果。

下标的值称作"下标"或"索引",任何表达式只要它的值是一个整型值就能作为索引。不过,如果某个索引是带符号类型的值将自动转换成由string::size_type,表达的无符号类型。

下面的程序使用下标运算符输出string对象中的第一个字符:

if(!is.empty())//确保确实有字符需要输出cout << s[0] <<endl;  //输出s的第一个字符

在访问指定字符之前,首先检查s是否为空。其实不管什么时候只要对string对象使用了下标,都要确认在那个位置上确实有值。如果s为空,则s[0]的结果将是未定义的。

只要字符串不是常量,就能为下标运算符返回的字符赋新值。例如,下面的程序将字符串的首字符改成了大写形式:

string s("some string")
if(!s.empty())//确保s[0]的位置确实有字符s[0] = toupper(s[0]); // 为s的第一个字符赋一个新的值

程序的输出结果将是:

Some string

使用下标执行迭代
另一个例子是把s的第一个词改成大写形式:

    //依次处理s中的字符直至我们处理完全部字符或者遇到一个空白for(decltype(s.size()) index=0index!=s.size()&&!isspace(s[index]);++index)s[index]=toupper(s[index]);//将当前字符政成大写形式

程序的输出结果将是:

SOME string

在上述程序中,for循环使用变量index作为s的下标,index的类型是由decl1type关键字决定的。首先把index初始化为0,这样第一次迭代就会从s的首字符开始,之后每次迭代将index加1以得到s的下一个字符。循环体负责将当前的字母改写为大写形式。

for语句的条件部分涉及一点新知识,该条件使用了逻辑与运算符(&&)。如果参与运算的两个运算对象都为真,则逻辑与结果为真;否则结果为假。对这个运算符来说最重要的一点是,C++语言规定只有当左侧运算对象为真时才会检查右侧运算对象的情况。如此例所示,这条规定确保了只有当下标取值在合理范围之内时才会真的用此下标去访问字符串。也就是说,只有在index达到s.size()之前才会执行s[index]。随着index的增加,它永远也不可能超过s.size()的值,所以可以确保index比s.size()小。

提示:注意检查下标的合法性

使用下标必须确保其在合理的范围内,也就是说下标必须,大于等于0,而小于字符串的size()的值。一种简便易行的方法是,总是设下标的类型为string::size_type,因为此类型是无符号数,因为此类型是无符号数,可以确保下标不会小于0。此时,代码只需保证下标小于size()的值就史以了。

C++标准并不要求标准库检测下标是否合法。一旦使用了超出范围的下标,就会产生不可预知的结果。

使用下标执行随机访问

在之前的示例中,我们让字符串的下标每次加1从而按顺序把所有字符改写成了大写形式。其实也能通过计算得到某个下标值,然后直接获取对应位置的字符,并不是每次都得从前往后依次访问。

例如,想要编写一个程序把0到15之间的十进制数转换成对应的十六进制形式,只需初始化一个字符串令其存放16个十六进制"数字":

const string hexdigits = "0123456789RBCDEF";//可能的十六进制数字
cout << "Enter a series of numbers between 0 and 15"<<" separated by spaces. Hit ENTER when finished:"<<endl;
string result;       //用于保存十六进制的字符串
string::size_type n; //用于保存从输入流读取的数while(cin >> n)if(n<hexdigits.size()) //忽略无效输入result+= hexdigits[n];//得到对应的十六进制数字
cout<<"Your hex number is:"<<result<<endl;

假设输入的内容如下:

12 0 5 15 8 15

程序的输出结果将是:

Your hex number is: C05F8F

上述程序的执行过程是这样的:首先初始化变量hexdigits后其存放从0到F的十六进制数字,注意我们把hexdigits声明成了常量,这是因为在后面的程序中不打算再改变它的值。在循环内部使用输入值n作为hexdigits的下标, hexdigits[n]的值就是hexdigits内位置n处的字符。例如,如果n是15,则结果是F:如果n是12,则结果是C,以此类推。把得到的十六进制数字添加到result内,最后一并输出。

无论何时用到字符串的下标,都应该注意检查其合法性。在上面的程序中,下标n是string::size_type类型,也就是无符号类型,所以n可以确保大于或等于0。在实际使用时,还需检查n是否小于hexdigits的长度。

相关文章:

C++ Primer 标准库类型string

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…...

51c嵌入式~电路~合集25

我自己的原文哦~ https://blog.51cto.com/whaosoft/13241709 一、“开关电源”和“普通电源”的区别 什么叫开关电源 随着电力电子技术的发展和创新&#xff0c;使得开关电源技术也在不断地创新。目前&#xff0c;开关电源以小型、轻量和高效率的特点被广泛应用几乎所有的电…...

Vue3学习笔记-Vue开发前准备-1

一、安装15.0或更高版本的Node.js node -v npm -v 二、创建Vue项目 npm init vuelatest 三、Vue项目结构 node_modules: Vue项目运行的依赖文件public&#xff1a;资源文件夹package.json&#xff1a;信息描述文件...

架构技能(四):需求分析

需求分析&#xff0c;即分析需求&#xff0c;分析软件用户需要解决的问题。 需求分析的下一环节是软件的整体架构设计&#xff0c;需求是输入&#xff0c;架构是输出&#xff0c;需求决定了架构。 决定架构的是软件的所有需求吗&#xff1f;肯定不是&#xff0c;真正决定架构…...

51单片机 05 矩阵键盘

嘻嘻&#xff0c;LCD在RC板子上可以勉强装上&#xff0c;会有一点歪。 一、矩阵键盘 在键盘中按键数量较多时&#xff0c;为了减少I/O口的占用&#xff0c;通常将按键排列成矩阵形式&#xff1b;采用逐行或逐列的“扫描”&#xff0c;就可以读出任何位置按键的状态。&#xf…...

服务SDK三方新版中央仓库和私服发布详解

预备信息Github仓库发布Gradle版本匹配Gradle项目构建全局变量定义Gradle项目Nexus仓库配置与发布过程Gradle项目发布至Sonatype中央仓库配置过程总结当我们在实现一个项目技术总结、工具类封装或SDK封装,通常是为了方便开发者使用特定服务或平台而提供的一组工具和API。您可能…...

jmeter响应数据编码设置

jmeter响应数据编码设置 如果查看结果树的响应数据存在中文乱码&#xff0c;可以尝试以下方法&#xff1a; 1、找到jmeter的bin目录下的 jmeter.properties 文件&#xff0c;修改如下配置&#xff1a; 去掉sampleresult.default.encodingUTF-8前面的#号 2、保存文件后&#x…...

FPGA学习篇——开篇之作

今天正式开始学FPGA啦&#xff0c;接下来将会编写FPGA学习篇来记录自己学习FPGA 的过程&#xff01; 今天是大年初六&#xff0c;简单学一下FPGA的相关概念叭叭叭&#xff01; 一&#xff1a;数字系统设计流程 一个数字系统的设计分为前端设计和后端设计。在我看来&#xff0…...

Leetcode:680

1&#xff0c;题目 2&#xff0c;思路 首先就是判断它不发生改变会不会是回文如果不是回文&#xff0c;那么俩个指针从前往后与从后往前做对比如果俩字符不同&#xff0c;那就俩种选择&#xff0c;一种是保留前面的字符去掉后面字符&#xff0c;另一种是其反然后俩种选择只要满…...

Python教学:文档处理及箱线图等

代码1&#xff1a; import os import pandas as pd import numpy as py import os.path from os import listdir import openpyxl from openpyxl import Workbook import re import matplotlib.pyplot as plt # 导入matplotlib的绘图模块&#xff0c;用于可视化 cwdos.getcwd…...

SQLGlot:用SQLGlot解析SQL

几十年来&#xff0c;结构化查询语言&#xff08;SQL&#xff09;一直是与数据库交互的实际语言。在一段时间内&#xff0c;不同的数据库在支持通用SQL语法的同时演变出了不同的SQL风格&#xff0c;也就是方言。这可能是SQL被广泛采用和流行的原因之一。 SQL解析是解构SQL查询…...

C++STL(一)——string类

目录 一、string的定义方式二、 string类对象的容量操作三、string类对象的访问及遍历操作四、string类对象的修改操作五、string类非成员函数 一、string的定义方式 string是个管理字符数组的类&#xff0c;其实就是字符数组的顺序表。 它的接口也是非常多的。本章介绍一些常…...

C++ Primer 迭代器

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…...

排序算法--归并排序

归并排序是分治法的经典实现&#xff0c;适合大规模数据排序&#xff0c;尤其适合需要稳定排序的场景&#xff08;如数据库排序&#xff09; #include <stdlib.h> // 用于动态内存分配 // 合并两个已排序的子数组 void merge(int arr[], int left, int mid, int right) …...

深入探讨DICOM医学影像中的WADO服务及其具体实现

1. 引言 随着数字化医学影像技术的普及&#xff0c;如何高效、安全地存储、管理和共享医学影像数据成为医疗行业亟待解决的关键问题。DICOM&#xff08;Digital Imaging and Communications in Medicine&#xff09;作为国际公认的医学影像标准&#xff0c;在全球范围内广泛应…...

自定义数据集 使用paddlepaddle框架实现逻辑回归

导入必要的库 import numpy as np import paddle import paddle.nn as nn 数据准备&#xff1a; seed1 paddle.seed(seed)# 1.散点输入 定义输入数据 data [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6…...

信息学奥赛一本通 2112:【24CSPJ普及组】地图探险(explore) | 洛谷 P11228 [CSP-J 2024] 地图探险

【题目链接】 ybt 2112&#xff1a;【24CSPJ普及组】地图探险&#xff08;explore&#xff09; 洛谷 P11228 [CSP-J 2024] 地图探险 【题目考点】 1. 模拟 2. 二维数组 3. 方向数组 在一个矩阵中&#xff0c;当前位置为(sx, sy)&#xff0c;将下一个位置与当前位置横纵坐…...

xxl-job 在 Java 项目的使用 以一个代驾项目中的订单模块举例

能搜到这里的最起码一定知道 xxl-job 是用来干什么的&#xff0c;我就不多啰嗦怎么下载以及它的历史了 首先我们要知道 xxl-job 这个框架的结构&#xff0c;如下图&#xff1a; xxl-job-master&#xff1a;xxl-job-admin&#xff1a;调度中心xxl-job-core&#xff1a;公共依赖…...

javaEE-8.JVM(八股文系列)

目录 一.简介 二.JVM中的内存划分 JVM的内存划分图: 堆区:​编辑 栈区:​编辑 程序计数器&#xff1a;​编辑 元数据区&#xff1a;​编辑 经典笔试题&#xff1a; 三,JVM的类加载机制 1.加载: 2.验证: 3.准备: 4.解析: 5.初始化: 双亲委派模型 概念: JVM的类加…...

模型/O功能之提示词模板

文章目录 模型/O功能之提示词模板什么是提示词模板提示词模板的输入和输出 使用提示词模板构造提示词 模型/O功能之提示词模板 在LangChain框架中&#xff0c;提示词不是简单的字符串&#xff0c;而是一个更复杂的结构&#xff0c;是一个“提示词工程”。这个结构中包含一个或多…...

[Proteus仿真]基于51单片机的智能温控系统

[Proteus仿真]基于51单片机的智能温控系统 基于51单片机的智能温控系统&#xff1a;DS18B20精准测温LCD1602双屏显示三键设置上下限声光报警&#xff0c;支持温度校准、抗干扰设计、阈值记忆。 一.仿真原理图 ​​ 二.模块介绍 温度采集模块&#xff08;DS18B20&#xff0…...

掌握 HTML5 多媒体标签:如何在所有浏览器中顺利嵌入视频与音频

系列文章目录 01-从零开始学 HTML&#xff1a;构建网页的基本框架与技巧 02-HTML常见文本标签解析&#xff1a;从基础到进阶的全面指南 03-HTML从入门到精通&#xff1a;链接与图像标签全解析 04-HTML 列表标签全解析&#xff1a;无序与有序列表的深度应用 05-HTML表格标签全面…...

ChatGPT与GPT的区别与联系

ChatGPT 和 GPT 都是基于 Transformer 架构的语言模型&#xff0c;但它们有不同的侧重点和应用。下面我们来探讨一下它们的区别与联系。 1. GPT&#xff08;Generative Pre-trained Transformer&#xff09; GPT 是一类由 OpenAI 开发的语言模型&#xff0c;基于 Transformer…...

浅谈线段树

文章同步发布于洛谷&#xff0c;建议前往洛谷查看。 前言 蒟蒻终于学会线段树&#xff08;指【模板】线段树 1 1 1&#xff09;啦&#xff01; 线段树思想 我们先来考虑 P3372&#xff08;基础线段树模板题&#xff09;给的操作&#xff1a; 区间修改&#xff08;增加&am…...

深度解读 Docker Swarm

一、引言 随着业务规模的不断扩大和应用复杂度的增加,容器集群管理的需求应运而生。如何有效地管理和调度大量的容器,确保应用的高可用性、弹性伸缩和资源的合理分配,成为了亟待解决的问题。Docker Swarm 作为 Docker 官方推出的容器集群管理工具,正是在这样的背景下崭露头…...

在线知识库的构建策略提升组织信息管理效率与决策能力

内容概要 在线知识库作为现代企业信息管理的重要组成部分&#xff0c;具有显著的定义与重要性。它不仅为组织提供了一个集中存储与管理知识的平台&#xff0c;还能够有效提升信息检索的效率&#xff0c;促进知识的创新和利用。通过这样的知识库&#xff0c;企业可以更好地应对…...

网件r7000刷回原厂固件合集测评

《网件R7000路由器刷回原厂固件详解》 网件R7000是一款备受赞誉的高性能无线路由器&#xff0c;其强大的性能和可定制性吸引了许多高级用户。然而&#xff0c;有时候用户可能会尝试第三方固件以提升功能或优化网络性能&#xff0c;但这也可能导致一些问题&#xff0c;如系统不…...

为什么命令“echo -e “\033[9;0]“ > /dev/tty0“能控制开发板上的LCD不熄屏?

为什么命令"echo -e “\033[9;0]” > /dev/tty0"能控制开发板上的LCD不熄屏&#xff1f; 在回答这个问题前请先阅读我之前写的与tty和终端有关的博文 https://blog.csdn.net/wenhao_ir/article/details/145431655 然后再来看这条命令的解释就要容易些了。 这条…...

vscode软件操作界面UI布局@各个功能区域划分及其名称称呼

文章目录 abstract检查用户界面的主要区域官方文档关于UI的介绍 abstract 检查 Visual Studio Code 用户界面 - Training | Microsoft Learn 本质上&#xff0c;Visual Studio Code 是一个代码编辑器&#xff0c;其用户界面和布局与许多其他代码编辑器相似。 界面左侧是用于访…...

【Java基础-42.3】Java 基本数据类型与字符串之间的转换:深入理解数据类型的转换方法

在 Java 开发中&#xff0c;基本数据类型与字符串之间的转换是非常常见的操作。无论是从用户输入中读取数据&#xff0c;还是将数据输出到日志或界面&#xff0c;都需要进行数据类型与字符串之间的转换。本文将深入探讨 Java 中基本数据类型与字符串之间的转换方法&#xff0c;…...

【ActiveMq RocketMq RabbitMq Kafka对比】

以下是 ActiveMQ、RocketMQ、RabbitMQ 和 Kafka 的对比表格&#xff0c;从复杂性、功能、性能和适用场景等方面进行整理&#xff1a; 特性ActiveMQRocketMQRabbitMQKafka开发语言JavaJavaErlangScala/Java协议支持AMQP、STOMP、MQTT、OpenWire 等自定义协议AMQP、STOMP、MQTT …...

csapp笔记3.6节——控制(1)

本节解决了x86-64如何实现条件语句、循环语句和分支语句的问题 条件码 除了整数寄存器外&#xff0c;cpu还维护着一组单个位的条件码寄存器&#xff0c;用来描述最近的算数和逻辑运算的某些属性。可检测这些寄存器来执行条件分支指令。 CF&#xff08;Carry Flag&#xff09…...

网站快速收录:如何优化网站音频内容?

本文转自&#xff1a;百万收录网 原文链接&#xff1a;https://www.baiwanshoulu.com/60.html 为了优化网站音频内容以实现快速收录&#xff0c;以下是一些关键的策略和步骤&#xff1a; 一、高质量音频内容创作 原创性&#xff1a; 确保音频内容是原创的&#xff0c;避免使…...

音视频入门基础:RTP专题(8)——使用Wireshark分析RTP

一、引言 通过Wireshark可以抓取RTP数据包&#xff0c;该软件可以从Wireshark Go Deep 下载。 二、通过Wireshark抓取RTP数据包 首先通过FFmpeg将一个媒体文件转推RTP&#xff0c;生成RTP流&#xff1a; ffmpeg -re -stream_loop -1 -i input.mp4 -vcodec copy -an -f rtp …...

4-图像梯度计算

文章目录 4.图像梯度计算(1)Sobel算子(2)梯度计算方法(3)Scharr与Laplacian算子4.图像梯度计算 (1)Sobel算子 图像梯度-Sobel算子 Sobel算子是一种经典的图像边缘检测算子,广泛应用于图像处理和计算机视觉领域。以下是关于Sobel算子的详细介绍: 基本原理 Sobel算子…...

深入解析 Redis AOF 机制:持久化原理、重写优化与 COW 影响

深入解析 Redis AOF 机制&#xff1a;持久化原理、重写优化与 COW 影响 1. 引言2. AOF 机制详解2.1 AOF 解决了什么问题&#xff1f;2.2 AOF 写入机制2.2.1 AOF 的基本原理2.2.2 AOF 运行流程2.2.3 AOF 文件刷盘策略 3. AOF 重写机制3.1 AOF 文件为什么会变大&#xff1f;3.2 解…...

机器学习day8

自定义数据集 &#xff0c;使用朴素贝叶斯对其进行分类 代码 import numpy as np import matplotlib.pyplot as pltclass1_points np.array([[2.1, 2.2], [2.4, 2.5], [2.2, 2.0], [2.0, 2.1], [2.3, 2.3], [2.6, 2.4], [2.5, 2.1]]) class2_points np.array([[4.0, 3.5], …...

【前端】ES6模块化

文章目录 1. 模块化概述1.1 什么是模块化?1.2 为什么需要模块化? 2. 有哪些模块化规范3. CommonJs3.1 导出数据3.2 导入数据3.3 扩展理解3.4 在浏览器端运行 4.ES6模块化 参考视频地址 1. 模块化概述 1.1 什么是模块化? 将程序文件依据一定规则拆分成多个文件,这种编码方式…...

【leetcode练习·二叉树拓展】快速排序详解及应用

本文参考labuladong算法笔记[拓展&#xff1a;快速排序详解及应用 | labuladong 的算法笔记] 1、算法思路 首先我们看一下快速排序的代码框架&#xff1a; def sort(nums: List[int], lo: int, hi: int):if lo > hi:return# 对 nums[lo..hi] 进行切分# 使得 nums[lo..p-1]…...

Gurobi基础语法之 addConstr, addConstrs, addQConstr, addMQConstr

在新版本的 Gurobi 中&#xff0c;向 addConstr 这个方法中传入一个 TempConstr 对象&#xff0c;在模型中就会根据这个对象生成一个约束。更重要的是&#xff1a;TempConstr 对象可以传给所有addConstr系列方法&#xff0c;所以下面先介绍 TempConstr 对象 TempConstr TempC…...

游戏引擎 Unity - Unity 设置为简体中文、Unity 创建项目

Unity Unity 首次发布于 2005 年&#xff0c;属于 Unity Technologies Unity 使用的开发技术有&#xff1a;C# Unity 的适用平台&#xff1a;PC、主机、移动设备、VR / AR、Web 等 Unity 的适用领域&#xff1a;开发中等画质中小型项目 Unity 适合初学者或需要快速上手的开…...

Kamailio、MySQL、Redis、Gin后端、Vue.js前端等基于容器化部署

基于容器化的部署方案&#xff0c;通常会将每个核心服务&#xff08;如Kamailio、MySQL、Redis、Gin后端、Vue.js前端等&#xff09;独立运行在不同的容器中&#xff0c;通过Docker或Kubernetes统一管理。以下是具体实现方式和关键原因&#xff1a; 1. 容器化部署的核心思路 每…...

从1号点到n号点最多经过k条边的最短距离

目录 解析方法思路代码解释代码逐行注释1. 头文件和常量定义&#xff1a;2.边的结构体&#xff1a;3.全局变量&#xff1a;4.Bellman-Ford算法实现&#xff1a;5.主函数&#xff1a; 注意事项代码含义为什么需要 backup[a]&#xff1f;举例说明关键点 总结 解析 要实现从1号点…...

模拟实战-用CompletableFuture优化远程RPC调用

实战场景 这是广州某500-900人互联网厂的面试原题 手写并发优化解决思路 我们要调用对方的RPC接口&#xff0c;我们的RPC接口每调用一次对方都会阻塞50ms 但是我们的业务要批量调用RPC&#xff0c;例如我们要批量调用1k次&#xff0c;我们不可能在for循环里面写1k次远程调用…...

【pinia状态管理配置】

pinia状态管理配置 安装main.ts引入自定义user仓库使用自定义仓库 安装 pnpm add piniamain.ts引入 // createPinia() 函数调用创建了一个新的 Pinia 实例。 // 这个实例是状态管理的核心&#xff0c;它将管理应用中所有的 store。 import { createPinia } from pinia app.us…...

SpringBoot 引⼊MybatisGenerator

SpringBoot 引⼊MybatisGenerator 1. 引入插件2. 添加generator.xml并修改3. 生成文件 1. 引入插件 <plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.5</vers…...

在线销售数据集分析:基于Python的RFM数据分析方法实操训练

一、前言 个人练习&#xff0c;文章用于记录自己的学习练习过程&#xff0c;分享出来和大家一起学习。 数据集&#xff1a;在线销售数据集 分析方法&#xff1a;RFM分析方法 二、过程 1.1 库的导入与一些必要的初始设置 import pandas as pd import datetime import matplo…...

LeetCode - #197 Swift 实现找出温度更高的日期

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…...

分析哲学:从 语言解剖到 思想澄清的哲学探险

分析哲学&#xff1a;从 语言解剖 到 思想澄清 的哲学探险 第一节&#xff1a;分析哲学的基本概念与公式解释 【通俗讲解&#xff0c;打比方来讲解&#xff01;】 分析哲学&#xff0c;就像一位 “语言侦探”&#xff0c;专注于 “解剖语言”&#xff0c;揭示我们日常使用的语…...

C++【iostream】数据库的部分函数功能介绍

在 C 编程世界中&#xff0c;iostream 库扮演着举足轻重的角色&#xff0c;它是 C 标准库的核心组成部分&#xff0c;为程序提供了强大的输入输出功能。无论是简单的控制台交互&#xff0c;还是复杂的文件操作&#xff0c;iostream 库都能提供便捷高效的解决方案。本文将深入剖…...