STL-string
use of string
In C language, there is no concept of class. Strings are usually stored in character arrays for processing, and a large number of string processing functions are provided in the library, but they are not very useful compared with C++. , C++ encapsulates the string class, and the bottom layer is also a character array. On this basis, the class encapsulates a large number of methods for processing strings. Let's introduce them one by one
.
First recommend a website for C++ documentation: cplusplus
can see that the string class is actually typedef. The original class is called basic_string. Because there are many types of encoding, the space occupied by a character is different, and some are 1 byte. 2 bytes and some 4 bytes, so there are different string classes.
The most commonly used is the basic_string< char > class.
default member function
Constructor
You can see that there are many overloaded forms of constructors, and I will only demonstrate the most commonly used ones below.
1. Use string initialization
int main()
{
string str = "hello string";
cout << str << endl;
return 0;
}
2. Copy construction
int main()
{
string str = "hello string";
cout << str << endl;
string str1(str);
cout << str1 << endl;
return 0;
}
3. Use a section of the string class object to construct an interval
int main()
{
string str1 = "hello string";
string str2(str1, 0, 8);
cout << str2 << endl;
return 0;
}
4. Use the first few characters of the string to construct
int main()
{
string str1("hello string", 5);
cout << str1 << endl;
return 0;
}
assignment operator overloading
1. The string class object is used as a parameter
int main()
{
string str1;
string str2 = "hello C++";
str1 = str2;
cout << str1 << endl;
return 0;
}
2, the string as a parameter
int main()
{
string str1;
str1 = "hello C++";
cout << str1 << endl;
return 0;
}
3, a single character as a parameter
int main()
{
string str1;
str1 = 'C';
cout << str1 << endl;
return 0;
}
destructor
capcity-related functions
- size与length
int main()
{
string str1 = "hello world";
cout << "size() : " << str1.size() << endl
<< "length() : " << str1.length() << endl;
return 0;
}
In fact, the functions of these two functions overlap, and the implementation is exactly the same. It is more reasonable to use length for strings, but the size of the subsequent containers is used, so the size interface is also provided to unify the string class.
- The max_size
string can reach the maximum length, in fact, returns the maximum value of the unsigned integer.
-
capcity
capcity is to return its capacity -
resize and reserve
resize is to re-adjust the size of the string. If the parameter passed in is larger than the current size, it will be expanded and initialized. If it is smaller than the current size, its effective length will be changed (the capacity will not change).
int main()
{
string str1 = "hello world";
str1.resize(20);
str1.resize(5);
return 0;
}
reserve readjusts its capacity, it will only work when the incoming parameter is greater than the current capacity, and when the incoming parameter is greater than the current capacity, the capacity will be expanded without initialization.
int main()
{
string str1 = "hello world";
cout << str1.capacity() << endl;
str1.reserve(5);
cout << str1.capacity() << endl;
str1.reserve(20);
cout << str1.capacity() << endl;
return 0;
}
-
clear
clears the string -
empty
Check whether the string is empty
Access related functions
The most commonly used is [ ] to access any element of the string. at() is similar to its function except that it checks for out-of-bounds. operator[ ] uses assertion checking, and at uses gentle checking.
int main()
{
string str1("hello world");
for (int i = 0; i < str1.size(); i++)
{
cout << str1[i] << " ";
}
cout << endl;
for (int i = 0; i < str1.size(); i++)
{
cout << str1.at(i) << " ";
}
cout << endl;
return 0;
}
Modify string related functions
1.
The functions of append and operator+= are the same, except that append has more interfaces, but append is not more commonly used than operator+=.
2. Tail insertion and tail deletion
3. Insert and delete at any position
4. Exchange two string objects
String class other functions
1, c_str
returns the address of the underlying maintenance string.
int main()
{
string str1("hello string");
const char* s = str1.c_str();
cout << s << endl;
return 0;
}
2, find and rfind
One is to search from front to back, and the other is to search from back to front. The search content can be characters, strings, and string objects. Returns the position subscript of the found string.
3.substr
The string cutting function returns a string object starting from position pos with a length of len, where nops is the maximum value of an unsigned integer. If the length is greater than the original string itself, then the string from pos position to the end will be returned.
4.
The compare function is actually not commonly used, mainly because the string class overloads a large number of relational operators.
non-member function
1. Overloading stream extraction and stream insertion operators
Since the string class is a self-defined type, cin and cout cannot be used to input and output it, so the >> and << operators must be overloaded.
2,getline
When using cin>> to read a string, it will stop when it encounters a space, so if we want to input a string with a space, there will be a problem, and the getline function can avoid this problem. It is read by default If '\n' is the end mark, the end mark can also be changed manually.
Analog implementation of string
1. General framework
namespace gy
{
class string
{
public:
string(const char* str = "")
:_size(strlen(str))
{
_capcity = _size == 0 ? 4 : _size;
_str = new char[_capcity + 1];
strcpy(_str, str);
}
private:
char* _str;
size_t _size;
size_t _capcity;
static const size_t npos = -1;
};
}
2. Copy constructor
string(const string& s)
:_size(s._size)
, _capcity(s._capcity)
{
_str = new char[_capcity + 1];
strcmp(_str, s._str);
}
3. Assignment operator overloading
string& operator=(const string& s)
{
_size = s._size;
_capcity = s._capcity;
char* tmp = new char[_capcity + 1];
strcpy(tmp, s._str);
delete[] _str;
_str = tmp;
return *this;
}
4. Destructor
~string()
{
delete[] _str;
_str = nullptr;
_size = _capcity = 0;
}
5, c_str function
const char* c_str()
{
return _str;
}
6, size and capacity
size_t size() const
{
return _size;
}
size_t capcity() const
{
return _capcity;
}
Since such a function does not modify the content of the string, it is best to add const so that both ordinary objects and const objects can be called.
7,operator[ ]
char& operator[](size_t n)
{
assert(n < _size);
return _str[n];
}
const char& operator[](size_t n) const
{
assert(n < _size);
return _str[n];
}
8,reserve
void reserve(size_t n)
{
if (n > _capcity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capcity = n;
}
}
9,insert
insert overloads two versions, one for inserting characters and one for inserting strings
string& insert(size_t pos, char ch)
{
assert(pos <= _size);
//插入前检查是否需要扩容
if (_size + 1 > _capcity)
reserve(_size * 2);
//挪动数据
size_t end = _size;
while (end >= pos)
{
_str[end + 1] = _str[end];
--end;
}
_str[pos] = ch;
_size++;
return *this;
}
If you use this way of writing, you will find that the program keeps running and cannot stop when you are testing.
This is because the subscripts we use are all of size_t type. If pos is 0, when the data is moved for the last time, end is at 0 position. After moving – end, end will be reduced to -1, and -1 is for none For signed integers, it is the maximum value, so it will cause an infinite loop. So we have to write it differently.
string& insert(size_t pos, char ch)
{
assert(pos <= _size);
//插入前检查是否需要扩容
if (_size + 1 > _capcity)
reserve(_size * 2);
//挪动数据
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
_size++;
return *this;
}
insert string
When inserting strings, you also need to pay attention to the above infinite loop problem.
string& insert(size_t pos, const char* s)
{
assert(pos <= _size);
size_t lens = strlen(s);
if (_size + lens > _capcity)
reserve(_size + lens);
//挪动数据
size_t end = _size + lens;
while (end > pos + lens - 1)
{
_str[end] = _str[end - lens];
--end;
}
strncpy(_str, s, lens);
_size += lens;
return *this;
}
10,erase
string& erase(size_t pos, size_t len = npos)
{
assert(pos < _size);
//挪动数据
if (len == npos || _size - pos <= len)
{
_str[pos] = '\0';
_size = pos;
}
else
{
size_t begin = pos + len;
while (begin <= _size)
{
_str[begin - len] = _str[begin];
++begin;
}
_size -= len;
}
return *this;
}
11,push_back, pop_back, append
These interfaces can be reused using the above insert and erase.
void push_back(char ch)
{
insert(_size, ch);
}
void pop_back()
{
erase(_size - 1);
}
void append(const char* s)
{
insert(_size, s);
}
12,operator+=
+= a character
void operator+=(char ch)
{
push_back(ch);
}
+= string
void operator+=(const char* s)
{
append(s);
}
These functions are reusing insert and erase. It can be seen that once insert and erase are implemented, a lot of work has been completed.
13,swap
The swap of the member function is very simple, it only needs to exchange the internal _str, _size, _capcity.
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capcity, s._capcity);
}
14,find
find a character
size_t find(char ch,size_t pos = 0)
{
assert(pos < _size);
for (int i = pos; i < size(); i++)
{
if (_str[i] == ch)
return i;
}
return npos;
}
find a string
size_t find(const char* s, size_t pos = 0)
{
assert(pos < _size);
char* res = strstr(_str + pos, s);
if (!res)
return npos;
return res - _str;
}
15,substr
string substr(size_t pos, size_t len = npos)
{
assert(pos < _size);
string res;
size_t curlen = len;
if (len <= _size - pos || len == npos)
curlen = _size - pos;
char* tmp = new char[curlen + 1];
strncpy(tmp, _str + pos, curlen);
tmp[curlen] = '\0';
res += tmp;
delete[] tmp;
return res;
}
16, Overloading relational operators
bool operator==(const string& str) const
{
return strcmp(_str, str._str) == 0;
}
bool operator>(const string& str) const
{
return strcmp(_str, str._str) > 0;
}
bool operator>=(const string& str) const
{
return (*this > str) || (*this == str);
}
bool operator<(const string& str) const
{
return !(*this >= str);
}
bool operator<=(const string& str) const
{
return !(*this > str);
}
bool operator!=(const string& str) const
{
return !(*this == str);
}
17. Overloaded stream insertion operator
friend ostream& operator<<(ostream& _cout, const string& str);//类内
ostream& operator<<(ostream& _cout, const string& str)
{
for (int i = 0; i < str.size(); i++)
{
if (str[i] == '\0')
cout << ' ';
else
cout << str[i];
}
return _cout;
}
18. Overloaded stream insertion operator
friend istream& operator>>(istream& _cin, string& str);//类内
istream& operator>>(istream& _cin, string& str)
{
str.clear();
char ch = cin.get();
//缓冲区提高效率
char tmp[128];
int i = 0;
while (ch != ' ' && ch != '\n')
{
tmp[i++] = ch;
if (i == 127)
{
tmp[127] = '\0';
str += tmp;
i = 0;
}
ch = cin.get();
}
if (i != 0)
{
tmp[i] = '\0';
str += tmp;
}
return _cin;
}
18. Forward iterator
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}