string--关于STL标准模板库

string的概念

string是标准库的字符序列容器,使用string需要包含头文件<string>。

在使用迭代器时需要额外添加头文件:<functional>,<algorithm>。

string常用的迭代器:

string的用法示例

'string 变量可以直接通过赋值操作符 = 进行赋值'

#include <iostream>
#include <string>
using namespace std;

int main(){
    string s1;
    string s2 = "c plus plus";
    string s3 = s2;
    string s4 (5, 's');
    return 0;
}

变量 s1 只是定义但没有初始化,编译器会将默认值赋给 s1,默认值是"",也即空字符串。

变量 s2 在定义的同时被初始化为"c plus plus"。与C风格的字符串不同,string 的结尾没有结束标志'\0'。

变量 s3 在定义的时候直接用 s2 进行初始化,因此 s3 的内容也是"c plus plus"。

变量 s4 被初始化为由 5 个's'字符组成的字符串,也就是"sssss"。

获取字符串长度

string s = "studying in mayi";
int len = s.length();
cout << len << endl;

//输出:16,因为string的末尾没有“\0”字符,所有返回的是真实长度,没有+1.(空格也算长度)

转换为C风格的字符串

//打开文件时的路径,需要用到C风格的字符串,
//string 类为我们提供了一个转换函数c_str(),
//该函数能够将 string 字符串转换为C风格的字符串,并返回该字符串的 const 指针(const char*)。

string path = "D:\\demo.txt";
FILE *fp = fopen(path.c_str(), "rt");

//为了使用C语言中的 fopen() 函数打开文件,必须将 string 字符串转换为C风格的字符串。

字符串的拼接

string类对常用的运算符进行了重载,在对字符进行操作时,就会异常方便;

#include <string>
using namespace std;

int main(){
    string s1 = "first ";
    string s2 = "second ";
    char *s3 = "third ";
    char s4[] = "fourth ";
    char ch = '@';
    
    string s5 = s1 + s2;
    string s6 = s1 + s3;
    string s7 = s1 + s4;
    string s8 = s1 + ch;
    
    cout << s5 << endl 
         << s6 << endl 
         << s7 << endl 
         << s8 << endl;
    return 0;
}

输出:first second
	 first third
	 first fourth
	 first @

这里有一个通用的截取字符串并保存或者输出的方法,这里用到了序列式容器vector,之后会继续更新它的用法;

//分割字符串,通用法

void  split(const string & str,const string & sp, vector<string> &arr) {
	size_t left = 0;
	size_t pos = 0;
	while ((pos = str.find(sp, left)) != string::npos)//sp为标记字符串,left为开始下标
	{
		arr.push_back(str.substr(left, pos - left));//left为起始下标,pos-left为提取长度
		left = pos + sp.size();
	}
	if (left < str.size()) {//还未结束,要将剩余的读完
		arr.push_back(str.substr(left));
	}
}

排序函数

#include <algorithm> //需要头文件

int main4() {
	string s1 = "sdfASDMKvgp";
	string s4 = "878463129";
	sort(s4.begin(), s4.end());
	cout << s4 << endl;

	sort(s1.rbegin(), s1.rend());
	cout << s1 << endl;

	sort(s4.begin(), s4.end(), greater<char>()); //指定排序方向从大到小
	cout << s4 << endl;

	sort(s1.begin(), s1.end(), [](char a, char b) //用lambda表达式进行排序,俗称匿名函数
	{
		return a < b;
	});
	cout << s1 << endl;
	return 0;
}

手撕string类的实现

string类还是比较好实现的,底层就是用char*型指针进行频繁的动态申请内存空间并释放;

头文件:String.h 

//String.h 头文件
#include <iostream>
#include <exception>
using namespace std;
class String
{
public:
	String();//无参构造函数
	String(const char *str);//有参构造函数
	~String();//析构函数
	String(const String &other);//深拷贝构造函数

	char * c_Str() const;//转为C风格字符串
	char At(const int index) const;//下标访问函数
	char Front() const;//访问首字符函数
	char Back() const;//访问尾字符函数
	int Size() const;//获取长度
	bool Empty() const;//判空函数
	void Erase(const int index);//删除指定下标元素
	void Clear();//清空函数
	void pop_Back();//删除尾元素
	String Substr(const int index, int count) const;//截断字符串

	String operator = (const String &other);//重载=
	String &operator += (const char *str);//重载+=字符串
	String &operator += (const String &obj);//重载+=对象
	String operator + (const char *str) const;//重载+字符串
	String operator + (const String &obj) const;//重载+对象
	String operator * (const int num) const;//重载*

	bool operator != (const String &obj) const;//重载!=
	bool operator == (const String &obj) const;//重载==

	char operator [] (int index);//重载[],可修改
	const char operator [] (const int index) const;重载[],均不可修改

	friend istream &operator >> (istream &input, String &obj);//重载流输入>>
	friend ostream &operator << (ostream &output, const String &obj);//重载流输出<<
private:
	char *m_str;
};

源文件:String.cpp 

//String.cpp 源文件
#include "String.h"

String::String()
{
	m_str = nullptr;
}

String::String(const char *str)
{
	if (str) {
		int length = strlen(str) + 1;
		m_str = new char[length];
		strcpy_s(m_str, length, str);
        //strcpy_s拷贝函数,参数是目标字符串地址,目标字符串长度,源字符串地址
	}
	else
	{
		m_str = nullptr;
	}
}

String::~String()
{
	if (m_str) {
		delete[] m_str;
	}
}

String::String(const String & other) : String(other.m_str)
{
}

//根据需求,添加const关键字,使之成为常成员函数,防止函数内部修改对象
char * String::c_Str() const
{
	char *str = new char[strlen(m_str) + 1];
	strcpy_s(str, strlen(m_str) + 1, m_str);
	return str;
}

//根据需求,在适当的地方进行异常处理
char String::At(const int index) const
{
	if (index < 0 || index > Size()) {
		throw logic_error("下标异常!");
	}
	return m_str[index];
}

char String::Front() const
{
	if (Empty()) {
		throw logic_error("字符串为空!");
	}
	return m_str[0];
}

char String::Back() const
{
	if (Empty()) {
		throw logic_error("字符串为空!");
	}
	return m_str[strlen(m_str) - 1];
}

int String::Size() const
{
	return strlen(m_str);
}

bool String::Empty() const
{
	return m_str == nullptr;
}

void String::Erase(const int index)
{
	if (index < 0 || index > Size()) {
		throw logic_error("下标异常!");
	}
	memmove(m_str + index, m_str + index + 1, strlen(m_str) - index);
	//此函数允许有重叠的部分
	//m_str + index表示目标内存的起始地址,m_str + index + 1是源内存起始地址,strlen(m_str) - index要复制的字节数
}

void String::Clear()
{
	if (m_str) {
		delete[] m_str;
		m_str = nullptr;
	}
	else
	{
		throw logic_error("清空失败!");
	}
}

void String::pop_Back()
{
	if (m_str == nullptr) {
		return;
	}
	int length = strlen(m_str);
	m_str[length - 1] = '\0';
}

String String::Substr(const int index, int count) const
{
	String temp;
	int length = Size();
	if (index >= length) {
		return temp;
	}
	if (index + count > length) {
		count = length - index;
	}
	temp.m_str = new char[count + 1];
	strncpy_s(temp.m_str, count + 1, m_str + index, count);
	//m_str + index表示偏移后的地址,count表示要拷贝的字符数
	return temp;
}

String String::operator=(const String & other)
{
	if (m_str) {
		delete[] m_str;
	}
	m_str = nullptr;
	if (other.m_str) {
		int length = strlen(m_str) + 1;
		m_str = new char[length];
		strcpy_s(m_str, length, other.m_str);
	}
	return *this;
}

//对象和字符串都要考虑到
//思考何时需要返回引用
String & String::operator+=(const char * str)
{
	if (str == nullptr) {
		return *this;
	}
	int newlen = strlen(str) + 1;
	if (m_str) {
		newlen += strlen(m_str);
	}
	char *temp = new char[newlen];
	temp[0] = '\0';
	if (m_str) {
		strcpy_s(temp, newlen, m_str);
		delete[] m_str;
	}
	strcat_s(temp, newlen, str);
	m_str = temp;
	return *this;
}

String & String::operator+=(const String & obj)
{
	return (*this) += obj.m_str;
}

String String::operator+(const char * str) const
{
	String temp = *this;
	temp += str;
	return temp;
}

String String::operator+(const String & obj) const
{
	String temp = *this;
	temp += obj.m_str;
	return temp;
}

String String::operator*(const int num) const
{
	String temp;
	for (int i = 0; i < num; ++i) {
		temp += m_str;
	}
	return temp;
}

bool String::operator!=(const String & obj) const
{
	if (strlen(obj.m_str) != strlen(this->m_str)) {
		return true;
	}
	for (size_t i = 0; i < strlen(m_str); ++i) {
		if (this->m_str[i] != obj.m_str[i]) {
			return true;
		}
	}
	return false;
}

bool String::operator==(const String & obj) const
{
	if (strlen(obj.m_str) != strlen(this->m_str)) {
		return false;
	}
	for (size_t i = 0; i < strlen(m_str); ++i) {
		if (this->m_str[i] != obj.m_str[i]) {
			return false;
		}
	}
	return true; 
}

//根据需求,添加const关键字,使返回值、参数、对象皆不可修改。(下面俩保留一个即可)
char String::operator[](int index)
{
	if (index < 0 || index > Size()) {
		throw logic_error("下标异常!");
	}
	return m_str[index];
}

const char String::operator[](const int index) const
{
	if (index < 0 || index > Size()) {
		throw logic_error("下标异常!");
	}
	return m_str[index];
}

istream & operator >> (istream & input, String & obj)
{
	cout << "请输入字符串:";
	char buffer[1024] = { 0 };
	input >> buffer;
	if (obj.m_str) {
		delete[]obj.m_str;
		obj.m_str = nullptr;
	}
	obj.m_str = new char[strlen(buffer) + 1];
	strcpy_s(obj.m_str, strlen(buffer) + 1, buffer);
	return input;
}

ostream & operator << (ostream & output, const String & obj)
{
	if (obj.m_str) {
		output << obj.m_str;
		return output;
	}
	return output;
}

主函数:main.cpp 

//主函数接口
#include <iostream>
using namespace std;
#include "String.h"

int main() {
	//无参构造
	String str1;
	cout << "str1:" << str1 << endl;
	//有参构造
	String str2("hello");

	cout << "str2:" << str2 << endl;
	//拷贝构造函数
	String str3(str2);
	cout << "str3:" << str3 << endl;
	//c_Str()函数
	char *buffer = str2.c_Str();
	cout << "c风格字符串buffer:" << buffer << endl;
	//At()函数
	try
	{
		cout << "At()函数:" << str2.At(4) << endl;
	}
	catch (const std::exception & e)
	{
		cout << "At()函数:" << e.what() << endl;
	}
	//Front()函数
	try
	{
		cout << "Front()函数:" << str2.Front() << endl;
	}
	catch (const std::exception & e)
	{
		cout << "Front()函数:" << e.what() << endl;
	}
	//Back()函数
	try
	{
		cout << "Back()函数:" << str2.Back() << endl;
	}
	catch (const std::exception & e)
	{
		cout << "Back()函数:" << e.what() << endl;
	}
	//Size()函数
	cout << "Size()函数:" << str2.Size() << endl;
	//Empty()函数
    //默认情况下,bool类型会以1或0的形式输出,使用boolalpha()操纵器设置输出格式为true或false
	cout << "Empty()函数:" << boolalpha << str1.Empty() << endl;
	cout << "Empty()函数:" << boolalpha << str2.Empty() << endl;

	//重载=
	String str4 = str2;
	cout << "str4:" << str4 << endl;
	//重载+=,分别是 +=字符串 和 +=对象
	cout << "+= 字符串:" << (str2 += " world!") << endl;
	cout << "+= 对象:" << (str3 += str4) << endl;
	//重载[]
	cout << "下标[]:" << str2[0] << endl;
	//重载!= 和 ==
	cout << "!= 吗?:" << boolalpha << (str2 != str3) << endl;
	cout << "== 吗?:" << boolalpha << (str2 == str3) << endl;
	//重载+,分别是 +字符串 和 +对象
	cout << "+ 字符串:" << (str2 + ",c++") << endl;
	cout << "+ 对象:" << (str3 + str4) << endl;
	//重载*
	cout << "对象 * 个数:" << (str4 * 3) << endl;
	
	String str5 = "abandon_c++";
	//Substr()函数
	String temp = str5.Substr(8, 3);
	cout << "Substr()函数:" << temp << endl;
	//Erase()函数
	str5.Erase(7);
	cout << "Erase()函数:" << str5 << endl;
	//pop_Back()函数
	str5.pop_Back();
	str5.pop_Back();
	str5.pop_Back();
	cout << "pop_Back()函数:" << str5 << endl;
	//Clear()函数
	try
	{
		str1.Clear();
		cout << "Clear()函数:" << str5;
		cout << "清空成功!" << endl;
	}
	catch (const std::exception & e)
	{
		cout << "Clear()函数:" << e.what() << endl;
	}

	//重载 >> 和 << 
	cin >> str1;
	cout << "输出:" << str1 << endl;
	return 0;
}

输出:

输出:
str1:
str2:hello
str3:hello
c风格字符串buffer:hello
At()函数:o
Front()函数:h
Back()函数:o
Size()函数:5
Empty()函数:true
Empty()函数:false
str4:hello
+= 字符串:hello world!
+= 对象:hellohello
下标[]:h
!= 吗?:true
== 吗?:false
+ 字符串:hello world!,c++
+ 对象:hellohellohello
对象 * 个数:hellohellohello
Substr()函数:c++
Erase()函数:abandonc++
pop_Back()函数:abandon
Clear()函数:清空失败!
请输入字符串:这里是CSDN博客!
输出:这里是CSDN博客!

STL是C++的灵魂,这也正是C++的伟大之处,本文为基础知识分享,如有错误和补充,请在评论区指正,感谢!

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值