预学先知
1.STL的六大组件,容器,算法,迭代器最为重要,allocator就是个内存池
2.STL是学习C++中一个很重要的方面,需要认真对待。“没有学过STL就不要说自己学过C++”; 三个境界:能用,明理,能扩展
3 .辅助学习的网站www.cplusplus.com
4.几个编码表 ascii – 表示英文编码表 unicode – 表示全世界文字编码表 utf-8 utf-16 utf-32 gbk --中文自己量身定做的编码表 Linux上一般设置utf-8 根据编码的不同,也有不同的方式进行存储
String类
1 .对应于C语言中的串,C++中式管理字符串的类, 同样以/0结尾,basic_string中每个字符用char存储
2 .构造方法中,重点掌握三个
#include<cstring>
#include<iostream>
using namespace std;
int main() {
string s1;
string s2("hello world");
string s3(s2);
cin >> s1;
cout << s1 << endl;
cout << s2 << " " << s3 << endl;
string s4(s2, 0, 3);
cout << s4 << endl;
string s5(s2, 2);
cout << s5 << endl;
string s6("heiheihei", 5);
cout << s6 << endl;
string s7(10, '.');
cout << s7 << endl;
return 0;
}
3 .size和length
都可以用来计算字符串的有效字符(不包含最后的标识符’\0’),两者没有区别,但是size符合各种容器,一般我们用size (历史原因,size的意思是“个数”,适用性更广,比如说树就讲个数,而string既可以讲长度也可以讲个数,但是用出来的效果没有什么区别)
int main() {
string s1("hello zkx");
cout << s1.size() << endl;
cout << s1.length() << endl;
cout << s1 << endl;
cout << s1.capacity() << endl;
s1.clear();
cout <<s1<< endl;
cout << s1.capacity() << endl;
return 0;
}
4 . [ ]方括号
可以让string像数组一样访问每个字符,at也可以访问每个字符,但是在遇到数组越界等异常的时候,[ ] 方括号是直接断言assert强制报错,at是进行异常处理,另外[ ]用的比较多
#include<cstring>
#include<iostream>
using namespace std;
int main() {
string s1("hello zkx");
for (int i = 0; i < s1.size(); i++) {
cout << s1[i] << " ";
}
cout << endl;
for (int i = 0; i < s1.size(); i++) {
s1[i] += 1;
}
for (int i = 0; i < s1.size(); i++) {
cout << s1[i] << " ";
}
cout << endl;
return 0;
}
5 .附加字符方面,建议使用+
#include<cstring>
#include<iostream>
using namespace std;
int main() {
string s1;
s1.push_back('1');
s1.append("213");
s1 += "12312312";
cout << s1 << endl;
return 0;
}
6 . 遍历 + 修改 string 的三种方式以及反向迭代器的介绍
#include<cstring>
#include<iostream>
using namespace std;
int main() {
string s1("hello zkx");
for (int i = 0; i < s1.size(); i++) {
cout << s1[i];
}
cout << endl;
string::iterator it = s1.begin();
while (it != s1.end()) {
*it += 1;
++it;
}
cout << endl;
it = s1.begin();
while (it != s1.end()) {
cout << *it << " ";
++it;
}
cout << endl;
for (auto& e : s1) {
e -= 1;
}
for (auto e : s1) {
cout << e;
}
cout << endl;
auto rit = s1.rbegin();
while (rit != s1.rend()) {
cout << *rit;
rit++;
}
cout << endl;
return 0;
}
迭代器的意义是说明? 所有的容器都可以使用迭代器这种方式去访问修改 对于string,无论是正着倒着,下标+[ ] 的方式都很好用 但是如果是其他的数据结构(不支持下标+[ ]),那么迭代器的用处就体现出来了 结论:对于string来说,要学会使用迭代器,但是一般我们还是喜欢用下标+[ ] 的方式
注意:!=是通用的, 虽然<没有重载也可以使用 用了模板以后报错可能会特别长,不用害怕,看前几行就行 带const的迭代器不能被修改
7 . reserve 和 resize
一个是开空间 ,一个是开空间加初始化 如果本来字符串有值,reserve和resize都不会对其造成影响,resize会往后面追加数据,但是如果resize的字符量小于原来有的字符量,最后以小的字符量为准
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
string s1;
s1.reserve(100);
string s2;
s2.resize(100, '1');
string s3("hello world");
s3.reserve(100);
string s4("hello world");
s4.resize(100, 'a');
string s5("hello world");
s5.resize(5);
return 0;
}
8 .c_str 可以让c++中的string使用C语言中的一些函数,它的存在是有意义的
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
string s1("hello world");
cout << s1 << endl;
cout << s1.c_str() << endl;
return 0;
}
9 .find和rfind
rfind是find倒着找
nops给了一个定值-1,其实是一个无线大的数 substr是左闭右开的
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
string s1("hello world");
cout << s1 << endl;
cout << s1.c_str() << endl;
string file("test.txt");
FILE* fout = fopen(file.c_str(), "w");
size_t pos = file.find('.');
if (pos != string::npos) {
string suffix = file.substr(pos, file.size()-pos);
cout << suffix << endl;
}
return 0;
}
应用:分离一个网址的协议,域名,地址
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
string url = "http://cplusplus.com/reference/string/string/?kw=string";
size_t pos1 = url.find(':');
string protocol = url.substr(0, pos1 - 0);
cout << protocol << endl;
size_t pos2 = url.find('/', pos1 + 3);
string domain = url.substr(pos1 + 3, pos2);
cout << domain << endl;
string uri = url.substr(pos2 + 1);
cout << uri << endl;
return 0;
}
10 .erase和insert
总的来说,插入和删除,都不建议使用,尾增和尾增还可以,但头插和任意位置删效率很低,O(n)的时间复杂度
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
string s1("hello world");
s1 += "1";
s1 += "2312312";
cout << endl;
s1.insert(0, 1, 'x');
s1.insert(s1.begin(), 'y');
s1.insert(0, "test");
cout << s1 << endl;
string s2("hello world");
s2.erase(0, 1);
s2.erase(s2.size() - 1, 1);
cout << s2 << endl;
return 0;
}
11 .string类型转换
头文件#include< string >才可以是哟个c++11特有的
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
int main() {
string s1 = "123";
int i1 = stoi("123");
int i2 = stoi(s1);
cout << i1 << " " << i2 << endl;
string s2 = to_string(12334);
cout << s2 << endl;
return 0;
}
12 .string类的模拟实现
传统写法 头文件 string.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<iostream>
#include<cstring>
#include<assert.h>
using namespace std;
namespace zkx {
class string {
public:
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
const_iterator begin()const
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator end()const
{
return _str + _size;
}
string(const char* str = "")
:_size(strlen(str))
,_capacity(_size)
{
_str = new char[_capacity+1];
strcpy(_str, str);
}
string(const string& str)
: _size(str._size)
,_capacity(_size)
{
_str = new char[_capacity + 1];
strcpy(_str, str._str);
}
string& operator=(const string& s)
{
if (this != &s)
{
char* temp = new char[strlen(s._str) + 1];
strcpy(temp, s._str);
delete[] _str;
_str = temp;
_size = s._size;
_capacity = s._capacity;
}
return *this;
}
~string()
{
delete[] _str;
_str = nullptr;
_capacity = 0;
_size = 0;
}
const char* c_str()
{
return _str;
}
size_t size() const
{
return _size;
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
private:
char* _str;
size_t _size;
size_t _capacity;
};
}
test.cpp
#include"string.h"
void test1()
{
zkx::string s1("zkxxxxx");
zkx::string s2(s1);
zkx::string s3("hello");
s1 = s3;
zkx::string s;
}
void test2()
{
zkx::string s("zkx123123");
s[0] = 'k';
for (int i = 0; i < s.size(); i++)
{
cout << s[i];
}
cout << endl;
zkx::string::iterator it = s.begin();
while (it != s.end())
{
cout << *it << " ";
it++;
}
zkx::string::const_iterator it1 = s.begin();
while (it1 != s.end())
{
cout << *it1 << " ";
it1++;
}
for (auto e : s)
{
cout << e << " ";
}
}
int main()
{
test2();
return 0;
}
现代写法完整版
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<iostream>
#include<cstring>
#include<assert.h>
#include<algorithm>
using namespace std;
namespace zkx{
class string {
public:
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
const_iterator begin()const
{
return _str;
}
iterator end()
{
return _str+_size;
}
const_iterator end()const
{
return _str + _size;
}
string(const char* str = "")
:_size(strlen(str))
,_capacity(_size)
{
_str = new char[_capacity + 1];
strcpy(_str, str);
}
string(const string& s2)
:_str(nullptr)
,_size(s2._size)
,_capacity(s2._capacity)
{
string temp(s2._str);
swap(temp);
}
void swap(string& s2)
{
std::swap(_str, s2._str);
std::swap(_size, s2._size);
std::swap(_capacity, s2._capacity);
}
string& operator=(string s2)
{
swap(s2);
return *this;
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos)const
{
assert(pos < _size);
return _str[pos];
}
const int size()const
{
return _size;
}
const char* c_str()const
{
return _str;
}
void reserve(size_t n)
{
if (n > _capacity)
{
char* temp = new char[n+1];
strcpy(temp, _str);
delete[] _str;
_str = temp;
_capacity = n;
}
}
void append(const char* s)
{
insert(_size, s);
}
void push_back(char ch)
{
insert(_size, ch);
}
string& operator+=(const char* s)
{
append(s);
return *this;
}
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
void resize(size_t n, char ch = '\0')
{
if (n <= _capacity)
{
_str[n] = '\0';
_size = n;
}
else
{
if (n > _capacity)
{
reserve(n);
}
memset(_str + _size, ch, n - _size);
_size = n;
_str[n] = '\0';
}
}
size_t find(char ch)
{
for (int i = 0; i < _size; i++)
{
if (_str[i] == ch)
return i;
}
return npos;
}
size_t find(const char* s, size_t pos = 0)
{
const char* ptr = strstr(_str + pos, s);
if (ptr == nullptr)
{
return npos;
}
else
{
return ptr - _str;
}
}
string& insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : _capacity * 2);
}
size_t end = _size + 1;
while (end > pos )
{
_str[end] = _str[end - 1];
end--;
}
_str[end] = ch;
++_size;
return *this;
}
string& insert(size_t pos,const char* s)
{
assert(pos < _size);
size_t len = strlen(s);
if (_size + len > _capacity)
{
reserve(_size + len+1);
}
size_t end = _size + len;
while (end>= pos + len)
{
_str[end] = _str[end - len];
--end;
}
strncpy(_str + pos, s, 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;
}
~string()
{
delete[] _str;
_str = nullptr;
}
private:
char* _str;
size_t _size;
size_t _capacity;
static const size_t npos = -1;
};
bool operator>(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) >0;
}
bool operator==(const string& s1, const string& s2)
{
return strcmp(s1.c_str(), s2.c_str()) == 0;
}
bool operator<(const string& s1, const string& s2)
{
return !((s1 == s2) || (s1 > s2));
}
bool operator<=(const string& s1, const string& s2)
{
return (s1 < s2) || (s1 == s2);
}
bool operator>=(const string& s1, const string& s2)
{
return (s1 > s2) || (s1 == s2);
}
bool operator!=(const string& s1, const string& s2)
{
return !(s1 == s2);
}
ostream& operator<<(ostream& out ,const string& s)
{
for (auto e : s)
{
out << e;
}
return out;
}
istream& operator>>(istream& in, string& s)
{
char ch = in.get();
while (ch != ' ' && ch != '\n')
{
s += ch;
ch = in.get();
}
return in;
}
void test()
{
string s1("zkxx");
s1.insert(0,"haha");
cout << s1.c_str() << endl;
}
void test2()
{
string s2;
cin >> s2;
cout << s2;
}
};
|