了解string
1.为什么要学习String
(1) c语言的字符串是以‘\0’结尾的字符集合,为了方便操作,c标准库提供了一系列str系列函数。但是这些库函数与字符串是分离的,不太符合OOP的思想,而且底层空间需要用户自己管理,会有越界等的分险。
(2)在Oj题或者平常工作使用中,String的出现会让对字符串的操作更加检点,方便和快捷。
2.认识String
2.1 了解string
(1).字符串是表示字符序列的对象
(2).标准的字符串类提供了对此对象的支持,其接口类似于标准子符容器的接口,但添加了专门用于操作单字符串的设计特性。
(3).string类是使用char(即作为它的字符类型, 使用它的默认char_traits和分配器类型)
(4).string类是basic_string模版类的一个实例, 它使用char来实例化basic_string模版类, 并用char_traits和allocator作为basic_taring的默认参数。
(5). 注意:这个类独立于左右的编码来处理字节,如果用来处理多字节或变长字符(如UTF-8)的序列, 这个类的做优成员(如长度或大小)以及她的迭代器, 将任然按照字节(而不是实际编码的字符)来操作。
总结:
1.string是表示字符串的字符串类
2.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3.string在底层实际是:basic_string类模板的别名,typedef basic_sting<char, char_traits, allocator> string;
4.不能操作多字节或者变长字符的序列。
在使用string 类时, 必须包含#include头文件以及using namespace std;
2.2 string的常用接口说明
函数名称 | 功能说明 |
---|---|
string() | 构造函数,构造空的string类对象, 即空字符串 |
string(const char* s) | 用C-string来构造string类对象 |
string(size_t n, char c) | string类对象中包含n个字符C |
string(const string&s) | 拷贝构造函数 |
示例 |
void
Teststring
()
{
string s1
;
//
构造空的
string
类对象
s1
string s2
(
"hello bit"
);
//
用
C
格式字
符串构造 string 类对象 s2
string s3
(
s2
);
//
拷贝构造
s3
}
|
size() | 返回字符串有效字符长度 |
length() | 返回字符串有效字符长度 |
capacity() | 返回空间总大小 |
empty() | 检测字符串释放为空串, 是返回true 否则返回false |
clear() | 清空有效字符 |
reserve() | 为空字符串预留空间 |
resize() | 将有效祖父的个数改成n个,多出来的用字符c填充 |
operator[] | 返回pos位置的字符, coset string类对象调用 |
begin + end | begin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭代器 |
rbegun + read | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 |
范围for | c++支持更简洁的范围for的新遍历方式 |
push_back | 在字符串后尾插字符c |
append | 在字符串后追加一个字符串 |
operator+= | 在字符串后追加字符串str |
c_str | 返回c格式字符串 |
find + npos | 从字符串pos位置开始往后找字符c, 返回改字符在字符串中的位置 |
rfind |
从字符串
pos
位置开始往前找字符
c
,返回该字符在字符串中的位置
|
substr |
在
str
中从
pos
位置开始,截取
n
个字符,然后将其返回
|
operator+ | 尽量少用,传值返回,导致深拷贝效率低 |
operator>> | 输入运算符重载 |
operator<< | 输出运算符重载 |
grtline | 获取一行字符串 |
relational_operators | 比较两个string的大小 |
注:1.在string尾部追加字符时, s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般 情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
3.vs 和 g++ 下string结构的说明
32位平台下
vs下string的结构共占28个字符, 内部结构稍微复杂一点, 先是有一个联合体,联合体用来定义string 中祖父床的存储空间:
1.当字符串长度小于1时,使用内部固定的字符数组来存放
2.大于等于16 ,从堆上开辟
union _Bxty
{ // storage for small buffer or pointer to larger one
value_type _Buf[_BUF_SIZE];
pointer _Ptr;
char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
struct _Rep_base
{
size_type _M_length; // 字符串有效长度
size_type _M_capacity; // 空间总大小
_Atomic_word _M_refcount; //引用计数
};
4.实现简单的string,以便于理解
mystring.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
namespace my_string
{
class string {
typedef char* iterator;
typedef const char* const_iterator;
public:
string(const char* str = "");
~string();
string(const string& s);
string& operator=(const string& s);
size_t capaccite();
size_t szie();
char* c_str();
size_t find(char ch, size_t pos = 0);
size_t find(char* str, size_t pos = 0);
void insert(size_t pos, char ch);
void swap(string& s);
void reserve(size_t n);
void resize(size_t n, char c = '\0');
void append(const char* str);
void push_back(char ch);
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
string& operator+=(char ch);
string& operator+=(char* str);
char& operator[](size_t pos);
const char& operator[](size_t pos) const;
void clear();
void insert(size_t pos, const char* str);
void erase(size_t pos, size_t len = npos);
private:
size_t __capacity;
size_t __size;
char* __str;
public:
const static size_t npos;
};
ostream& operator<<(ostream& out, const string& s);
istream& operator >> (istream& in, string& s);
}
//istream& operator>>(my_string::string::istream& _cin, my_string::string& s);
//ostream& operator<<(my_string::string::ostream& _cout, const my_string::string& s);
mystring.cpp
#include "myString.h"
const size_t my_string::string::npos = -1;
my_string::string::string(const char* str)
:__capacity(strlen(str))
,__size(__capacity)
{
__str = new char[__capacity + 1];
strcpy(__str, str);
}
my_string::string::string(const string& s)
{
string tmp(s.__str);
swap(tmp);
}
my_string::string& my_string::string::operator=(const string& s)
{
string tmp(s);
swap(tmp);
return *this;
}
void my_string::string::swap(string& s)
{
std::swap(__str, s.__str);
std::swap(__capacity, s.__capacity);
std::swap(__size, s.__size);
}
size_t my_string::string::capaccite()
{
return __capacity;
}
size_t my_string::string::szie()
{
return __size;
}
char* my_string::string::c_str()
{
return __str;
}
my_string::string::~string()
{
delete[] __str;
}
void my_string::string::reserve(size_t n)
{
if (n <= __capacity) return;
if (n > __capacity)
{
char* new_str = new char[n + 1];
if (__str)
{
strcpy(new_str, __str);
}
else
{
new_str[0] = '\0';
}
delete[] __str;
__str = new_str;
__capacity = n;
}
}
void my_string::string::resize(size_t n, char c)
{
if (n <= __capacity) {
__str[n] = '\0';
__size = n;
}
else {
reserve(n);
while(__size < n)
{
__str[__size++] = c;
}
__str[__size] = '\0';
}
}
void my_string::string::push_back(char ch)
{
if (__size >= __capacity)
{
__capacity = __capacity == 0 ? 4 : __capacity * 2;
reserve(__capacity);
}
__str[__size++] = ch;
__str[__size] = '\0';
}
my_string::string::iterator my_string::string::begin()
{
return __str;
}
my_string::string::iterator my_string::string::end()
{
return __str + __size;
}
my_string::string::const_iterator my_string::string::begin() const
{
return __str;
}
my_string::string::const_iterator my_string::string::end() const
{
return __str + __size;
}
char& my_string::string::operator[](size_t pos)
{
return __str[pos];
}
const char& my_string::string::operator[](size_t pos) const
{
return __str[pos];
}
size_t my_string::string::find(char ch, size_t pos)
{
while (__size > pos)
{
if (__str[pos] == ch)
{
return pos;
}
pos++;
}
return npos;
}
size_t my_string::string::find(char* str, size_t pos)
{
const char* p = strstr(__str + pos, str);
if (p)
{
return p - __str;
}
return npos;
}
void my_string::string::clear()
{
__str[0] = '\0';
__size = 0;
}
void my_string::string::append(const char* str)
{
size_t len = strlen(str);
if (__size + len > __capacity)
{
reserve(__size + len);
}
strcpy(__str + __size, str);
__size += len;
}
my_string::string& my_string::string::operator+=(const char ch)
{
push_back(ch);
return *this;
}
my_string::string& my_string::string::operator+=(const char* str)
{
append(str);
return *this;
}
void my_string::string::insert(size_t pos, char ch)
{
if (pos <= __size) return;
if (__size == __capacity)
{
reserve(__capacity == 0 ? 4 : __capacity * 2);
}
size_t end = __size + 1;
while (end > pos)
{
__str[end] = __str[end + 1];
--end;
}
__str[pos] = ch;
__size++;
}
void my_string::string::insert(size_t pos, const char* str)
{
if(pos <= __size) return;
size_t len = strlen(str);
if (__size + len > __capacity)
{
reserve(__size + len);
}
// 挪动数据
int end = __size;
while (end >= (int)pos)
{
__str[end + len] = __str[end];
--end;
}
strncpy(__str + pos, str, len);
__size += len;
}
void my_string::string::erase(size_t pos, size_t len)
{
if(pos < __size) return;
if (len == npos || pos + len >= __size)
{
__str[pos] = '\0';
__size = pos;
}
else
{
size_t begin = pos + len;
while (begin <= __size)
{
__str[begin - len] = __str[begin];
++begin;
}
__size -= len;
}
}
ostream& operator<<(ostream& out, const my_string::string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
istream& operator >> (istream& in, my_string::string& s)
{
s.clear();
char buff[129] = { 0 };
size_t i = 0;
char ch = in.get();
while (ch != ' ' && ch != '\n')
{
buff[i++] = ch;
if (i == 128)
{
buff[i] = '\0';
s += buff;
i = 0;
}
ch = in.get();
}
if (i != 0)
{
buff[i] = '\0';
s += buff;
}
return in;
}
int main(){
my_string::string s("str");
s += "string";
for (auto str : s)
{
std::cout << str << " ";
}
std::cout << std::endl;
const my_string::string s1 = s;
for (const auto str : s1)
{
std::cout << str << " ";
}
std::cout << std::endl;
my_string::string s2(s);
for (auto str : s2)
{
std::cout << str << " ";
}
std::cout << std::endl;
return 0;
}