IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++】string -> 正文阅读

[C++知识库]【C++】string

目录

前言

1.string类

1.1.常用接口

2.string模拟实现?

2.1.默认成员函数

2.2.容量(capacity)、大小(size)、清理(clear)、判空(empty)、[]重载、c_str

2.3.迭代器(iterator)?

2.4.扩容(reserve)、调整大小(resize)

2.5.尾插(append、push_back、+=)

2.6.任意位置的插入删除(insert、erase)

2.7.查找(find)

2.8.运算符重载(==、<、<=、>、>=)

2.9.输入输出(cin、cout、getline)


前言

为什么C++中增加了string类型,而不继续使用C语言中的字符串?

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问,可能会出现很多错误。

同时

在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。

1.string类

  • string类在C++中是用来管理字符串的,任何使用 string 类的程序都必须使用 #include 包含 string 头文件。
  • 为了方便使用,在类中实现了很多实用的接口。

在cplusplus中我们可以方便查看各种函数的实现和用法:https://www.cplusplus.com/reference/

string 的各种接口:https://www.cplusplus.com/reference/string/basic_string/

1.1.常用接口

string构造函数

定?义用法/功能
string()默认构造函数:创建空字符串。示例:string?str();
string(const char *s)使用 C 字符串创建一个 string 对象。示例:string str("abcd");
string(const string &s)拷贝构造函数:从现有字符串创建一个新的字符串。示例:?string s1(s);


string 类运算符重载

重载运算符用法/功能
>>

从流中提取字符并将其插入到字符串中。复制字符直至遇到空格或输入的结尾。

示例:string str(); cin >> str;

<<将字符串插入流中。示例:string str("abcd"); cout << str << endl;
=

将右侧的字符串赋值给左侧的 string 对象。示例:string s1("abc"); string s2("123"); s1 = s2;

+=将右侧字符串的副本附加到左侧的 string 对象。示例:s += 'a'; s += "abcd";
+返回将两个字符串连接在一起所形成的字符串。
[]使用数组下标表示法,如 s[x]。返回 x 位置的字符的引用。
关系运算符以下每个关系运算符都将被执行:< > <= >= = !=


string 类的成员函数

成员函数用法/功能
iterator begin();返回指向 string 中第一个字符的迭代器。
iterator end();返回指向 string 中最后一个字符的下一个位置的迭代器(即'\0'位置)。
const_iterator begin()返回指向 string 中第一个字符的迭代器。(const)
const_iterator end()返回指向 string 中最后一个字符的下一个位置的迭代器(即'\0'位置)。(const)
reverse_iterator rbegin()返回指向 string 中最后一个字符的反向迭代器。
reverse_iterator rend()返回指向 string 中第一个字符前一个位置的反向迭代器(即-1位置)。
size_t _capacity();返回 string 被分配的容量的大小。
size_t _size()返回 string 中字符串的长度。
void clear();删除 string 中存储的所有字符。
char* c_str():返回 string 对象的 C 字符串值(即以'\0'结束)。
bool empty();如果 string 为空则返回 true,否则返回 false。
void reserve(size_t n)将string容量扩大至n,如果n<_capacity 则保持不变。
void resize(size_t n)将string字符串长度扩大/ 缩小至n。
string& append(const char* str)将str字符串插入string的末尾位置。
string& push_back(char ch)将ch字符插入string的末尾位置。

string& insert(size_t pos, char*str);

string& insert(size_t pos, char ch)

将 str 字符串或ch 字符 插入到 string 中指定位置,从位置 pos 开始。
string& erase(size_t pos,? size_t n);

从 string中_str字符串的pos位置??开始,删除 n 个字符。

static const size_t nposstring 类中的静态成员,值为-1。
size_t find(char*str, size_t pos);返回在 string 中找到的 str 字符串的第一个位置。如果没有找到 str,则返回 string 类的静态成员?string::npos。
size_t find(char ch, size_t pos);返回在 string 中找到的 ch 字符的第一个位置。如果没有找到 ch,则返回?string::npos。
string substr(size_t pos, size_t n);返回一个string 对象,_str为一个字串,子串长度为 n 个字符,从string 的 pos 位置开始。
void swap(string& str);交换 string 和 str 的内容。
istream& getline(istream&, string& s)获取一行字符,包括空格

2.string模拟实现?

2.1.默认成员函数

namespace wt
{
    class string
	{
	public:
		
		string(const char* str);
	
		string(string& s);

		string& operator=(string s);

		~string();

    private:
        char* _str;
        size_t _size;
        size_t _capacity;
    }
}

由于标准库中也有string类,为防止命名冲突,这里可以加上命名空间

构造函数:使用缺省值,无参时构造空字符串,_capacity不包括'\0'

string(const char* str = "")
			:_size(strlen(str))
			,_capacity(_size)
		{
			_str = new char[_size + 1]; // 给'\0'多开一个空间
			strcpy(_str, str);
		}

析构函数:清理全部空间

~string()
		{
			delete[] _str;
			_size = _capacity = 0;
		}

拷贝构造、赋值运算符重载:面临深拷贝问题

string(string& s)
			:_str(s._str)
            ,_size(s._size)
			,_capacity(_capacity)
            
		{}
		
string& operator=(const string& s)
		{
			if (&s!=this)
			{
				_str = s._str;
                _size = s._size;
                _capacity = s._capcity;
			}
			return *this;
		}

若直接这样拷贝或复制,会导致相同的空间被析构两次,程序会崩溃,所以这里应该使用深拷贝

原始写法:按照正常思路深拷贝去拷贝和赋值

string(string& s)
			:_size(strlen(s._str))
			,_capacity(_size)
		{
            // 深拷贝
			_str = new char[_size + 1]; // 申请与被拷贝字符串相同大小的空间
			strcpy(_str, s._str); // 拷贝字符串
		}


		
string& operator=(const string& s)
		{
			if (&s!=this) // 避免自己给自己复制(导致原地址发生变化)
			{
				char* tmp = new char[strlen(s._str) + 1]; // 创建临时空间保存字符串
				strcpy(tmp, s._str);

				delete[] _str; // 释放原空间
				_str = tmp; // 直接使用临时空间地址
				_size = s._size;
				_capacity = _size;
			}
			return *this;
		}

现代写法:思路巧妙,写法简单

void swap(string& s)
{
    std::swap(_str, s._str); // 使用std中的swap库函数交换
    std::swap(_capacity, s._capacity);
    std::swap(_size, s._szie);
}

string(string& s)
			:_size(nullptr) // 先将原对象初始化为空
			,_capacity(0)
            ,_size(0)
		{
            string tmp(s._str); // 以被拷贝对象字符串创建临时对象
            swap(tmp); // 将临时对象与原对象交换
		}


		
string& operator=(string s) // 传参传临时对象,因为后面会改变该对象
		{
			swap(s); // 直接将临时对象和原对象交换
            return *this;  // 函数调用结束后临时对象会被销毁,而临时对象指向的是被交换后的空间
		}

2.2.容量(capacity)、大小(size)、清理(clear)、判空(empty)、[]重载、c_str

这部分接口比较简单,不详细介绍,主要是为后面的接口铺垫。

size_t size()const
		{
			return _size;
		}
		
size_t capacity()const
		{
			return _capacity;
		}

void clear()
		{
			_str[0] = '\0'; // 直接将首位置置为'\0'
			_size = 0;      // 将大小置为0
		}

bool empty()
		{
			return _size == 0;
		}

char& operator[](size_t pos)
		{
			return _str[pos];
		}

		
const char& operator[](size_t pos)const // 因为存在const 对象调用情况,需要实现const版本
		{
			return _str[pos];
		}

const char* c_str()const 
		{
			return _str;
		}

2.3.迭代器(iterator)?

迭代器是STL容器遍历的通用方法。

typedef const char* const_iterator; // const 对象调用
		
typedef char* iterator;
		
const_iterator begin()const 
		{
			return _str; // 本质是返回字符串起始位置的指针
		}
		
const_iterator end()const
		{
			return _str + _size; // 本质是返回字符串'\0'位置的指针
		}
		
iterator begin()
		{
			return _str;
		}
		
iterator end()
		{
			return _str + _size;
		}

用法:

void test()
{
	wt::string s1("hello world!");
	wt::string::iterator it = s1.begin();
    // 迭代器遍历
	while (it != s1.end())
	{
		std::cout << *it;
		++it;
	}
	std::cout << std::endl;

    // for循环遍历
	for (size_t i = 0; i < s1.size(); ++i)
	{
		std::cout << s1[i];
	}
	std::cout << std::endl;
    // 范围for遍历
	for (auto ch : s1)
	{
		std::cout << ch;
	}
	std::cout << std::endl;

}

2.4.扩容(reserve)、调整大小(resize)

void reserve(size_t n)
		{
			if (n > _capacity) // n <= _capacity无需扩容
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str); // 拷贝原字符串
				delete[] _str; // 释放原空间
				_str = tmp;
				_capacity = n;
			}
		}

void resize(size_t n, char ch = '\0') // 默认用'\0'填充
		{
			if (n <= _size) // 若n <= _size,只需将n位置处置为'\0'
			{
				_str[n] = '\0';
			}
			else
			{
				if (n > _capacity) // 否则需先扩容
				{
					reserve(n);
				}
				memset(_str + _size, ch, n - _size - 1);
				_str[n] = '\0';
			}
			_size = n;
		}

2.5.尾插(append、push_back、+=)

void push_back(char ch)
		{
			if (_size == _capacity) // 判断容量
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			_str[_size] = ch;
			_str[++_size] = '\0'; // 尾部添'\0'
		}

void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity) // 检查容量是否足够
			{
				reserve(_capacity+strlen(str));
			}
			strcpy(_str + _size, str);
			_size += len;
		}

string& operator+=(char ch)
		{
			push_back(ch); // 复用
			return *this;
		}

string& operator+=(const char* str)
		{
			append(str); // 复用
			return *this;
		}

2.6.任意位置的插入删除(insert、erase)

string& insert(size_t pos, char ch)
		{
			assert(pos <= _size);

			if (_size == _capacity) // 检查容量
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}

			for (size_t i = _size + 1; i > pos; --i)
			{
				_str[i] = _str[i - 1]; // 移动字符
			}

			_str[pos] = ch;
			_size++;
			return *this;
		}

string& insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_capacity + strlen(str));
			}

			/*for (size_t i = _size + len; i >= pos + len; --i)
			{
				_str[i] = _str[i - len];
			}*/

			memmove(_str + pos + len, _str + pos, _size - pos + 1);
			strncpy(_str + pos, str, len);
			_size += len;
			return *this;
		}

string& erase(size_t pos = 0, size_t n = npos)
		{
			assert(pos < _size);
			if (n == npos || n > _size - pos) // n=pos或者删除的字符个数大于剩余个数则直接将pos位置后面的所有字符全部删除
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + n);
				_size -= n;
			}
			return *this;
		}

2.7.查找(find)

size_t find(char ch)
		{
			for (size_t i = 0; i < _size; ++i)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}

size_t find(const char* str, size_t pos)
		{
			const char* ptr = strstr(_str + pos, str); // 借助strstr找字串
			if (ptr == nullptr)
			{
				return npos;
			}
			else
			{
				return ptr - _str;
			}
		}

2.8.运算符重载(==、<、<=、>、>=)

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);
	}

bool operator>=(const string& s1, const string& s2)
	{
		return !(s1 < s2);
	}

2.9.输入输出(cin、cout、getline)

std::ostream& operator<<(std::ostream& out, const string& s)
	{
		for (auto e : s)
		{
			out << e;
		}
		out << std::endl; // 这里不能使用out << s.c_str() 输出
		return out;
	}

std::istream& operator>>(std::istream& in, string& s)
	{
		s.clear(); // 输入前先清除字符串数据
		char ch = 0;
		ch = in.get(); // 获取一个字符
		while (ch != ' ' && ch != '\n')
		{
			s += ch;
			ch = in.get();
		}
		return in;
	}

std::istream& getline(std::istream& in, string& s)
	{
		s.clear();
		char ch = 0;
		ch = in.get();
		while ( ch != '\n')
		{
			s += ch;
			in.get();
		}
		return in;
	}
}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:10:02  更:2022-03-08 22:13:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:17:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码