【C++】STL:String

news2024/9/21 0:33:37

🐱作者:傻响
🐱专栏:《C/C++ - STL》
🔥格言:你只管努力,剩下的交给时间!

                                                              

目录

STD - String标准库

字符串类介绍

字符串类构造函数

No.1 string() ;

No.2 string(const char* s) ;

No.3 string(const string&s) ;

No.4 string(size_t n, char c);

No.5 string (const string& str, size_t pos, size_t len = npos);

No.6 string (const char* s, size_t n);

No.7 template <,class InputIterator> string (InputIterator first, InputIterator last);

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

No.1 operator[]

No.2 正向迭代器(iterator)

No.3 反向迭代器(reverse_iterator)

No.4 const迭代器

No.5 for范围

No.6 at

No.7 back

No.8 front

string类对象的容量操作

No.1 size() / length()

No.2 capacity()

No.3 max_size()

No.4 clear()

No.5 empty()

No.6 shrink_to_fit()

No.7 reserve()

No.8 resize ()

string类对象的修改操作

No.1 push_back()

No.2 append(push_back延申)

No.3 operator+=

No.4 Insert()

No.5 Erase()

No.6 assign()

No.7 replace()

No.8 find()

string类的模拟实现


STD - String标准库

string标准库是包含在STD库中。

链接: - C++ Reference (cplusplus.com)

// 声明
#include<string>

字符串类介绍

字符串是表示字符序列的对象。

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

string类是basic_string类模板的实例化,该模板使用char(即bytes)作为其字符类型,并具有默认的char_traits和allocator类型(有关模板的更多信息,请参阅basic_string)。

注意,这个类独立于所使用的编码处理字节:如果用于处理多字节或变长字符(如UTF-8)的序列,该类的所有成员(如length或size)及其迭代器仍将按照字节(而不是实际编码的字符)进行操作。

字符串类构造函数

构造函数名(constructor)功能说明
string() ;(重点)空字符串构造函数(默认构造函数),构造一个空字符串,长度为零。
string(const char* s) ;(重点)从c字符串,复制由s指向的以空结束的字符序列(C-string)。
string(const string&s) ;(重点)拷贝构造函数,构造str的副本。
string(size_t n, char c);(一般)把构造函数 ,用字符c的n个连续副本填充字符串。
string (const string& str, size_t pos, size_t len = npos);(一般)子字符串构造函数 ,复制str中从字符位置pos开始并跨越len字符的部分(或者直到str的末尾,如果str太短,len很长,这样str有多少取多少,直到str结束)。
string (const char* s, size_t n);(一般)从缓冲区 ,从由s指向的字符数组中复制前n个字符。
template <class InputIterator> string (InputIterator first, InputIterator last);(一般)

No.1 string() ;

空字符串构造函数(默认构造函数),构造一个空字符串,长度为零。

// 构造空字符串(默认构造函数)
string str1;
cout << str1 << endl;

No.2 string(const char* s) ;

从c字符串,复制由s指向的以空结束的字符序列(C-string)。

// 从c字符串,复制由s指向的以空结束的字符序列(C-string)。
string str2 = "傻响";
string str3 = "是啥";
cout << str2 << " " << str3 << endl;

No.3 string(const string&s) ;

拷贝构造函数,构造str的副本。

// 从c字符串,复制由s指向的以空结束的字符序列(C-string)。
string str2 = "傻响";
string str3 = "是啥";
cout << str2 << " " << str3 << endl;
// 拷贝构造函数,构造str副本。
string str4 = str2;
string str5(str3);
cout << str4 << " " << str5 << endl;

No.4 string(size_t n, char c);

把构造函数 ,用字符c的n个连续副本填充字符串。

// 把构造函数 ,用字符c的n个连续副本填充字符串。
string str6(10, '*');
cout << str6 << endl;

No.5 string (const string& str, size_t pos, size_t len = npos);

子字符串构造函数 ,复制str中从字符位置pos开始并跨越len字符的部分(或者直到str的末尾,如果str太短,len很长,这样str有多少取多少,直到str结束)。

// 从缓冲区 ,从由s指向的字符数组中复制前n个字符。
string str7("Hello World", 5);
cout << str7 << endl;

No.6 string (const char* s, size_t n);

从缓冲区 ,从由s指向的字符数组中复制前n个字符。

// 从缓冲区 ,从由s指向的字符数组中复制前n个字符。
string str7("Hello World", 5);
cout << str7 << endl;
// 子字符串构造函数 ,复制str中从字符位置pos开始并跨越len字符的部分(或者直到str的末尾,如果str太短或len为string::npos)。
string str8(str7, 2, 3);
cout << str8 << endl;

No.7 template <,class InputIterator> string (InputIterator first, InputIterator last);

 

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

函数名称功能说明
operator[] (重点)返回pos位置的字符,const string类对象调用
begin+ endbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭 代器
rbegin + rendbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭 代器
范围forC++11支持更简洁的范围for的新遍历方式

No.1 operator[]

返回对字符串中位置为pos的字符的引用。

char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
// pos:
// 值与字符在字符串中的位置一起。
// 注意:字符串中的第一个字符用值0表示(而不是1)。
// Size_t是无符号整型(与成员类型string::size_type相同)。
​
// 返回值:
// 位于字符串中指定位置的字符。
// 如果字符串对象是const限定的,则该函数返回const char&。否则,它返回char&。
​
string str1("1234");
cout << str1 << endl;
// 使用operator[]运算符重载的方式进行对字符串的每个字符加1。
for (size_t i = 0; i < str1.size(); i++)
{
    str1[i]++;
}
cout << str1 << endl;

 

No.2 正向迭代器(iterator)

      iterator begin();
const_iterator begin() const;
      iterator end();
const_iterator end() const;
​
string str1("2345");
cout << str1 << endl;
// 迭代器(iterator):行为上像指针一样的类型。
string::iterator it = str1.begin(); // begin指向string第一个位置。
while (it != str1.end())    // end指向string最后一个字符的下一个位置。
{
    *it += 1;
    ++it;
}
​
// 迭代器打印
it = str1.begin();
while (it != str1.end())
{
    cout << *it;
    ++it;
}
cout << endl;

 

No.3 反向迭代器(reverse_iterator)

      reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
      reverse_iterator rend();
const_reverse_iterator rend() const;
​
​
string str1 = "1234";
cout << str1 << endl;
​
// 迭代器(reverse_iterator):行为上像指针一样的类型。
string::reverse_iterator rit = str1.rbegin();
while (rit != str1.rend())
{
    cout << *rit;
    rit++;
}
cout << endl;

 

No.4 const迭代器

这里演示一下const iterator。

void Print(const string& s)
{
    // 遍历string const::interator只能读,不支持写
    string::const_iterator it = s.begin();
    while (it != s.end())
    {
        cout << *it << " ";
​
        ++it;
    }
    cout << endl;
​
    string::const_reverse_iterator rit = s.rbegin();
    while (rit != s.rend())
    {
        cout << *rit << " ";
​
        ++rit;
    }
    cout << endl;
}
​
int main()
{
    string str1 = "1234";
    cout << str1 << endl;
    
    // 测试const迭代器
    Print(str1);
}

No.5 for范围

string str1("2345");
cout << str1 << endl;
// 使用for范围
for (auto& ch : str1)
{
    ch--;
}
cout << str1 << endl;

 

No.6 at

返回对字符串中位置为pos的字符的引用.

该函数自动检查pos是否是字符串中某个字符的有效位置(即pos是否小于字符串长度),如果不是则抛出out_of_range异常。

string str1 = "Hello World";
​
// 使用at进行打印。
for (size_t i = 0; i < str1.size(); i++)
{
    cout << str1.at(i);
}
cout << endl;

No.7 back

返回对字符串最后一个字符的引用。

此函数不能在空字符串上调用。

      char& back();
const char& back() const;
​
string str1 = "Hello World";
// 返回str1中最后一个字符。
char lastChar = str1.back();

No.8 front

返回对字符串第一个字符的引用。

与返回指向相同字符的迭代器的member string::begin不同,此函数返回直接引用。

此函数不能在空字符串上调用。

      char& front();
const char& front() const;
​
string str1 = "Hello World";
// 返回str1中第一个字符。
char firstChar = str1.front();

 

string类对象的容量操作

函数名称功能说明
size(重点)返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回空间总大小
empty (重点)检测字符串释放为空串,是返回true,否则返回false
clear (重点)清空有效字符
reserve (重点)为字符串预留空间
resize (重点)将有效字符的个数该成n个,多出的空间用字符c填充
max_size返回字符串的最大大小
shrink_to_fit缩小以适应,请求字符串减少其容量以适应其大小。

No.1 size() / length()

返回字符串的长度,以字节为单位。

这是符合字符串内容的实际字节数,它不一定等于其存储容量。

注意,字符串对象处理字节时不知道最终可能用于编码其包含的字符的编码。因此,返回的值可能与多字节或变长字符序列(如UTF-8)中编码字符的实际数量不对应。

string::size和string::length都是同义词,返回相同的值。

size_t size() const;
size_t length() const;

string str1 = "Hello World";

// 使用Stirng::size / String::lenght
cout << str1.size() << " " << str1.length() << endl;

No.2 capacity()

返回当前分配给字符串的存储空间大小,以字节表示。

这个容量不一定等于字符串长度。它可以等于或更大,额外的空间允许对象在向字符串中添加新字符时优化其操作。

注意,此容量并不假设对字符串的长度有限制。当此容量耗尽且需要更多时,对象会自动扩展该容量(为其重新分配存储空间)。字符串长度的理论限制由成员max_size给出。

在修改对象的任何时候,都可以更改字符串的容量,即使这种修改意味着大小的减少或容量尚未耗尽(这与vector容器中提供的容量保证相反)。

字符串的容量可以通过调用成员预留显式更改。

size_t capacity() const;

string str1 = "Hello World";
string str2 = "Hello";

// 使用string::capacity
cout << str1.capacity() << endl;
cout << str2.capacity() << endl;

No.3 max_size()

返回字符串可以达到的最大长度。

这是由于已知的系统或库实现限制,字符串可以达到的最大潜在长度,但不能保证对象能够达到该长度:在达到该长度之前,它仍然可能无法分配存储。

size_t max_size() const;

string str1 = "Hello World";
string str2 = "Hello";

// 使用string::max_size()
cout << str1.max_size() << endl;
cout << str2.max_size() << endl;

No.4 clear()

擦除字符串的内容,使其成为空字符串(长度为0个字符)。

void clear();

string str1 = "Hello World";
string str2 = "Hello";

// 使用string::clear()
str2.clear();
cout << str2 << endl;
cout << str2.capacity() << endl;

No.5 empty()

返回字符串是否为空(即其长度是否为0)。

此函数不以任何方式修改字符串的值。要清除字符串的内容,请参见string::clear。

bool empty() const;
​
string str1 = "Hello World";
string str2 = "Hello";
// 使用string::clear()
str2.clear();
cout << str2 << endl;
cout << str2.capacity() << endl;
// 使用string::empty()
cout << boolalpha << str1.empty() << endl;  // false
cout << boolalpha << str2.empty() << endl;  // true

 

No.6 shrink_to_fit()

请求字符串减少其容量以适应其大小。

该请求是非绑定的,容器实现可以自由优化,使字符串的容量大于其大小。

此函数对字符串长度没有影响,也不能更改其内容。

void shrink_to_fit();
​
string str1(100,'x');
string str2(200, 'x');
​
cout << "str1的大小" << str1.size() << endl;
cout << "str2的大小" << str2.size() << endl;
cout << "str1的容量:" << str1.capacity() << endl;
cout << "str2的容量:" << str2.capacity() << endl;
​
str1.resize(10);
str2.resize(20);
​
// 调用str1和str2的shrink_to_fit()函数自适应调整大小。
str1.shrink_to_fit();
str2.shrink_to_fit();
cout << "str1的大小" << str1.size() << endl;
cout << "str2的大小" << str2.size() << endl;
cout << "str1的容量:" << str1.capacity() << endl;
cout << "str2的容量:" << str2.capacity() << endl;

 

No.7 reserve()

请求调整字符串容量,以适应计划的大小更改,长度最多为n个字符。

如果n大于当前字符串容量,则该函数将容器的容量增加到n个字符(或更大)。

在所有其他情况下,收缩字符串容量都被视为非绑定请求:容器实现可以自由优化,否则将使字符串的容量大于n。

此函数对字符串长度没有影响,也不能更改其内容。

void reserve (size_t n = 0);

string str1 = "Hello World";
cout << str1.size() << endl;
cout << str1.capacity() << endl;
cout << str1 << endl << endl;

// 调用reserbe()函数进行预备空间。
str1.reserve(1000);
cout << str1.size() << endl;
cout << str1.capacity() << endl;
cout << str1 << endl;

 

No.8 resize ()

将字符串的长度调整为n个字符。

如果n小于当前字符串长度,则将当前值缩短为第n个字符,删除第n个字符以外的字符。

如果n大于当前字符串长度,则通过在末尾插入所需的字符来扩展当前内容,以达到n的大小。如果指定了c,则将新元素初始化为c的副本,否则,它们是值初始化的字符(空字符)。

void resize (size_t n);
void resize (size_t n, char c);

// resize源数据相当于删除。
string str1 = "Hello World";
str1.resize(5);
cout << str1.size() << endl;
cout << str1.capacity() << endl;
cout << str1 << endl << endl;

// resize源数据不变,后面追加\0
string str2 = "Hello World";
str2.resize(20);
cout << str2.size() << endl;
cout << str2.capacity() << endl;
cout << str2 << endl << endl;

// resize元数据改变,后面追加了x
string str3 = "Hello World";
str3.resize(20,'x');
cout << str3.size() << endl;
cout << str3.capacity() << endl;
cout << str3 << endl << endl;

 

string类对象的修改操作

函数名称功能说明
push_back在字符串后尾插字符c
append在字符串后追加一个字符串
operator+= (重点)在字符串后追加字符串str
c_str(重点)返回C格式字符串
find + npos(重点)从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr在str中从pos位置开始,截取n个字符,然后将其返回

No.1 push_back()

将字符附加到字符串

将字符c追加到字符串的末尾,使其长度增加1。

// push_back();单个字符进行push
string str1 = "Hello World";
str1.push_back('!');
str1.push_back('-');
cout << str1 << endl;

No.2 append(push_back延申)

string& append (const string& str);	
string& append (const string& str, size_t subpos, size_t sublen);
string& append (const char* s);	
string& append (const char* s, size_t n);	
string& append (size_t n, char c);
template <class InputIterator>
   string& append (InputIterator first, InputIterator last);

(1)字符串:追加str的副本。
(2)子串 :追加str的子字符串的副本。该子字符串是str中从字符位置subpos开始并跨越子字符的部分(或者直到str的末尾,如果str太短或如果sublen是string::npos)。
(3) c字符串:追加由由s指向的以空结束的字符序列(C-string)组成的字符串的副本。
(4)缓冲区:追加由s指向的字符数组中前n个字符的副本。
(5)填:追加字符c的n个连续拷贝。
(6)范围:以相同的顺序追加范围[第一个,最后一个)中的字符序列的副本。
(7)初始化器列表:以相同的顺序追加il中每个字符的副本。
// push_back();单个字符进行push
string str1 = "Hello World";
str1.push_back('!');
str1.push_back('-');
cout << str1 << endl;

cout << endl;

// append作为push_back的延申,可追加字符串。
str1.append("ShaXiang");
cout << str1 << endl;

 

No.3 operator+=

string& operator+= (const string& str);	
string& operator+= (const char* s);
string& operator+= (char c);

// str:字符串对象,其值在末尾被复制。
// s:指向以空结束的字符序列的指针。在字符串的末尾复制序列。
// c:一个字符,被附加到字符串的当前值之后。
// il:一个initializer_list对象。这些对象是由初始化器列表声明符自动构造的。字符以相同的顺序被追加到字符串中。
// 返回值:*this

str1 += "886";
cout << str1 << endl;

 

No.4 Insert()

string插入接口,这里我就举例一个,其他接口可以登录链接自行查看。

// 插入str的副本。
string& insert (size_t pos, const string& str);
// pos:插入点:新内容插入到字符的前面,位置为pos,注意:第一个字符用值0表示(而不是1)。
// str:另一个字符串对象。
​
​
string s("Hello world");
cout << s << endl;
​
// string::Insert插入函数。
s.insert(0, "ShaXiang");
cout << s << endl;
s.insert(5, "ShaXiang");
cout << s << endl;

 

No.5 Erase()

删除字符串的一部分,减少其长度:

string& erase (size_t pos = 0, size_t len = npos);
// pos:第一个要擦除的字符的位置,注意:str中的第一个字符用值0表示(而不是1)。
// len:要删除的字符数(如果字符串较短,则删除尽可能多的字符)。


string s("Hello world");
cout << s << endl;

// string::Erase删除函数。
s.erase(0, 5);
cout << s << endl;
s.erase(2);
cout << s << endl;
// 结果:
Hello world
 world
 w

No.6 assign()

将新值赋给字符串,替换其当前内容。

string& assign (const string& str);
string& assign (const char* s, size_t n);

No.7 replace()

将字符串中以字符pos开始并跨越len字符的部分(或字符串中[i1,i2)之间的部分)替换为新内容:

string& replace (size_t pos,  size_t len,  const string& str);

 

No.8 find()

在字符串中搜索由其参数指定的序列的第一个出现项。

当指定pos时,搜索只包括位置pos上或之后的字符,忽略任何可能出现的包括pos之前的字符。

注意,与成员find_first_of不同的是,每当搜索多个字符时,只匹配其中一个字符是不够的,而必须匹配整个序列。

size_t find (const string& str, size_t pos = 0) const;
// str:另一个带有要搜索的主题的字符串。
// pos:要在搜索中考虑的字符串中第一个字符的位置。如果该值大于字符串长度,则函数永远找不到匹配项。
// 注意:第一个字符用值0表示(而不是1):值0表示搜索整个字符串。
​
// 返回值:第一个匹配的第一个字符的位置。如果没有找到匹配项,函数返回string::npos。Size_t是无符号整型(与成员类型string::size_type相同)。

 

string类的模拟实现

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<assert.h>
using namespace std;
​
namespace ShaXiang
{
    class string
    {
    public:
        // 构造函数:带参构造。
        string(const char* str)
        {
            _size = strlen(str);
            _capacity = _size;
            _str = new char [strlen(str) + 1];
​
            // C语言的字符串拷贝函数。
            strcpy(_str, str);
        }
​
        // 构造函数:无参数构造。
        string()
        {
            _str = new char[1];
            _str[0] = '\0';
            _capacity = _size = 0;
        }
​
        // 拷贝构造函数 - 传统写法。
        //string(const string& s)
        //{
        //  _str = new char[s._capacity + 1];
        //  _capacity = s._capacity;
        //  _size = s._size;
​
        //  strcpy(_str, s._str);
        //}
​
        // 拷贝构造函数 - 现在写法。
        string(const string& s)
            :_str(nullptr)
            ,_size(0)
            ,_capacity(0)
        {
            string temp(s._str);
​
            swap(temp);
        }
​
​
        // 析构函数。
        ~string()
        {
            delete[] _str;
            _str = nullptr;
​
            _capacity = _size = 0;
        }
​
​
        // 迭代器。
        typedef char* iterator;
        iterator begin()
        {
            return _str;
        }
        iterator end()
        {
            return _str + _size;
        }
​
        // 交换
        void swap(string& s)
        {
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }
​
​
        // 扩容。
        void reserve(size_t n)
        {
            if (_capacity < n)
            {
                char* pTemp = new char[n + 1];
                strcpy(pTemp, _str);
                delete[] _str;
​
                _str = pTemp;
                _capacity = n;
            }
        }
​
        void resize(size_t n, char ch = '\0')
        {
            if (n > _size)
            {
                reserve(n);
                for (size_t i = _size; i < n; ++i)
                {
                    _str[i] = ch;
                }
                _size = n;
                _str[_size] = '\0';
            }
            else
            {
                _str[n] = '\0';
                _size = n;
            }
​
        }
​
​
        // 尾插入一个字符。
        void push_back(char ch)
        {
            // 检查是否需要扩容。
            if (_size == _capacity)
            {
                // 判断首次开辟内存空间。
                size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
                reserve(newCapacity); // 扩容。
            }
​
            _str[_size] = ch;
            ++_size;
            _str[_size] = '\0';
        }
​
        // 尾插入一个字符串。
        void append(const char* str)
        {
            size_t len = strlen(str);
            if (_size + len > _capacity)
            {
                reserve(_size + len);
            }
            strcpy(_str + _size, str);
            _size += len;
        }
​
        // 在pos位置插入一个字符
        string& insert(size_t pos, char ch)
        {
            if (_size == _capacity)
            {
                size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
                reserve(newCapacity);
            }
​
            // 先挪动数据(注意挪动数据\还有整型提升的问题)
            size_t end = _size + 1;
            while (end > pos)
            {
                _str[end] = _str[end - 1];
                --end;
            }
​
            _str[pos] = ch;
            ++_size;
​
            return *this;
        }
​
        // 在pos位置插入字符串。
        string& insert(size_t pos, const char* str)
        {
            // 求字符串个数,进行扩容。
            size_t len = strlen(str);
            if (_size + len > _capacity)
            {
                reserve(_size + len);
            }
​
            // 挪动数据
            size_t end = _size + len;
            while (end >= pos + len)
            {
                _str[end] = _str[end - len];
                --end;
            }
​
            // 拷贝整个要插入的字符串,到移动出来的空位置。
            // No.1
            /*const char* begin = str;
            size_t i = pos;
            while (*begin != '\0')
            {
                _str[i] = *begin;
                ++i;
                ++begin;
            }*/
            // No.2
            strncpy(_str + pos, str, len);
            _size += len;
            return *this;
        }
​
        string& erase(size_t pos, size_t len = npos)
        {
            assert(pos < _size);
            if (len == npos || pos + len > _size)
            {
                _str[pos] = '\0';
                _size = pos;
            }
            else
            {
                strcpy(_str + pos, _str + pos + len);
                _size -= len;
            }
​
            return *this;
        }
​
        size_t find(const char ch, size_t pos = 0) const
        {
            assert(pos < _size);
            while (pos < _size)
            {
                if (_str[pos] == ch)
                {
                    return pos;
                }
​
                ++pos;
            }
​
            return npos;
        }
​
        size_t find(const char* str, size_t pos = 0) const 
        {
            assert(pos < _size);
            const char* result = strstr(_str + pos, str);
            if (result == nullptr)
            {
                return npos;
            }
            else
            {
                return result - _str;
            }
        }
​
​
​
​
        // 返回字符串指针。
        const char* c_str() const
        {
            return _str;
        }
​
        // 返回字符串大小。
        size_t size() const
        {
            return _size;
        }
​
        size_t capacity() const
        {
            return _capacity;
        }
​
        // 返回_str每一个元素的值。
        char& operator[](size_t pos)
        {
            // 检查pos是否越界。
            assert(pos < _size);
            // 返回_str每一个元素的值。
            return _str[pos];
        }
​
        const char& operator[](size_t pos) const
        {
            // 检查pos是否越界。
            assert(pos < _size);
            // 返回_str每一个元素的值。
            return _str[pos];
        }
​
        string& operator+=(char ch)
        {
            push_back(ch);
            return *this;
        }
​
        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }
​
        //string& operator=(const string& s)
        //{
        //  if (this != &s)
        //  {
        //      char* tmp = new char[s._capacity + 1];
        //      strcpy(tmp, s._str);
​
        //      delete[] _str;
        //      _str = tmp;
​
        //      _size = s._size;
        //      _capacity = s._capacity;
        //  }
        //  return *this;
        //}
​
        string& operator=(string s)
        {
            swap(s);
            return *this;
        }
​
        void clear()
        {
            _size = 0;
            _str[_size] = '\0';
        }
​
    private:
        char* _str;
        size_t _size;
        size_t _capacity;
​
        const static size_t npos = -1;
    };
​
​
​
    // 字符串输出流
    inline ostream& operator<<(ostream& out, const string& s)
    {
        for (size_t i = 0; i < s.size(); ++i)
        {
            out << s[i];
        }
        return out;
    }
    // 字符串输入流
    inline istream& operator>>(istream& in, string& s)
    {
        //char ch = in.get();
        //while (ch != ' ' && ch != '\n')
        //{
        //  s += ch;
        //  ch = in.get();
        //}
        s.clear();
        char buffer[128] = { '\0' };
        size_t i = 0;
        char ch = in.get();
        while (ch != ' ' && ch != '\n')
        {
            if (i == 127)
            {
                // 满了
                s += buffer;
                i = 0;
            }
            buffer[i++] = ch;
            ch = in.get();
        }
​
        if (i > 0)
        {
            buffer[i] = '\0';
            s += buffer;
        }
​
        return in;
    }
​
    //istream& operator>>(istream& in, string& s)
    //{
    //  return in;
    //}
​
}

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

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

相关文章

实操1 : Jupyter Notebook 如何更换主题+全部主题展示+深色主题下如何设置可视化图表

文章目录(一) 如何更换主题(二) 全部主题展示(三) 深色主题下设置可视化图表(一) 如何更换主题 1.打开 Jupyter Notebook, 新建一个Python文件 在文件中输入下方命令开始安装主题 pip install --upgrade jupyterthemes -i https://pipy.douban.com/simple2.win R 打开 cmd 命…

效率工具之Arthas

Arthas 阿里巴巴开源的Java诊断工具&#xff1b;追踪方法执行链、反编译、监控JVM状态 在线安装 使用 1. trace 跟踪调用链 解决痛点&#xff1a;定位问题根据日志推理分析&#xff0c;方法出入参不可见&#xff0c;分支判断太多情况下 定位很慢&#xff0c;分析出可能有问…

[附源码]JAVA毕业设计科院垃圾分类系统(系统+LW)

[附源码]JAVA毕业设计科院垃圾分类系统&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术…

JVM学习-- JVM调优

一、选择垃圾收集器 垃圾收集器和内存大小有关 一般情况&#xff0c; serialserial old 适用几十兆内存 pspo 适用几百兆~几个G parNewCMS 可以用到20G G1 可以用到上百G ZGC 可以 4T~16T 1. 常见垃圾收集器组合参数设定 -XX:UseConc(urrent)MarkSweepGC ParNew CM…

【web实战-业务逻辑】评论点赞逻辑

目录 点赞逻辑一&#xff1a; 第一步&#xff1a;找关键 第二步&#xff1a;猜测逻辑 第三步&#xff1a;结论 第四步&#xff1a;归类 点赞逻辑二&#xff1a; 第一步&#xff1a;找关键 第二步&#xff1a;猜测逻辑 第三步&#xff1a;结论 第四步&#xff1a;归纳…

Framework 学习之旅:Service 启动过程

前言 Service 的启动过程将分为两个部分&#xff0c;分别是ContextImpl到ActivityManageService调用过程和ActivityThread启动Service过程。 ContextImpl到ActivityManageService调用过程 一般启动服务操作在Activity中调用startService方法&#xff0c;从Activity的startSe…

[附源码]计算机毕业设计springboot智慧园区运营管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

360T7路由器进行WiFi无线中继教程

360T7路由器进行WiFi中继教程1. 概述2. 360T7路由器进行WiFi中继实现教程2.1 登录路由器管理界面2.2 选择上网方式2.3 搜索WiFi2.4 连接WiFi2.5 点击确认2.6 在主页面查看网络1. 概述 中继路由系统由一组中继路由器组成&#xff0c;为不能交换路由信息的路由域提供中继路由。该…

关于小程序session_key漏洞问题的解决2022-12-01

业务背景&#xff1a;开发了小程序&#xff0c;使用了一段时间以后&#xff0c;小程序提示系统漏洞session_key的问题&#xff0c;在网上找了好多的博客&#xff0c;感觉好多写的没那么清晰&#xff0c;更偏重于理论&#xff0c;导致自己走了很多的弯路&#xff0c;为了更方便快…

基于海鸥算法优化的lssvm回归预测-附代码

基于海鸥算法优化的lssvm回归预测 - 附代码 文章目录基于海鸥算法优化的lssvm回归预测 - 附代码1.数据集2.lssvm模型3.基于海鸥算法优化的LSSVM4.测试结果5.Matlab代码摘要&#xff1a;为了提高最小二乘支持向量机&#xff08;lssvm&#xff09;的回归预测准确率&#xff0c;对…

【树莓派不吃灰】Linux服务器篇(核心概念)

目录1. 第一章 架设服务器前的准备工作2. 第二章 基础网络概念3. 第三章 局域网络架构简介4. 第四章 连上 Internet5. 第五章 Linux 常用网络指令6. 第六章 Linux 网络侦错7. 第七章 网络安全与主机基本防护8. 第八章 路由观念与路由器设定9. 第九章 防火墙与 NAT 服务器&#…

Python源码剖析2-字符串对象PyStringObject

二、 1、PyStringObject与 PyString_Type PyStringObject是变长对象中的不可变对象。当创建了一个PyStringObject对象之后,该对象内部维护的字符串就不能再被改变了。这一点特性使得 PyStringObject 对象能作为 PyDictObject 的键值,但同时也使得一些字符串操作的效率大大降低…

Kafka RecordAccumulator 三 高并发写入数据

Kafka RecordAccumulator 三 高并发写入数据 首先我们客户端会通过多线程的方式来发送消息&#xff08;一般业务需求可能会通过业务系统或者大数据流计算系统如Spark Streaming或者Flink将业务数据发送出去&#xff0c;进而让下游系统消费使用&#xff09;&#xff0c;那这里业…

【Linux】进程状态|僵尸进程 |孤儿进程

索引运行状态&#xff1a;阻塞状态挂起状态看看Linux是怎么做的运行状态R睡眠状态S停止状态T两个特殊的进程&#xff1a;僵尸进程孤儿进程在之前我们听过很多很多进程的状态&#xff0c;像是运行、新建、就绪、挂起、阻塞、等待、停止、挂机、死亡等等。推荐阅读&#xff1a;通…

http协议之digest(摘要)认证,详细讲解并附Java SpringBoot源码

目录 1.digest认证是什么&#xff1f; 2.digest认证过程 3.digest认证参数详解 4.基于SpringBoot实现digest认证 5.digest认证演示 6.digest认证完整项目 7.参考博客 1.digest认证是什么&#xff1f; HTTP通讯采用人类可阅读的文本格式进行数据通讯&#xff0c;其内容非…

Android入门第40天-Android中的Service(SimpleStartService)

简介 博文总阅读量已经突破了300万&#xff0c;给自己加油打CALL。 从今天开始&#xff0c;之前39天的Android如果每一篇只有30分钟就能读完和掌握那么从今天开始越往后会越复杂。因为我们的Android教程开始进入“中级”难度了。特别是Service&#xff0c;这个Service我要分成…

java面向对象的三大特性之封装和继承(配视频讲解)

&#x1f345;程序员小王的博客&#xff1a;程序员小王的博客 &#x1f345;程序员小王的资源博客&#xff1a;http://wanghj.online/ &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 如有编辑错误联系作者&#xff0c;如果有比较好的文章欢迎…

JMeter入门教程(13) --事务

文章目录1.任务背景2.任务目标3.任务实操3.1.1 事务控制器3.2.2循环控制器1.任务背景 JMeter中的事务是通过事务控制器实现的。&#xff0c;为了衡量服务器对某一个或一系列操作处理的响应时间&#xff0c;需要定义事务。下面我们详细介绍在JMeter中如何使用事务 2.任务目标 …

基于JSP的网络教学平台的设计与实现

目 录 摘 要 I Abstract II 一、 引言 1 &#xff08;一&#xff09;项目开发的背景 1 &#xff08;二&#xff09;项目开发的意义 1 二、可行性分析及总体设计原则 3 &#xff08;一&#xff09;可行性分析 3 1&#xff0e;技术可行性 3 2&#xff0e;经济可行性 3 3&#xff…

MATLAB算法实战应用案例精讲-【图像处理】目标检测(附实战案例及代码实现)

前言 目标检测,也叫目标提取,是一种基于目标几何和统计特征的图像分割。它将目标的分割和识别合二为一,其准确性和实时性是整个系统的一项重要能力。尤其是在复杂场景中,需要对多个目标进行实时处理时,目标自动提取和识别就显得特别重要。 随着计算机技术的发展和计算机视…