STL—容器—string类【对其结构和使用的了解】【对oj相关练习的训练】

STL—容器—string类

其实string类准确来说并不是容器,因为他出现的时间比STL要早,但是也可以说是容器吧。

1.为什么要学习string类?

1.1C语言当中的字符串

C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

1.2面试题

415. 字符串相加 - 力扣(LeetCode)

在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本

都使用string类,很少有人去使用C库中的字符串操作函数。

2.标准库中的string类

2.1string类的了解

string类的文档介绍

  1. 字符串是表示字符序列的类

  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。

  3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。

  4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。

  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。

总结:

  1. string是表示字符串的字符串类

  2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。

  3. string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;

  4. 不能操作多字节或者变长字符的序列。

使用string类时,必须包含#include头文件以及using namespace std;

我们在包含头文件的时候经常会遇到两个比较容易混淆的头文件引用#include<string.h> 和 #include ,两者的主要区别如下:

#include<string.h>是C语言的标准库,主要是对字符串进行操作的库函数,是基于char*进行操作的,例如常见的字符串操作函数stpcpy、strcat都是在该头文件里面声明的。

#include是C++语言的标准库,该库里面定义了string类,你可以包含这个头文件,然后定义一个字符串对象,对于字符串的操作就基于该对象进行,例如:string str;

一般来说,c++的头文件不会有.h的出现,比如

————————————————

文档方面,个人觉得这个比较好用

- C++ Reference

作为一个程序员,查文档是一个必须具备的基本素质,当遇到一个不熟悉的接口需要使用的时候,查文档就是最好的解决方法,因此我们需要学会怎么查文档。

2.2string类的常用接口说明

2.2.1.string类的常见构造

image-20240617000544460

c++98版本中全部的构造

image-20240617002205885

实例:

// 初识string类 
// string类 有很多的接口和成员函数,我们主要得熟悉的使用其中的2成,剩下的8成需要我们去通过网络查询来解决
# include<string>
# include<iostream>using namespace std;
int main()
{// 关于string类的构造string s1; // 构造string s2("string"); // 直接构造string s3(s2); // 拷贝构造// 上面这三个最常用string s4(10, 's'); // string类中的的不常用的特殊构造string s5("hello", 1, 3); // string类中的不常用的特殊构造 [这里如果给的不是3 是过大的值,那么就是npos,意思就是将字符串后面有多少给多少] 这些知识都可以查文档查到// 能使用 << 来输出是因为 库中 已经对<< 进行了重载cout << s1 << endl; // [这里默认是空串]cout << s2 << endl; // stringcout << s3 << endl; // stringcout << s4 << endl; // sssssssssscout << s5 << endl; // ell [取"hello"中的 第 1~3号元素来构造的, 正好就是ell]string s6 = s4; // 这里还是拷贝构造string s7 = "string"; // 这里正常来说就是发生隐式类型转化 意味着,先直接构造,在拷贝构造// 但是这里的直接构造 + 拷贝构造发生在了同一表达式,因此编译器直接优化成直接构造cout << s6 << endl; // sssssssssscout << s7 << endl; // stringreturn 0;
}
2.2.2string类对象的容量操作

常见的与容量相关的接口:

image-20240617005128425

接口的代码使用:

1.size(重点)

size可以统计字符串的有效字符长度并返回。一般来说会用作遍历。

// string类对象有关容量的常见接口
// 1.size()
# include<string>
# include<iostream>
using namespace std;int main()
{	string s("hello");cout << "s: ";// 遍历for (size_t i = 0; i < s.size(); i++){s[i] += 1; // 写 [这个相当于对取出来的字符+1,就相当于给其ASCII码值+1]}for (size_t i = 0; i < s.size(); i++){cout << s[i]; // 读}cout << endl; //s8: ifmmp [hello每个字符的ASCII码值分别+1]return 0;
}
2.length

length也会统计字符串的有效长度并返回。其实和size是非常像的,甚至其底层的实现原理都是一样的、

其实在早期的时候用的都是length,但是后面数据结构都用size了,就统一用size了,length和size可以说就是一样的,这里推荐使用size

// 2.length# include<string>
# include<iostream>
using namespace std;void test_string()
{string s1("hello, world");cout << s1.size() << endl; // 12cout << s1.length() << endl; // 12}int main()
{test_string();return 0;
}
3.capacity

capacity可以返回当前空间的总大小

// 3.capacity
# include<string>
# include<iostream>
using namespace std;int main()
{string s("hello, world");cout << s.capacity() << endl; // 15// 目前s有12个空间存放数据,如果超出空间,会增容多少呢?s += "ddddd";cout << s.capacity() << endl; // 31// 可以发现,直接将其增容到了2倍的容量。return 0;
}
4.clear(重点)

清空字符串内容 【注意,空间不会被销毁,只是内容被清空了】

// 4.clear# include<string>
# include<iostream>
using namespace std;int main()
{string s("hello, world");cout << s << endl; // hello, worlds.clear();cout << s << endl; // 空串// 我们清除了字符串内容,不代表空间被销毁了、cout << s.capacity() << endl; // 15return 0;
}
5.empyt(重点)

empty可以检测字符串是否为空串,是就返回true,不是就返回false

//5.empty# include<string>
# include<iostream>
using namespace std;int main()
{string s("hello, world");if (s.empty())cout << "该string类对象为空" << endl;elsecout << "该string类对象不为空" << endl;s.clear();if (s.empty())cout << "该string类对象为空" << endl;elsecout << "该string类对象不为空" << endl;return 0;
}
6.reserve/resize(重点)

在学习这两个接口之前,我们先来看一个代码:

这个代码可以观察到每次增容时容量的变化大小

# include<string>
# include<iostream>
using namespace std;int main()
{string s;size_t sz = s.capacity();cout << "s_capacity grow\n";for (int i = 0; i < 100; i++){s.push_back('c'); // 也可以s += 'c'if (sz != s.capacity()) // != 的时候就说明s进行了增容{sz = s.capacity(); // 将新容量给到szcout << "new capacity: " << sz << endl; // 将此时的容量打印出来}}return 0;
}

image-20240617164339500

我们发现是接近1.5倍增容的。但是我们之前知道15容量在增容的时候是按两倍增容增到31的、

规律是:空间基数越大,增容的倍数越小

因为增容是有代价的。增容越多的空间,执行越多次增容,代价就越大。

知道了这个小知识,我们就可以来看resize和reserve了。

reserve给字符串预留空间。

其实就是给字符串开辟空间

// 6.resize/reserve
# include<string>
# include<iostream>
using namespace std;int main()
{string s;s.reserve(100); // 我们知道s需要100个空间,提前开好空间size_t sz = s.capacity();cout << "s_capacity grow\n";for (int i = 0; i < 100; i++){s.push_back('c'); // 也可以s += 'c'if (sz != s.capacity()) // != 的时候就说明s进行了增容{sz = s.capacity(); // 将新容量给到szcout << "new capacity: " << sz << endl; // 将此时的容量打印出来}}return 0;
}

image-20240617165039849

由于我们提前开辟好了100个空间【实际上不一定会开100个,因为要考虑内存对齐,最后还要放个\0】,s没有再执行增容操作。

这样我们只增容了一次,比起自动增容的次数就减少了许多。

image-20240617165453007

直接开辟了111个空间,并不是我们输入的100。【了解一下】

resize:在reserve的基础上,将有效字符的个数修改,并填充字符

int main()
{string s;//s.reserve(100); // 我们知道s需要100个空间,提前开好空间s.resize(100); // 将有效字符个数修改到100,并填充\0size_t sz = s.capacity();cout << "s_capacity grow\n";for (int i = 0; i < 100; i++){s.push_back('c'); // 也可以s += 'c'if (sz != s.capacity()) // != 的时候就说明s进行了增容{sz = s.capacity(); // 将新容量给到szcout << "new capacity: " << sz << endl; // 将此时的容量打印出来}}return 0;
}

image-20240617165704803

可以看到它相当于reserve(100)并且将有效字符个数修改到了100,并且填充了\0、

image-20240617171034866

由于前100个空间被resize填充了\0,因此后面还是会执行增容操作

因此如果想后面不执行增容操作,这里要用reserve

我们还可以指定填充的字符

int main()
{string s;//s.reserve(100); // 我们知道s需要100个空间,提前开好空间//s.resize(100); // 将有效字符个数修改到100,并填充\0s.resize(100,'6'); // 将有效字符修改到100,并填充6// 因此如果想后面不执行增容操作,这里要用reservesize_t sz = s.capacity();cout << "s_capacity grow\n";for (int i = 0; i < 100; i++){s.push_back('c'); // 也可以s += 'c'if (sz != s.capacity()) // != 的时候就说明s进行了增容{sz = s.capacity(); // 将新容量给到szcout << "new capacity: " << sz << endl; // 将此时的容量打印出来}}return 0;
}

image-20240617165942993

可以看到不再填充\0而是填充我们指定的字符6

image-20240617170946266

并且由于前100个空间都被resize填入了元素,因此后面插入100个c的时候还是会增容的

因此如果想后面不执行增容操作,这里要用reserve

总结(重要):

string容量相关方法使用代码演示

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  2. clear()只是将string中有效字符清空,不改变底层空间大小
  3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变
string s1("hello, world");
s1.resize(5); // 会将原来的size减小到 5。
cout << s1 << endl; // hellos1.resize(20, 'x'); // 将size改到20,由于前5个已经有元素了,后15个填入x【空间不够会自动扩容】
cout << s1 << endl; // helloxxxxxxxxxxxxxxx
  1. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小
注意:
  1. 上面我们讲的有关容量的接口都是常用的,并不是全部。全部的接口可以去文档中查看
  2. 在查看接口的时候,目前来说只需要查看接口如何使用,不用查看接口的底层实现,因为以目前的水平,是完全看不懂的。
  3. 常用的接口需要熟悉使用、

2.2.3string类对象的访问及遍历操作

image-20240617183351615

string中元素访问及遍历代码演示

下面我们对于遍历一共有3种方法【[] + 下标】【迭代器】【范围for】

拓展:迭代器

我们来了解一下迭代器

image-20240617120225600

如图所示,迭代器一共四种,这里我们就是了解一下,具体的我们后面会详细学习。

遍历的代码:

void test_string3()
{// 迭代器一共有4种迭代器,这里在介绍一种string s("hello world");// 倒着遍历string::reverse_iterator rit = s.rbegin(); //要用rbegin,指向字符串的最后一个有效元素// auto rit = s.rbegin();while (rit != s.rend()) // rend,指向字符串的首元素{cout << *rit;rit++; // 其实是倒着走的}cout << endl;// dlrow olleh
}int main()
{	// [] + 下标  【平常推荐使用这个】string s("hello");cout << "s: ";// 遍历for (size_t i = 0; i < s.size(); i++){s[i] += 1; // 写 [这个相当于对取出来的字符+1,就相当于给其ASCII码值+1]}for (size_t i = 0; i < s.size(); i++){cout << s[i]; // 读}cout << endl; //s8: ifmmp [hello每个字符的ASCII码值分别+1]// 迭代器【每个容器都会有自己的迭代器】【迭代器一共有四种】(这里了解一下迭代器)string::iterator it = s.begin(); // string::iterator 实际是一个类型//auto it = s1.begin(); // 也可以这样写 [自动推演]// 遍历while (it != s.end()){*it -= 1; // 写++it; // 迭代}it = s.begin(); // 重置while (it != s.end()){cout << *it; // 读++it; // 迭代}cout << endl;// hellotest_string3(); // 另外一种迭代器的使用// 上述是迭代器的使用方法,熟悉一下就行,后面会详细学习。// 范围for(c++11)  [原理其实就是迭代器]for (auto ch : s) // 自动把s8从左到右依次给到ch auto会自动推断类型{cout << ch;}cout << endl; //helloreturn 0;
}

再来看一个场景:

  • 将字符串转化为整数
// 将传进来的字符串转化成整数 【使用迭代器】
int string2int(const string& str)// 用引用提高效率,并且不改变str,const修饰
{int val = 0;string::const_iterator cit = str.begin(); // 此时的str是const对象,返回的是const类型的迭代器类型while (cit != str.end()){val *= 10;val += (*cit - '0');}cout << val << endl;
}int main()
{// 将字符串转化成整数string s("12345");int val = 0; for (int i = 0; i < s.size(); i++) // 遍历{// 让val + 上取出来的数字,然后再*10, 循环,直至全部取出、val *= 10; val += (s[i] - '0'); // -'0'是因为 取出来的是字符 而不是整形, - 去'0'的ASCII值才是对应整形}cout << val << endl; // 12345string s1("12345");int ret = string2int(s1);cout << ret << endl; // 12345return 0;
}

通过上面两个例子,我们了解到了遍历有不同的方式去遍历。

在这里面当中,迭代器似乎是一个比较麻烦的使用方式。

从方向上分:正向和反向迭代器

从权限上分:普通迭代器,const迭代器。

因此使用的时候似乎不吃香,从短期来看确实是如此,因为经过了c语言的学习,我们已经习惯于用数组的方式去遍历。但是数组这个方式只能用于vector 和 string。等到后面更多的数据结构,也就是容器出现,迭代器就会频繁使用,因为+所有容器的迭代器使用方法都是类似的。

因此迭代器的学习是c++中一个重要的部分。迭代器可以用于所有STL库中的容器的遍历

2.2.4string类对象的修改操作

常见的几个与修改操作相关的接口

image-20240617194843211

1.push_back/append/+=(重要)

push_back:在字符串后边尾插字符

append:在字符串后边追加字符串

+=:在字符串后边追加字符串

这三个我们推荐**+=**

有关尾插的三个接口的使用的代码:

// 1.+= / push_back / append 【有关尾插的三个接口】
# include<string>
# include<iostream>
using namespace std;int main()
{string s1;s1.push_back('p');s1 += 'p'; // 推荐使用+=cout << s1 << endl; //pp  可以看到 += 和 调用尾插接口的结果是一样的s1 += "hello"; // 这里调用的是另外一个 += 的重载函数cout << s1 << endl; // pphellos1.append(" world"); // 在s1后尾插" world"字符串cout << s1 << endl; // pphello world// 在上述三个尾插的操作接口中,我们推荐使用+=return 0;
}

如果想在具体位置插入的话可以使用insert接口,想删除具体位置的话用erase接口

可以上文档查具体使用方法,这里不做详解

2.c_str

image-20240618130116327

c_str: 会将string类对象以const char 的格式返回*

他会在string类对象中找到\0 ,把\0之前的字符串内容当做一个 const char 类型返回*

代码操作:

//2.c_str
# include<string>
# include<iostream>
using namespace std;int main()
{string s("hello");const char* str = s.c_str();// str拿到的是const char* 类型。// 获取字符数组的首地址,用c语言中的字符串形式去遍历while (*str) // 只要*str不是\0就继续{cout << *str;str++;}cout << endl; // hello// 也可以直接输出cout << s << endl; // hello// 这里调用的是string类中的重载的<<, 它会将整个s进行输出cout << s.c_str() << endl; // hello// 这里相当于直接对 const char* 进行输出,遇到\0就会结束输出s += '\0';s += ' ';s += "world";cout << s << endl; // hello world  中间的\0是不可见字符,不会打印出来cout << s.c_str() << endl; // hello  因为从h到 \0 被当做了一个const char*,s.c_str()返回的就是 helloreturn 0;
}
拓展:编码表

我们知道一个中文占据两个字节,这是由编码表实现的,因为中文的编码表是GDK

而英文的编码表是ASCII表

编码的本质是:映射,将对应的值映射到表中的某一个位置。

我们来看一段代码:

// 编码表
# include<string>
# include<iostream>
using namespace std;int main()
{// 我们知道英文是用ASCII码表来编码的string s = "中国"; // 中文使用GDK来编码的cout << s << endl; //中国s[3] = -7;cout << s << endl; // 中郭s[3] = -8;cout << s << endl; // 中锅s[3] = -9;cout << s << endl; // 中棍return 0;
}

下图是s字符串中存储的信息:

image-20240618234637031

可以很清楚的看到中文是两个字节共同编码成一个中文。

3.find/rfind/substr(重要)

image-20240619005428685

find: 可以查询字符串中的某个字符

如果找不到会返回npos【rfind找不到也一样返回npos】

image-20240620170550769

npos是-1 size_t的-1相当于int类型的最大值,42亿多

image-20240620171505713

substr:可以返回指定位置以后得字符串。如果不指定就是默认从头开始

来看一段代码:

//3.find/rfind
# include<string>
# include<iostream>
using namespace std;int main()
{string s("text.cpp"); // 如果我们想查询这个后缀.cpp// 我们就可以用find去查询.  再将其后边的打印出来size_t pos = s.find('.'); // pos = 4if (pos != string::npos) // npos是-1  size_t的-1相当于int类型的最大值,42亿多{// 用substr接口实现.后的打印cout << s.substr(pos) << endl; // .cpp// s.substr(pos)就是打印pos之后的数据,包括pos}return 0;
}

rfind:可以查询字符串中的一个字符,并且是最后一次出现的

//3.find/rfind
# include<string>
# include<iostream>
using namespace std;int main()
{string s("text.cpp"); // 如果我们想查询这个后缀.cpp// 我们就可以用find去查询.  再将其后边的打印出来size_t pos = s.find('.'); // pos = 4if (pos != string::npos) // npos是一个-1  size_t的-1相当于int类型的最大值,42亿多{// 用substr接口实现.后的打印cout << s.substr(pos) << endl; // .cpp// s.substr(pos)就是打印pos之后的数据,包括pos}// 还会有一种情况,如果想查询的字符串有多个后缀,我们想输出最后一个后缀的话// 我们就可以用rfind 重复的查找.  找到最后一个.string s1("test.cpp.zip"); // pos1 = 8size_t pos1 = s1.rfind('.');if (pos1 != string::npos){cout << s1.substr(pos1) << endl; // .zip}return 0;
}
拓展:网址

平常我们看到的网址是由协议、域名、资源名称

// 网址
# include<string>
# include<iostream>
using namespace std;// 协议、域名、资源名称
int main()
{string url("https://gitee.com/wzf-sang");//https是协议 http和https的差别就是https是加密的///gitee.com其实是个ip但是绑定了域名。如果不绑定域名这里是个ip【域名更好记住】//wzf-sang就是资源名称。//【在我们输入网址敲回车之后,服务器做的第一件事就是将你输入的网址拆成协议、域名、资源名称】//【因此才能在对应协议下申请访问对应的域名并根据资源名称返回资源】// 现在有个要求:分离出url。size_t i1 = url.find(':'); // i1 = 5if (i1 != string::npos){cout << url.substr(0, i1) << endl; // https//从0这个下标,输出i1个元素}size_t i2 = url.find('/', i1 + 3); // 从i1 + 3开始找if (i2 != string::npos){cout << url.substr(i1 + 3, i2 - i1 - 3) << endl;// gitee.com// 从i1 + 3这个下标,输出i2 - i1 - 3个元素}cout << url.substr(i2 + 1) << endl; //wzf-sangreturn 0;
}

而我们可以将其功能分离出来,抽象成一个函数

// 网址
# include<string>
# include<iostream>
using namespace std;// 该函数用于分离网址的三个必要信息
void spilt_url(const string& url)
{//【在我们输入网址敲回车之后,服务器做的第一件事就是将你输入的网址拆成协议、域名、资源名称】//【因此才能在对应协议下申请访问对应的域名并根据资源名称返回资源】// 现在有个要求:分离出url。size_t i1 = url.find(':'); // i1 = 5if (i1 != string::npos){cout << url.substr(0, i1) << endl; // https//从0这个下标,输出i1个元素}size_t i2 = url.find('/', i1 + 3); // 从i1 + 3开始找if (i2 != string::npos){cout << url.substr(i1 + 3, i2 - i1 - 3) << endl;// gitee.com// 从i1 + 3这个下标,输出i2 - i1 - 3个元素}// 在i2这个下标后面的都是资源名称cout << url.substr(i2 + 1) << endl; // wzf-sang// + 1是因为i2是 / ,i2后面的才是资源名称
}// 协议、域名、资源名称
int main()
{string url("https://gitee.com/wzf-sang");string url2("https://leetcode.cn/problems/majority-element/description/?envType=study-plan-v2&envId=top-interview-150");//https是协议 http和https的差别就是https是加密的///gitee.com其实是个ip但是绑定了域名。如果不绑定域名这里是个ip【域名更好记住】//wzf-sang就是资源名称。spilt_url(url);//	https//	gitee.com//	wzf - sangspilt_url(url2);//https//leetcode.cn//problems/majority-element/description/?envType=study-plan-v2&envId=top-interview-150return 0;
}

2.2.5string类非成员函数

image-20240619011949494

上面的几个接口了解一下,下面的OJ题目中会有一些体现他们的使用。string类中还有一些其他的操作,这里不一一列举,在需要用到时不明白了查文档即可。

2.2.6.vs和g++下string结构的说明

注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

  • vs下string的结构

string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字

符串的存储空间

当字符串长度小于16时,使用内部固定的字符数组来存放

当字符串长度大于等于16时,从堆上开辟空间

这种设计是合理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内

部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。

其次:还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量

最后:还有一个指针做一些其他事情。

故总共占16+4+4+4=28个字节

image-20240705222701207

  • g++下string的结构

G++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指

针将来指向一块堆空间内部包含了如下字段:

  1. 空间总大小

  2. 字符串有效长度

  3. 引用计数

struct _Rep_base
{size_type _M_length;size_type _M_capacity;_Atomic_word _M_refcount;
};
  1. 指向堆空间的指针,用来存储字符串。

2.2.7与string相关的oj题目

  1. 917. 仅仅反转字母 - 力扣(LeetCode)

  2. 387. 字符串中的第一个唯一字符 - 力扣(LeetCode)

  3. 字符串最后一个单词的长度

  4. 125. 验证回文串 - 力扣(LeetCode)

  5. 415. 字符串相加 - 力扣(LeetCode)

  6. 541. 反转字符串 II - 力扣(LeetCode)

  7. 557. 反转字符串中的单词 III - 力扣(LeetCode)

  8. 43. 字符串相乘 - 力扣(LeetCode)较难

  9. 找出字符串中第一个只出现一次的字符较难

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

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

相关文章

CTFShow的RE题(三)

数学不及格 strtol 函数 long strtol(char str, char **endptr, int base); 将字符串转换为长整型 就是解这个方程组了 主要就是 v4, v9的关系&#xff0c; 3v9-(v10v11v12)62d10d4673 v4 v12 v11 v10 0x13A31412F8C 得到 3*v9v419D024E75FF(1773860189695) 重点&…

Windows ipconfig命令详解,Windows查看IP地址信息

「作者简介」&#xff1a;冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础著作 《网络安全自学教程》&#xff0c;适合基础薄弱的同学系统化的学习网络安全&#xff0c;用最短的时间掌握最核心的技术。 ipconfig 1、基…

Android Studio Run窗口中文乱码解决办法

Android Studio Run窗口中文乱码解决办法 问题描述&#xff1a; AndroidStudio 编译项目时Run窗口中文乱码&#xff0c;如图&#xff1a; 解决方法&#xff1a; 依次打开菜单&#xff1a;Help--Edit Custom VM Options&#xff0c;打开studio64.exe.vmoptions编辑框&#xf…

计算机专业怎么选择电脑

现在高考录取结果基本已经全部出来了&#xff0c;很多同学都如愿以偿的进入到了计算机类专业&#xff0c;现在大部分同学都在为自己的大学生活做准备了&#xff0c;其中第一件事就是买电脑&#xff0c;那计算机类专业该怎么选择电脑呢&#xff1f; 计算机专业是个一类学科&…

网络中的网络 NiN

一、全连接层问题 1、卷积层的参数&#xff1a;输入的通道数乘以输出的通道数再乘以窗口的高宽 2、全连接层的参数就是输入的元素个数乘以输出的元素个数&#xff0c;也就是输入的通道数乘以输入的高宽&#xff0c;再乘以输出的通道数乘以输出的高宽&#xff0c;贼大的量级 …

NLP简介

自然语言处理( Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门融语言学、计算机科学、数学于一体的科学。因此&#xff0c;这一领域的研究将涉及自…

【算法】(C语言):冒泡排序、选择排序、插入排序

冒泡排序 从第一个数据开始到第n-1个数据&#xff0c;依次和后面一个数据两两比较&#xff0c;数值小的在前。最终&#xff0c;最后一个数据&#xff08;第n个数据&#xff09;为最大值。从第一个数据开始到第n-2个数据&#xff0c;依次和后面一个数据两两比较&#xff0c;数值…

关于用户咨询华为擎云L410笔记本安装Windows系统的说明

同样也是单位购买的华为擎云L410 KLVU-WDU0笔记本电脑&#xff0c;国产UOS系统某些软件用着不是很方便&#xff0c;用户咨询是否能够安装Windows10或者Windows7&#xff1f; 带着种种疑问也做了一些查询&#xff0c;之前也给一些国产设备更改过操作系统&#xff0c;之前的国产设…

计算机网络浅谈—什么是 OSI 模型?

开放系统通信&#xff08;OSI&#xff09;模型是一个代表网络通信工作方式的概念模型。 思维导图 什么是 OSI 模型&#xff1f; 开放系统互连 (OSI) 模型是由国际标准化组织创建的概念模型&#xff0c;支持各种通信系统使用标准协议进行通信。简单而言&#xff0c;OSI 为保证…

智能交通(3)——Learning Phase Competition for Traffic Signal Control

论文分享 https://dl.acm.org/doi/pdf/10.1145/3357384.3357900https://dl.acm.org/doi/pdf/10.1145/3357384.3357900 论文代码 https://github.com/gjzheng93/frap-pubhttps://github.com/gjzheng93/frap-pub 摘要 越来越多可用的城市数据和先进的学习技术使人们能够提…

【pytorch19】交叉熵

分类问题的loss MSECross Entropy LossHinge Loss &#xff08;SVN用的比较多&#xff09; ∑ i m a x ( 0 , 1 − y i ∗ h θ ( x i ) ) \sum_imax(0,1-y_i*h_\theta(x_i)) ∑i​max(0,1−yi​∗hθ​(xi​)) Entropy&#xff08;熵&#xff09; Uncertainty&#xff08;…

ESP32——物联网小项目汇总

商品级ESP32智能手表 [文章链接] 用ESP32&#xff0c;做了个siri&#xff1f;&#xff01;开源了&#xff01; [文章链接]

UDP协议:独特之处及其在网络通信中的应用

在网络通信领域&#xff0c;UDP&#xff08;用户数据报协议&#xff0c;User Datagram Protocol&#xff09;是一种广泛使用的传输层协议。与TCP&#xff08;传输控制协议&#xff0c;Transmission Control Protocol&#xff09;相比&#xff0c;UDP具有其独特的特点和适用场景…

02STM32环境搭建新建工程

STM32环境搭建&新建工程 软件安装&#xff1a;开发方式&新建工程步骤&架构 个人心得 软件安装&#xff1a; 安装Keil5 MDK 安装器件支持包 软件注册 安装STLINK驱动 安装USB转串口驱动 开发方式&新建工程步骤&架构 STM32开发方式&#xff1a; 1.寄存器 …

mysql中的递归函数recursive

递归部门 WITH recursive dept_tree AS (SELECTsd.mine_id AS mine_id,sd.dept_id AS dept_id,sd.tenant_id AS tenant_id,sd.order_num,sd.dept_name AS topName,sd.dept_id AS topIdFROMsys_dept sdWHERE<!-- 加上or后也会查询出dept节点 sd.parent_id #{deptId} or sd.…

uniapp H5页面设置跨域请求

记录一下本地服务在uniapp H5页面访问请求报跨域的错误 这是我在本地起的服务端口号为8088 ip大家可打开cmd 输入ipconfig 查看 第一种方法 在源码视图中配置 "devServer": {"https": false, // 是否启用 https 协议&#xff0c;默认false"port&q…

跨界客户服务:拓展服务边界,创造更多价值

在当今这个日新月异的商业时代&#xff0c;跨界合作已不再是新鲜词汇&#xff0c;它如同一股强劲的东风&#xff0c;吹散了行业间的壁垒&#xff0c;为企业服务创新开辟了前所未有的广阔天地。特别是在客户服务领域&#xff0c;跨界合作正以前所未有的深度和广度&#xff0c;拓…

一文理解 Treelite,Treelite 为决策树集成模型的部署和推理提供了高效、灵活的解决方案

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、什么是 Treelite&#xff1f; Treelite 是一个专门用于将决策树集成模型高效部署到生产环境中的机器学习模型编译器&#xff0c;特别适合处理大批量数据的推理任务&#xff0c;能够显著提升推理性能…

[Vite]Vite插件生命周期了解

[Vite]Vite插件生命周期了解 Chunk和Bundle的概念 Chunk&#xff1a; 在 Vite 中&#xff0c;chunk 通常指的是应用程序中的一个代码片段&#xff0c;它是通过 Rollup 或其他打包工具在构建过程中生成的。每个 chunk 通常包含应用程序的一部分逻辑&#xff0c;可能是一个路由视…

【刷题汇总--大数加法、 链表相加(二)、大数乘法】

C日常刷题积累 今日刷题汇总 - day0061、大数加法1.1、题目1.2、思路1.3、程序实现 2、 链表相加(二)2.1、题目2.2、思路2.3、程序实现 3、大数乘法3.1、题目3.2、思路3.3、程序实现 4、题目链接 今日刷题汇总 - day006 1、大数加法 1.1、题目 1.2、思路 读完题,明白大数相加…