關于C++STL string類的介紹及模擬實現(xiàn)
一、標準庫中的string類
1.string類
字符串的表示字符序列的類
標準的字符串類提供了對此類對象的支持,其接口類似于標準字符容器的接口,但添加了專門用于操作
單字節(jié)字符字符串的設計特性。
string類是使用char(即作為它的字符類型,使用它的默認char_traits和分配器類型(關于模板的更多信
息,請參閱basic_string)。
string類是basic_string模板類的一個實例,它使用char來實例化basic_string模板類,并用char_traits
和allocator作為basic_string的默認參數(shù)(根于更多的模板信息請參考basic_string)。
注意,這個類獨立于所使用的編碼來處理字節(jié):如果用來處理多字節(jié)或變長字符(如UTF-8)的序列,這個
類的所有成員(如長度或大小)以及它的迭代器,將仍然按照字節(jié)(而不是實際編碼的字符)來操作。
2.string類中的常用接口說明+模擬實現(xiàn)
2.1 string類對象的常見構造+模擬實現(xiàn)

代碼演示:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1;
string s4("hello world");
string s5("hello world", 7);
string s6(10, 'x');
string s2(s4);
string s3(s4, 6, 3);
cout << "s1:"<< s1.c_str() << endl;
cout << "s4:" << s4.c_str() << endl;
cout << "s5:" << s5.c_str() << endl;
cout << "s6:" << s6.c_str() << endl;
cout << "s2:" << s2.c_str() << endl;
cout << "s3:" << s3.c_str() << endl;
}
運行結果:

模擬實現(xiàn)
由于上面有些接口不常用,所以我就模擬實現(xiàn)了一部分常用的接口
string (const char* s)
namespace cxy
{
class string
{
public:
string(const char*s = "")
{
if (s==nullptr)
return;
_size = strlen(s);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, s);
}
const char* c_str()
{
return _str;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
string (const string& str)
void swap (string& str)
namespace cxy
{
class string
{
public:
void swap(string& str)
{
//下面的swap會調(diào)用庫里面的接口
::swap(_size, str._size);
::swap(_capacity, str._capacity);
::swap(_str, str._str);
}
string(const char*s = "")
{
if (s==nullptr)
return;
_size = strlen(s);
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, s);
}
string(const string& str)
:_str(nullptr), _size(0), _capacity(0)
{
string tmp(str._str);
swap(tmp);
}
char* c_str()
{
return _str;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
2.2 string類對象的容量操作+模擬實現(xiàn)

代碼演示:
int main()
{
string s1("hello world");
cout <<"s1.size(): " <<s1.size() << endl;
cout <<"s1.length(): "<< s1.length() << endl;
cout <<"s1.capacity(): "<<s1.capacity() << endl;
cout <<"s1:"<< s1 << endl;
cout << endl;
s1.clear();
cout <<"s1:"<< s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
cout << endl;
s1 = "hello world";
cout << "s1:" << s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
s1.resize(17,'x');
//當n>capacity,則擴容,并且把0~27上位置的空余位置填充‘字符'
cout << "s1:" << s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
s1.resize(27, 'x');
//當size<n<capacity,則把0~27上位置的空余位置填充‘字符'
cout << "s1:" << s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
s1.resize(5, 'x');
//當n<size,則只保留n個‘字符',空間大小不變
cout << "s1:" << s1 << endl;
cout << "s1.size(): " << s1.size() << endl;
cout << "s1.capacity(): " << s1.capacity() << endl;
cout << endl;
string s2("hello world");
s2.reserve(5);
//當n<=capacity時,空間大小不變,且不改變數(shù)據(jù)內(nèi)容
cout << "s2:" << s2 << endl;
cout << "s2.size(): " << s2.size() << endl;
cout << "s2.capacity(): " << s2.capacity() << endl;
s2.reserve(100);
//當n>capacity時,空間會增大
cout << "s2:" << s2 << endl;
cout << "s2.size(): " << s2.size() << endl;
cout << "s2.capacity(): " << s2.capacity() << endl;
}
運行結果:

得知:
reserve和resize的區(qū)別:reserve不會影響內(nèi)容,resize會影響內(nèi)容。
模擬實現(xiàn)
size_t size() const
返回字符串的有效長度
namespace cxy
{
class string
{
public:
size_t size()const
{
return _size;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
size_t capacity() const
返回空間的大小
namespace cxy
{
class string
{
public:
size_t capacity()const
{
return _capacity;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
bool empty() const
檢測字符串釋放為空串,是返回true,否則返回false
namespace cxy
{
class string
{
public:
bool empty()const
{
return _str == 0;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
void clear()
清空有效字符 ,不會改變?nèi)萘?/code>
namespace cxy
{
class string
{
public:
void clear()
{
_size = 0;
_str[_size] = '\0';
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
void reserve (size_t n = 0)
請求改變?nèi)萘?,此功能對字符串長度沒有影響,無法改變其內(nèi)容
如果 n 大于當前字符串容量,則該函數(shù)會導致容器將其容量增加到 n 字符(或更大)
n小于當前字符串容量時,不會發(fā)生改變
namespace cxy
{
class string
{
public:
void reserve(size_t n=0)
{
if (n > _capacity)
{
char *tmp = new char[n + 1];
strncpy(tmp,_str,_size+1);
delete[]_str;
_str = tmp;
_capacity = n;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
補充:strncpy是C語言中的函數(shù)
char * strncpy ( char * destination, const char * source, size_t num )
功能:
- 將source中的字符串復制到destination中,且復制num個字符個數(shù),如果在沒有復制完num個字符之前,找到了source的末尾,則目標填充零,直到向其編寫了總共num字符。
- 如果來source中的字符有效長度大于數(shù)字,則目的地末尾不會隱含任何空字符('\0')。
- 因此,在這種情況下,目的地不應被視為無效終止的 C 字符串(因此讀取它將溢出,所以這種時候記得要在末尾添加'\0')。
void resize (size_t n, char c)
void resize (size_t n)
將有效字符的個數(shù)該成n個,多出的空間用字符c填充
- 將字符串大小重新變?yōu)閚字符的長度。
- 如果 n 小于當前字符串長度,則當前值將縮短為其第一個 n 字符,從而刪除 n 之外的字符。
- 如果 n 大于當前字符串長度,則通過在末尾插入盡可能多的字符c以達到 n 的大小來擴展當前內(nèi)容。
- 如果指定c,則新元素初始化為c的副本,否則,它們是值初始化字符(空字符)。
namespace cxy
{
class string
{
public:
void resize(size_t n,char c='\0')
{
if (n<_size)
{
_size = n;
_str[_size] = '\0';
}
else
{
if (n > _capacity)
{
reserve(n);
}
memset(_str + _size, c, n - _size);
_size = n;
_str[_size] = '\0';
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
補充:memset是C語言中的函數(shù)
void * memset ( void * ptr, int value, size_t num )
功能:
- 將value傳到prt中,以第一個位置開始傳,傳num個,傳完為止。
總結
- size()與length()方法底層實現(xiàn)原理完全相同,引入size()的原因是為了與其他容器的接口保持一致,一般情況下基本都是用size()。
- clear()只是將string中有效字符清空,
不改變底層空間大小。 - resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數(shù)改變到n個,不同的是當字符個數(shù)增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間。
注意:resize在改變元素個數(shù)時,如果是將元素個數(shù)增多,可能會改變底層容量的大 - reserve(size_t res_arg=0):為string預留空間,不改變有效元素個數(shù),當
reserve的參數(shù)小于string的底層空間總大小時,reserver不會改變?nèi)萘看笮 ?/code>
2.3 string類對象的訪問及遍歷操作+模擬實現(xiàn)

代碼演示:
int main()
{
string s("hello world");
cout << "operator[] :";
for (size_t i = 0; i < s.size(); i++)
cout << s[i] ;
cout << endl;
//迭代器
string::iterator it = s.begin();
cout << "iterator :";
while (it != s.end())
{
cout << *it ;
++it;
}
cout << endl;
//范圍for
cout << "范圍for :";
for (auto ch : s)
{
cout << ch ;
}
cout << endl;
}
模擬實現(xiàn)

const char& operator[] (size_t pos) const
namespace cxy
{
class string
{
public:
const char& operator[](size_t pos)const
{
assert(pos < _size);
return _str[pos];
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
iterator begin() iterator end()
namespace cxy
{
class string
{
public:
typedef char* iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str+_size;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
C++11:范圍for
在這里不實現(xiàn),知道怎么用就行
2.4 string類對象的修改操作+模擬實現(xiàn)

代碼演示:
int main()
{
string s("hello world");
s.push_back('K');
cout << s << endl;
s.append("SSSSS");
cout << s << endl;
s += "FF";
cout << s << endl;
cout << s.find("KSS") << endl;
s.erase(11, 8);
cout << s << endl;
}
運行結果:

模擬實現(xiàn):只實現(xiàn)了一些常用的接口
void push_back (char c)
在字符串后面插入字符c
namespace cxy
{
class string
{
public:
void push_back(char c)
{
if (_size == _capacity)
{
reserve(_capacity * 2);
}
_str[_size] = c;
_str[_size+1] = '\0';
_size++;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
string& append (const char*s)
在字符串后面追加字符串s
namespace cxy
{
class string
{
public:
string &append(const char*s)
{
size_t len = strlen(s)+_size;
if (len > _capacity)
{
reserve(len);
}
strncpy(_str + _size, s, len - _size+1);
_size = len;
return *this;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
string& operator+= (const char* s)
在字符串后面追加字符串s
namespace cxy
{
class string
{
public:
string& operator+=(const char*s)
{
append(s);
return *this;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
const char* c_str() const
返回c格式的字符串
namespace cxy
{
class string
{
public:
const char* c_str()const
{
return _str;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
size_t find (const char* s, size_t pos = 0) const
從字符串pos位置開始往后找字符串s,返回該字符串s在字符串中的位置
namespace cxy
{
class string
{
public:
size_t find(const char*s,size_t pos=0)const
{
char *str = _str+pos;
while (*str)
{
char* str_s = str;
const char* tmp = s;
while (*str_s&&*tmp==*str_s)
{
tmp++;
str_s++;
}
if (*tmp=='\0')
return str - _str;
else
str++;
}
return -1;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
string& erase (size_t pos = 0, size_t len = npos)
擦除字符串的一部分,減少其長度
static const size_t npos = 0;
namespace cxy
{
class string
{
public:
string &erase(size_t pos = 0, size_t len = npos)
{
assert(pos < _size);
if (len+pos >= _size)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
return *this;
}
private:
size_t _size;
size_t _capacity;
char* _str;
};
}
2.5 string類非成員函數(shù)+模擬實現(xiàn)

模擬實現(xiàn)
istream& operator>> (istream& is, string& str)
namespace cxy
{
class string
{
public:
private:
size_t _size;
size_t _capacity;
char* _str;
};
istream& operator >> (istream& is, string& str)
{
str.clear();
char ch;
ch = is.get();
while (ch != ' '&&ch != '\0')
{
str += ch;
ch = is.get();
}
return is;
}
}
說明一下:這個函數(shù)實現(xiàn)放在全局,是因為他的is要和對象str搶第一個位置,如果放在string類里面實現(xiàn),那么第一個位置是this指針,也就是str對象,在用這個函數(shù)的時候就會很變扭。
ostream& operator<< (ostream& os, const string& str);
namespace cxy
{
class string
{
public:
private:
size_t _size;
size_t _capacity;
char* _str;
};
ostream& operator<< (ostream& os, string& str)
{
for (auto ch:str)
{
os << ch;
}
return os;
}
}
istream& getline (istream& is, string& str)
獲取一行字符串
namespace cxy
{
class string
{
public:
private:
size_t _size;
size_t _capacity;
char* _str;
};
istream&getline(istream&is ,string&s)
{
s.clear();
char ch;
ch = is.get();
while (ch != '\0')
{
s += ch;
ch = is.get();
}
return is;
}
}
到此這篇關于 關于C++STL string類的介紹及模擬實現(xiàn)的文章就介紹到這了,更多相關C++STL string類介紹及模擬實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
C++利用MySQL API連接和操作數(shù)據(jù)庫實例詳解
這篇文章主要介紹了C++利用MySQL API連接和操作數(shù)據(jù)庫實例詳解的相關資料,需要的朋友可以參考下2017-01-01

