【C++】string类(上):string类的常用接口介绍
文章目录
- 前言
- 一、C++中设计string类的意义
- 二、string类的常用接口说明
- 1. string类对象的常见构造
- 2. string类对象的容量操作
- 2.1 size、capacity 和 empty的使用
- 2.2 clear的使用
- 2.3 reserve的使用
- 2.4 resize的使用
- 3. string类对象的访问及遍历操作
- 3.1 下标[ ] 和 at
- 3.2 迭代器iterator
- 3.3 范围for
- 4. string类对象的修改操作
- 4.1 push_back、append 和 operator+=(在字符串后追加字符)
- 4.2 insert(在字符串任意位置追加字符)
- 4.3 erase(删除指定范围的字符)
- 4.3 replace(替换字符串中指定范围的字符)
- 5. string类对象的字符串操作
- 5.1 c_str的使用
- 5.2 find的使用
- 5.3 rfind的使用
- 5.4 substr(从字符串中提取一个子字符串)
- 6. string类非成员函数
- 6.1 operator+
- 6.2 relational operators系列函数
- 6.3 >>运算符重载 和 getline函数的区别
前言
一、C++中设计string类的意义
二、string类的常用接口说明(string类对象的常见构造、容量操作、遍历操作、修改操作和查找操作等接口,以及一些string类非成员函数的接口)
一、C++中设计string类的意义
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中还提供了一些字符串操作库函数,但是这些库函数与字符串是分离开的,而且底层空间需要用户自己管理,操作繁琐且容易出错(如内存越界、忘记释放内存等)。
C++的string类封装了字符串的存储和操作,提供了更安全、便捷的接口。string类自动管理字符串的内存分配和释放,避免了手动管理内存的复杂性,减少了内存泄漏和悬空指针的风险;string类还提供了丰富的成员函数,如拼接、查找、替换、比较等,简化了字符串的常见操作;而且string类是类型安全的,避免了C语言中字符数组和指针的潜在问题,如类型不匹配或越界访问。
二、string类的常用接口说明
(string类的所有接口说明详见链接: link)
1. string类对象的常见构造
C++11中,std::string类的构造函数的所有重载类型如下:

std::string类对象的常见构造介绍:
| (constructor)函数名称 | 功能说明 |
|---|---|
| string() | 构造空的std::string类对象,即空字符串 |
| string(const char* s) | 用C-string来构造std::string类对象 |
| string(size_t n, char c) | 用n个c字符构造std::string类对象 |
| string(const string& str) | 拷贝构造函数 |
| string (const string& str, size_t pos, size_t len = npos); | 用str中字符串的pos位置往后的len个字符来构造初始化std::string类对象,如果len大于字符串pos位置往后的字符串长度,取到末尾也会停止 |
补充:npos是std::string类中的定义的public静态成员常量,它的数据类型是size_t
size_t 是一种无符号整数类型,当你将 -1 赋值给一个 size_t 类型的变量/常量时,会发生类型转换。由于 -1 是一个负数,而 size_t 是无符号类型(只能表示正数),因此 -1 会被转换为 size_t 类型的最大值。

#include <string>
using namespace std;int main()
{string s1; // 构造空的string类对象s1string s2("hello world"); // 用C格式字符串构造string类对象s2string s3(6, 'x'); // 用6个'x'字符构造string类对象s3string s4(s2); // 用对象s2拷贝构造s4string s5(s2, 5, 10); // 用s2中字符串pos位置往后的10个字符构造s5,// s2中字符串pos位置往后不够10个字符,取到其末尾停止return 0;
}

2. string类对象的容量操作

2.1 size、capacity 和 empty的使用
| 函数名称 | 功能说明 |
|---|---|
| size(通用) | 返回字符串有效字符长度(不包括’\0’) |
| length(用法同size) | 返回字符串有效字符长度 |
| capacity | 返回空间(容量)总大小(不包括’\0’) |
| empty | 检测字符串是否为空串,是返回true,否则返回false |
补充:size()与length()方法底层实现原理完全相同,size()是后来添加的,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
(1) size和capacity的使用
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("wukong");cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;string s2("I love Minecraft");cout << "s2的有效字符长度:" << s2.size() << endl;cout << "s2的容量:" << s2.capacity() << endl;return 0;
}

(2)empty的使用
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1;cout << s1.empty() << endl;string s2("I love Minecraft");cout << s2.empty() << endl;return 0;
}

2.2 clear的使用
std::string 类提供的 clear() 成员函数,用于清除字符串中的所有字符,使字符串变为空字符串。这个方法不会改变字符串的容量,只是将字符串的长度设置为0。
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("I love Minecraft");cout << "s1是否为空串:" << s1.empty() << endl;cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;s1.clear();cout << "s1是否为空串:" << s1.empty() << endl;cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;return 0;
}

2.3 reserve的使用

std::string 类提供的 reserve() 成员函数,用于请求字符串对象的容量调整。
注:这个函数不会改变字符串的有效字符长度,也不会修改字符串有效字符中的内容。

(1)使用 reserve() 扩容(vs2022运行结果):
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("wukong");cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;s1.reserve(50); // 将容量扩到50字节,但实际扩到了63字节,// 这是由于内存对齐的一些规则导致的,但只会多扩,不会少扩 cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;return 0;
}

(2)使用 reserve() 缩容(vs2022不执行reserve函数的缩容命令):
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("wukong");cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;s1.reserve(10); cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;s1.reserve(5);cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;return 0;
}

总结:
(1)扩容:如果请求的新容量大于当前容量,字符串会分配新的存储空间,使容量至少等于请求的新容量。
(2)缩容:如果请求的新容量小于当前容量,字符串的容量可能不会改变(因编译器而异)。
因为reserve函数的缩容机制因编译器而异,所以我们一般不会使用这个函数缩容。我们一般只用reserve函数进行扩容,使用场景如下:在你预先知道字符串将增长到某个大小时,可以使用reserve函数提前分配足够的空间,避免频繁扩容。
2.4 resize的使用

std::string 类提供的 resize() 成员函数,用于改变字符串的大小。
如果新的大小大于当前大小,字符串会用指定的字符填充(如果未指定填充字符,默认使用’\0’填充);如果新的大小小于当前大小,字符串会被截断。
(1)使用resize函数增加字符串大小:
int main()
{string s1("wukong");cout << s1 << endl;cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;s1.resize(10,'x');cout << s1 << endl;cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;s1.resize(20,'x');cout << s1 << endl;cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;return 0;
}

(2)使用resize函数缩小字符串大小:
int main()
{string s1("wukong");cout << s1 << endl;cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;s1.resize(4);cout << s1 << endl;cout << "s1的有效字符长度:" << s1.size() << endl;cout << "s1的容量:" << s1.capacity() << endl;return 0;
}

总结:
(1)增加大小:如果新的大小大于当前大小,字符串会用指定的字符填充。如果未指定填充字符,默认使用空字符(‘\0’)填充。
(2)减少大小:如果新的大小小于当前大小,字符串会被截断,超出部分的字符会被丢弃。
(3)容量调整:resize 方法可能会改变字符串的容量。如果新的大小大于字符串的当前容量,就会扩容。
3. string类对象的访问及遍历操作


3.1 下标[ ] 和 at
| 函数名称 | 功能说明 |
|---|---|
| operator[ ] | 返回pos位置的字符(越界访问的情况是不确定的) |
| at | 返回pos位置的字符(越界访问会抛异常) |


(1) 使用下标[ ]访问及遍历std::string类对象中内容(调用operator[ ]函数,注意它两个版本的区别):
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("abcdef");for (size_t i = 0; i < s1.size(); ++i){s1[i] += 1;cout << s1[i];// 普通对象调用 char& operator[](size_t pos); // 返回字符串中指定位置字符的引用(char&),// 这意味着你可以通过返回的引用修改字符串中的字符。}cout << endl;const string s2("abcdef");for (size_t i = 0; i < s1.size(); ++i){cout << s2[i];// const对象调用 const char& operator[](size_t pos) const; // 返回字符串中指定位置字符的常引用(const char&),// 这意味着你只能读取字符串中的字符,而无法进行修改。}cout << endl;return 0;
}
(2)使用at访问及遍历std::string类对象中内容(调用at函数,它的使用跟operator[ ]函数类似):
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("abcdef");for (size_t i = 0; i < s1.size(); ++i){s1[i] += 1;cout << s1.at(i);}cout << endl;const string s2("abcdef");for (size_t i = 0; i < s1.size(); ++i){cout << s2.at(i);}cout << endl;return 0;
}
3.2 迭代器iterator
| 函数名称 | 功能说明 |
|---|---|
| begin | 获取字符串第一个字符的迭代器 |
| end | 获取字符串(不包括’\0’)最后一个字符下一个位置的迭代器 |


int main()
{string s1("abcdefgh");string::iterator it1 = s1.begin();// 普通对象调用 iterator begin();// 返回指向字符串第一个字符的普通迭代器,允许修改字符串中的字符。while (it1 != s1.end()){(*it1)++;cout << *it1;++it1;}cout << endl;const string s2("abcdefgh");string::const_iterator it2 = s2.begin();// const对象调用 const_iterator begin() const;// 返回指向字符串第一个字符的const迭代器,只允许读取字符串中的字符,不能修改。while (it2 != s2.end()){cout << *it2;++it2;}cout << endl;return 0;
}

为什么用 iterator(迭代器) 定义变量/对象时要指定类域?
要知晓原因需研究一下 iterator 的底层实现。
iterator 在底层的实现方式一般有以下两种:
(1)内部类实现: iterator(正向迭代器)是定义在string类中的内部类,内部类可以访问外部类的私有成员,从而实现高效的迭代器操作。定义内部类的对象时需要指定外部类类域。
(2)指针实现: 在一些简单的容器(如array,vector,string等)中,iterator可以直接通过指针实现。比如,在string类中,将 char* 类型重命名为 iterator,代码如下:typedef char* iterator。因为是在string类中将 char* 重命名为 iterator,所以在类外要使用string类中的 iterator类型定义变量时需要指定类域。
所以无论 iterator 在底层的实现方式是以上的哪一种,在使用 iterator(迭代器) 定义变量/对象时都需要指定类域。
3.3 范围for
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此
C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
范围for的应用:
(1)范围for可以作用到数组和容器对象上进行遍历
(2)范围for的底层很简单,数组遍历实际就是使用指针(编译器会将范围for循环转换为基于指针的循环,使用数组的首地址和末地址来遍历数组中的元素);容器遍历实际就是替换为迭代器(范围for循环在容器中的底层实现是通过调用容器的begin()和end()方法来获取迭代器,并使用这些迭代器来遍历容器中的元素)
#include <string>
#include <iostream>
using namespace std;
int main()
{char array[] = "wukong";for (char e : array){cout << e;}cout << endl;string str("one piece");for (char ch : str){cout << ch;} cout << endl;return 0;
}

4. string类对象的修改操作

4.1 push_back、append 和 operator+=(在字符串后追加字符)
| 函数名称 | 功能说明 |
|---|---|
| push_back | 在字符串后尾插字符 |
| append | 在字符串后追加一个字符串或字符序列 |
| operator+= | 在字符串后追加一个字符串或字符 |
(1)std::string类提供的push_back成员函数,用于将一个字符追加到字符串的末尾。

#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("wukong");cout << s1 << endl;s1.push_back('o');cout << s1 << endl;s1.push_back('n');cout << s1 << endl;s1.push_back('e');cout << s1 << endl;return 0;
}

(2)std::string类提供的append成员函数(运算符重载),用于将一个字符串或字符序列追加到当前字符串的末尾。

示例一(追加另一个字符串的一部分到当前字符串的末尾):
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("zhangsan");cout << s1 << endl;string s2("i love you");s1.append(s2, 1, 5);// 调用 string& append(const string& str, size_t subpos, size_t sublen);// 用于将另一个字符串的一部分(从subpos位置往后sublen个字符)追加到当前字符串的末尾。// subpos位置往后的字符个数不够sublen,到末尾也会停止,不会额外追加。cout << s1 << endl;string s3("i like apple");s1.append(s3, 6, 20);cout << s1 << endl;return 0;
}

示例二(追加字符数组的前n个字符到当前字符串的末尾):
#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("one piece ");cout << s1 << endl;char a1[] = "is still enough";s1.append(a1, 9);// 调用 string& append(const char* s, size_t n);// 用于将字符数组的前n个字符追加到当前字符串的末尾。cout << s1 << endl;char a2[] = "missing is silent";s1.append(a2, 7);cout << s1 << endl;return 0;
}

(3)std::string类提供的operator+=成员函数,用于将一个字符串、字符数组或单个字符追加到当前字符串的末尾。

#include <string>
#include <iostream>
using namespace std;
int main()
{string s1("One Piece ");cout << s1 << endl;string s2("is a ");s1 += s2;cout << s1 << endl;char a1[] = "Miracle";s1 += a1;cout << s1 << endl;s1 += '!';cout << s1 << endl;return 0;
}

4.2 insert(在字符串任意位置追加字符)
std::string类提供的insert成员函数,用于在字符串的指定位置插入新的字符或子串。

示例一(在指定位置插入另一个字符串的子串):
#include <string>
#include <iostream>
using namespace std;
int main()
{string str1 = "i one piece!";string str2 = "peace and love";str1.insert(1, str2, 9, 20);// 调用string& insert(size_t pos, const string& str, size_t subpos, size_t sublen);// 参数:// pos:插入的位置。// str:要插入的std::string对象。// subpos:从str中开始插入的位置。// sublen:要插入的字符数。cout << str1 << endl;return 0;
}

示例二(在指定位置插入C风格字符串的前n个字符):
#include <string>
#include <iostream>
using namespace std;
int main()
{string str1 = "war and !";char ch[] = "peace and love";str1.insert(8, ch, 5);// 调用string& insert (size_t pos, const char* s, size_t n);// 在指定位置插入C风格字符串的前n个字符。cout << str1 << endl;return 0;
}

示例三(在指定位置插入n个字符):
#include <string>
#include <iostream>
using namespace std;
int main()
{string str1 = "hello";str1.insert(2, 5, 'x');// 调用string& insert (size_t pos, size_t n, char c);// 在指定位置插入n个c字符。cout << str1 << endl;return 0;
}

4.3 erase(删除指定范围的字符)
std::string类提供的erase成员函数,用于从字符串中删除指定范围的字符。

#include <string>
#include <iostream>
using namespace std;
int main()
{string str1 = "hello world!";str1.erase(6, 5);// 调用string& erase (size_t pos = 0, size_t len = npos);// 参数:// pos:开始删除的位置。// n:要删除的字符数。cout << str1 << endl;return 0;
}

4.3 replace(替换字符串中指定范围的字符)
std::string类提供的replace成员函数,用于替换字符串中指定范围的字符。

示例一(将字符串中指定范围的字符替换成另一个字符串的子串):
#include <string>
#include <iostream>
using namespace std;
int main()
{string str1 = "xxx xxxxxxxxxx xxx";string str2 = "one two three";str1.replace(4, 10, str2, 8, 10);// 调用string& replace (size_t pos, size_t len, const string& str,// size_t subpos, size_t sublen);// 参数:// pos:开始替换的位置。// n:要替换的字符数。// str:用于替换的std::string对象。// subpos:在str中用于替换的起始位置。// sublen:用于替换的字符长度cout << str1 << endl;return 0;
}

示例二(将字符串中指定范围的字符替换成C风格字符串的前n个字符):
#include <string>
#include <iostream>
using namespace std;
int main()
{string str1 = "xxx xxxxxxxxxx xxx";char ch[] = "one two three";str1.replace(4, 10, ch, 3);// 调用string& replace (size_t pos, size_t len, const char* s, size_t n);// 将字符串中指定范围的字符替换成C风格字符串的前n个字符cout << str1 << endl;return 0;
}

示例三(将字符串中指定范围的字符替换成n个c字符):
int main()
{string str1 = "xxx xxxxxxxxxx xxx";str1.replace(4, 10, 5, 'o');// 调用 string& replace (size_t pos, size_t len, size_t n, char c);// 将字符串中指定范围的字符替换成n个c字符cout << str1 << endl;return 0;
}

5. string类对象的字符串操作

5.1 c_str的使用
std::string类提供的 c_str 成员函数,返回 C 格式字符串。
这个函数在需要将 std::string 对象传递给需要 C 格式字符串的函数时非常有用。

#include <string>
#include <iostream>
using namespace std;
int main()
{string str("Please split this sentence into tokens");char* cstr = new char[str.size() + 1];strcpy(cstr, str.c_str());// char* strcpy(char* destination, const char* source );cout << cstr << endl;delete[] cstr;return 0;
}

5.2 find的使用
std::string类提供的 find 成员函数,从字符串pos位置开始往后找指定的字符或子串,找到了返回字符或子串首次出现的位置。如果未找到字符或子串,则返回一个特殊的常量 std::string::npos,表示“未找到”。

示例一(从字符串pos位置开始往后找指定的字符串):
int main()
{string s1 = "Hello World!";string s2 = "World";size_t pos = s1.find(s2);// pos不指定默认为0cout << pos << endl;return 0;
}

示例二(从字符串pos位置开始往后找指定的C风格字符串):
int main()
{string s1 = "Hello World!";size_t pos = s1.find("llo");cout << pos << endl;return 0;
}

示例三(从字符串pos位置开始往后找指定的字符):
int main()
{string s1 = "war and peace";size_t pos = s1.find(' ');while (pos != string::npos){s1[pos] = 'X';pos = s1.find(' ', pos + 1);}cout << s1 << endl;return 0;
}

5.3 rfind的使用
std::string 类中的 rfind 成员函数,用于在字符串中从后向前查找指定的字符或子串,找到了返回字符或子串最后一次出现的位置。如果未找到字符或子串,则返回一个特殊的常量 std::string::npos,表示“未找到”。

int main()
{string s1 = "war war war war";size_t pos = s1.rfind("war");cout << pos << endl;return 0;
}

5.4 substr(从字符串中提取一个子字符串)
std::string 类中的 substr 成员函数,用于从字符串中提取一个子字符串,通过指定起始位置和长度来获取子字符串。

#include <string>
#include <iostream>
using namespace std;
int main()
{string s1 = "Hello World!";string s2 = s1.substr(6, 5);cout << s2 << endl;return 0;
}

6. string类非成员函数

| 函数名称 | 功能说明 |
|---|---|
| operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
| operator>> | 输入运算符重载 |
| operator<< | 输出运算符重载 |
| getline | 获取一行字符串 |
| relational operators | 大小比较 |
6.1 operator+
std::string 类提供了多种方式来连接字符串,其中 operator+ 是一个常用的非成员函数,operator+ 的非成员函数形式允许你将两个字符串连接起来,或者将字符串与其他类型的对象(如C风格字符串、字符等)连接起来。

示例中依次调用以上operator+ 非成员函数的5种重载形式:
#include <iostream>
#include <string>
using namespace std;
int main() {std::string str1 = "Hello, ";std::string str2 = "world!";const char* cstr = "C-style string";char ch = '!';// 连接两个 string类对象string result1 = str1 + str2;// 连接 string类对象 和 C风格字符串string result2 = str1 + cstr;// 连接 C风格字符串 和 string类对象string result3 = cstr + str1;// 连接 string对象 和 字符string result4 = str1 + ch;// 连接 字符 和 string对象string result5 = ch + str1;cout << result1 << endl;cout << result2 << endl;cout << result3 << endl;cout << result4 << endl;cout << result5 << endl;return 0;
}

6.2 relational operators系列函数
std::string 类提供了一系列非成员函数形式的关系运算符的重载(Relational Operators),用于比较两个字符串 或 字符串与C风格字符串。
这些运算符包括:==(等于)、!=(不等于)、<(小于)、<=(小于等于)、>(大于)和 >=(大于等于)。

int main() {std::string str1 = "apple";std::string str2 = "banana";const char* cstr = "apple";// 比较两个 std::string 对象cout << "str1 == str2: " << (str1 == str2) << endl; cout << "str1 != str2: " << (str1 != str2) << endl; cout << "str1 < str2: " << (str1 < str2) << endl; // 比较 std::string 和 C风格字符串cout << "str1 == cstr: " << (str1 == cstr) << endl; cout << "str1 != cstr: " << (str1 != cstr) << endl; cout << "str1 < cstr: " << (str1 < cstr) << endl;// 比较 C风格字符串 和 std::stringcout << "cstr == str2: " << (cstr == str2) << endl; cout << "cstr != str2: " << (cstr != str2) << endl;cout << "cstr < str2: " << (cstr < str2) << endl; return 0;
}

6.3 >>运算符重载 和 getline函数的区别
(1) >>运算符重载
>>是流提取运算符,通常用于从输入流(如 std::cin)中读取数据。
行为:
读取数据时,会跳过前导空白字符(如空格、制表符、换行符等)。
读取到第一个空白字符时停止,空白字符不会被包含在结果中。
适用于读取单个单词或简单数据类型(如 int、double、std::string 等)。
示例:
int main()
{string word;cin >> word;// 输入" hello world"// >>运算符重载读取数据时,会跳过前导空白字符;// 开始读取有效字符时,读取到第一个空白字符时停止,空白字符不会被包含在结果中。// 所以 word 的值为"hello"cout << "输出:" << word << endl;return 0;
}

(2) getline 函数
getline 是专门用于从输入流中读取一行数据的函数。

行为:
读取整行内容,直到遇到指定的分隔符(默认为换行符 \n)。
不会跳过前导空白字符,会读取包括空格在内的所有字符。
读取的内容包含分隔符之前的所有字符,但不包括分隔符本身。
示例一(分隔符默认为换行符 \n):
int main()
{string word;getline(cin, word);// 输入 " hello world"// getline函数读取数据时,不会跳过前导空白字符,// 一直读取内容直到遇到指定的分隔符(默认为换行符 \n),// 所以 word 的值为 " hello world"cout << "输出:" << word << endl;return 0;
}

示例二(自己指定的分隔符):
int main()
{string word;getline(cin, word, '+');// 输入 " hello world/ncrazy 6+1"// getline函数读取数据时,会一直读取到到指定的分隔符'+'才停止// 所以 word 的值为 " hello world/ncrazy 6"cout << "输出:" << word << endl;return 0;
}

相关文章:
【C++】string类(上):string类的常用接口介绍
文章目录 前言一、C中设计string类的意义二、string类的常用接口说明1. string类对象的常见构造2. string类对象的容量操作2.1 size、capacity 和 empty的使用2.2 clear的使用2.3 reserve的使用2.4 resize的使用 3. string类对象的访问及遍历操作3.1 下标[ ] 和 at3.2 迭代器it…...
CSS关系选择器详解
CSS关系选择器详解 学习前提什么是关系选择器?后代选择器(Descendant Combinator)语法示例注意事项 子代选择器(Child Combinator)语法示例注意事项 邻接兄弟选择器(Adjacent Sibling Combinator࿰…...
C语言中的信号量
信号是操作系统中用来传递特定消息的机制。操作系统可以使用这种方式将程序运行过程中发生的各类特殊情况发送给程序,并按照其指定的逻辑进行处理。信号名称都以 “SIG” 作为前缀,如程序访问非法内存时,会产生名为 SIGSEGV 的信号。 程序需…...
求一个数的数根(高精度)
上一期我们讲的是求一个数的数根,和本期唯一不同的是,数据范围不同了,上一期这个数是小于等于10的18次方的,这一期是小于等于10的1000次方的,开一个变量?肯定不行,我们需要再开一个数组…...
从理论到实践:Linux 进程替换与 exec 系列函数
个人主页:chian-ocean 文章专栏-Linux 前言: 在Linux中,进程替换(Process Substitution)是一个非常强大的特性,它允许将一个进程的输出直接当作一个文件来处理。这种技术通常用于Shell脚本和命令行操作中…...
3 卷积神经网络CNN
1 Image Classification (Neuron Version) – 1.1 Observation 1 1.2 Observation 2 如果不同的receptive field需要相同功能的neuron,可以使这些neuron共享参数 1.3 Benefit of Convolutional Layer 2 Image Classification (Filter Version) 不用担心filter大小…...
详解Linux系统的终端(Terminal)以及分类(各种tty开头的设备文件)
目录 终端(Terminal)的概念和作用终端(Terminal)在Linux中被视为设备,每个终端有自己的设备文件tty三个字母的来源(tty名字的来源)如何查看当前终端的设备文件常见终端的分类1-串口终端02-虚拟控制台终端(Virtual Console)03-伪终端(Pseudo T…...
强化学习数学原理(五)——随机近似与随机
一、Motivating example 首先有个random variable(随机变量)X,我们的目标就是求出他的expectation E(x),我们有一些iid的采样,xi,从1到n,求出均值 但是如果有很多数据,我需要等很久,把所有数据都…...
图书管理系统 Axios 源码__获取图书列表
目录 核心功能 源码介绍 1. 获取图书列表 技术要点 适用人群 本项目是一个基于 HTML Bootstrap JavaScript Axios 开发的图书管理系统,可用于 添加、编辑、删除和管理图书信息,适合前端开发者学习 前端交互设计、Axios 数据请求 以及 Bootstrap 样…...
线性数据结构:单向链表
放弃眼高手低,你真正投入学习,会因为找到一个新方法产生成就感,学习不仅是片面的记单词、学高数......只要是提升自己的过程,探索到了未知,就是学习。 考虑到可能有小白在合并代码时出现各种细节问题,本文…...
线程互斥同步
前言: 简单回顾一下上文所学,上文我们最重要核心的工作就是介绍了我们线程自己的LWP和tid究竟是个什么,总结一句话,就是tid是用户视角下所认为的概念,因为在Linux系统中,从来没有线程这一说法,…...
《苍穹外卖》项目学习记录-Day11订单统计
根据起始时间和结束时间,先把begin放入集合中用while循环当begin不等于end的时候,让begin加一天,这样就把这个区间内的时间放到List集合。 查询每天的订单总数也就是查询的时间段是大于当天的开始时间(0点0分0秒)小于…...
SAP HCM 回溯分析
最近总有人问回溯问题,今天把12年总结的笔记在这共享下: 12年开这个图的时候总是不明白是什么原理,教程看N次,网上资料找一大堆,就是不明白原理,后来为搞明白逻辑,按照教材的数据一样做…...
JavaScript原型链与继承:优化与扩展的深度探索
在 JavaScript 的世界里,万物皆对象,而每个对象都有一个与之关联的原型对象,这就构成了原型链的基础。原型链,简单来说,是一个由对象的原型相互连接形成的链式结构 。每个对象都有一个内部属性[[Prototype]]࿰…...
五子棋对弈
问题描述 "在五子棋的对弈中,友谊的小船说翻就翻?" 不!对小蓝和小桥来说,五子棋不仅是棋盘上的较量,更是心与心之间的沟通。这两位挚友秉承着"友谊第一,比赛第二"的宗旨,决…...
vue vscode插件推荐安装
在 VSCode 中开发 Vue,推荐安装以下插件: 核心插件 1. Volar(Vue Language Features) - Vue 3 官方推荐的开发工具,替代 Vetur。 This extension is deprecated. Use the Vue - Official extension instead. 1.Vue …...
Med-R2:基于循证医学的检索推理框架:提升大语言模型医疗问答能力的新方法
Med-R2 : Crafting Trustworthy LLM Physicians through Retrieval and Reasoning of Evidence-Based Medicine Med-R2框架Why - 这个研究要解决什么现实问题What - 核心发现或论点是什么How - 1. 前人研究的局限性How - 2. 你的创新方法/视角How - 3. 关键数据支持How - 4. 可…...
P7497 四方喝彩 Solution
Description 给定序列 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1,a2,⋯,an),有 m m m 个操作,分四种: add ( l , r , v ) \operatorname{add}(l,r,v) add(l,r,v):对于所有 i ∈ [ l , r ] i \in [l,r…...
EtherCAT主站IGH-- 29 -- IGH之mailbox.h/c文件解析
EtherCAT主站IGH-- 29 -- IGH之mailbox.h/c文件解析 0 预览一 该文件功能`mailbox.c` 文件功能函数预览二 函数功能介绍`mailbox.c` 中主要函数的作用1. `ec_slave_mbox_prepare_send`2. `ec_slave_mbox_prepare_check`3. `ec_slave_mbox_check`4. `ec_slave_mbox_prepare_fetc…...
UI线程用到COM只能选单线程模型
无论用不用UI库,哪怕是用Win32 API手搓UI,UI线程要用COM的话,必须初始化为单线程单元(STA),即CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);,不能用MULTITHREADTHREADED。 实际上,很多(WPF等)UI库若…...
排序算法--桶排序
核心思想为分区间排序后合并。适用于数据均匀分布在一个范围内,或浮点数排序或范围明确的数据。如果需要处理整数或其他数据范围,可以通过调整BUCKET_RANGE的计算方式实现,例如对[0,100)的整数排序: int index arr[i] / 10; // …...
zsh安装插件
0 zsh不仅在外观上比较美观,而且其具有强大的插件,如果不使用那就亏大了。 官方插件库 https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins 官方插件库并不一定有所有的插件,比如zsh-autosuggestions插件就不再列表里,下面演示zs…...
bypass hcaptcha、hcaptcha逆向
可以过steam,已支持并发,欢迎询问! 有事危,ProfessorLuoMing...
python-UnitTest框架笔记
UnitTest框架的基本使用方法 UnitTest框架介绍 框架:framework,为了解决一类事情的功能集合 UnitTest框架:是python自带的单元测试框架 自带的,可以直接使用,不需要格外安装 测试人员用来做自动化测试,作…...
掌握API和控制点(从Java到JNI接口)_35 JNI开发与NDK 03
3、 如何载入 .so档案 VM的角色 由于Android的应用层级类别都是以Java撰写的,这些Java类别转译为Dex型式的Bytecode之后,必须仰赖Dalvik虚拟机器(VM: Virtual Machine)来执行之。 VM在Android平台里,扮演很重要的角色。此外,在执…...
计算机组成原理——存储系统(二)
🌱 "人生最深的裂痕,往往是光照进来的地方。 别怕脚下的荆棘,那是你与平庸划清界限的勋章;别惧眼前的迷雾,星辰永远藏在云层之上。真正的强者不是从未跌倒,而是把每一次踉跄都踏成攀登的阶梯。记住&am…...
CDDIS从2025年2月开始数据迁移
CDDIS 将从 2025 年 2 月开始将我们的网站从 cddis.nasa.gov 迁移到 earthdata.nasa.gov,并于 2025 年 6 月结束。 期间可能对GAMIT联网数据下载造成影响。...
VSCode设置内容字体大小
1、打开VSCode软件,点击左下角的“图标”,选择“Setting”。 在命令面板中的Font Size处选择适合自己的字体大小。 2、对比Font Size值为14与20下的字体大小。...
嵌入式学习---蜂鸣器篇
1. 蜂鸣器分类 蜂鸣器是一种电子发声器件,采用直流电压供电,能够发出声音。广泛应用于计算机、打印机、报警器、电子玩具等电子产品中作为发声部件。一般仅从外形不易分辨蜂鸣器的种类。但是有些蜂鸣器使用广泛,见得多了就很容易分辨。例如常…...
【优先算法】专题——前缀和
目录 一、【模版】前缀和 参考代码: 二、【模版】 二维前缀和 参考代码: 三、寻找数组的中心下标 参考代码: 四、除自身以外数组的乘积 参考代码: 五、和为K的子数组 参考代码: 六、和可被K整除的子数组 参…...
