C++——string类

目录

前言:

一、C语言中字符串的缺陷

 二、string常见接口极其调用

1.构造及遍历

2.+、+=、[]、<<、>>运算符重载

3.string自身属性接口 

4.增删查改接口

三、模拟实现


前言:

        严格来说,string类并不属于STL中的一部分,出现在STL之前,STL并没有把string归入其中,但是与STL中的容器的很多操作类似,字符串的操作也很常见,所以很值得学习。

        如需自己查找文档:cplusplus.com - The C++ Resources Network

一、C语言中字符串的缺陷

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

 二、string常见接口极其调用

这是所有的接口:

看起来很多但是因为历史原因设计较为冗余,下面是对比较重要和常用的接口的操作演示,注意要包含string的头文件<string>,下面是比较常见的:

代码注释写的很详细了,应该可以直接看懂

1.构造及遍历

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

void string_test1()
{
	string str1;//  默认构造
	string str2("musssshandsomehaha");// 带参构造
	string str3(str2);// 拷贝构造

	cout << "str1: " << str1 << endl;
	cout << "str2: " << str2 << endl;
	cout << "str3: " << str3 << endl;

	string str4(str2, 3, 4);// 从下标为3的位置开始(包括此位置),长度为4的子串
	cout << "str4: " << str4 << endl;

	string str5(str2, 3, 100); // 超过最大长度会默认取到最后
	cout << "str5: " << str5 << endl;

	string str6("abcdefg", 3);// 取前3个字符
	cout << "str6: " << str6 << endl;

	// from sequence (5)	  string(const char* s, size_t n);
	// 不能这么玩,会越界,库里面没处理
	//string str7("abcdefg", 100);
	//cout << "str7: " << str7 << endl;

	string str8(7, 'm');// 填充7个字符'm',必须要加单引号
	cout << "str8: " << str8 << endl;

	// 对string的遍历
	//  []重载
	for (int i = 0; i < str2.size(); i++) // size求str长度
	{
		//str2[i]++;    //也可以对其修改
		cout << str2[i];
	}
	cout << endl;

	// at,与[]不同的是,如果越界,at会抛出异常,而[]会直接报错(assert)
	for (int i = 0; i < str2.size(); i++)
	{
		str2.at(i)++;    //也可以对其修改
		cout << str2.at(i);
	}
	cout << endl;

	// 迭代器
	// 迭代器是一个很类似于指针的东西,可能是原生指针也可能是通过运算符重载封装起来的指针,不管怎么样,都可以进行类似指针的操作
	// 下面调用的begin、end、rbegin、rend等等都是返回string迭代器的接口
	string::iterator it = str2.begin();
	while (it != str2.end())
	{
		*it += 1;
		(*it)++; // 必须加括号!!!!
		cout << *it;
		it++;
	}
	cout << endl;

	// 范围for(底层其实就是迭代器)
	for (auto ch : str2)   // auto就是自动识别类型,改成char也一样
	{
		cout << ch;
	}
	// *it给了ch,ch只是一份拷贝,并不能通过修改ch来修改str2,如果非要通过这种方式就在auto后面加引用
	cout << endl;


	// 反向遍历:反向迭代器
	//string::reverse_iterator rit = str2.rbegin();
	// 可以通过auto来简化代码
	auto rit = str2.rbegin();
	while (rit != str2.rend())
	{
		cout << *rit;
		rit++;
	}
	cout << endl;

	// const正反向迭代器,只读
	const string str9("musssshandsomehaha");

	//      iterator begin();
	// const_iterator begin() const;
	// 这些迭代器接口会自动识别类型返回,但其实也可以用cbegin、cend、crbegin、crend指定
	string::const_iterator cit = str9.begin();
	while (cit != str9.end())
	{
		cout << *cit;
		cit++;
	}
	cout << endl;

	string::const_reverse_iterator crit = str9.rbegin();
	while (crit != str9.rend())
	{
		cout << *crit;
		crit++;
	}
	cout << endl;

	// cbegin,cend,crbegin,crend直接就是指定const迭代器,前面的那一组是自动识别

	string::const_iterator ccit = str9.cbegin();
	while (ccit != str9.cend())
	{
		cout << *ccit;
		ccit++;
	}
	cout << endl;

	string::const_reverse_iterator ccrit = str9.crbegin();
	while (ccrit != str9.crend())
	{
		cout << *ccrit;
		ccrit++;
	}
	cout << endl;
}
int main()
{
    string_test1();
    return 0;
}

2.+、+=、[]、<<、>>运算符重载

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

void string_test2()
{
	// =赋值运算符重载
	// 三种赋值方式:string、C语言字符数组首元素地址、单个字符
	string s("abcdefghijklmn");
	string s1 = s;	// 这里是拷贝构造,不是运算符重载!!!
	string s2 = "hello"; // 这里也是调用了构造函数,不是运算符重载!!!
	string s3;
	s3 = 'a'; // 这里才是赋值运算符重载,因为是已经声明并初始化过的,然后才把'a'赋给s3
	//string s4 = 'a';  // 这里会报错,因为这是调用构造函数,而这里char不能隐式类型强转成string
	char a[] = "wohaoshuai";
	string s4;// =重载调用
	s4 = a;
	string s5;
	cin >> s5;
	// 打印和输入其实就是调用的重载后的<<和>>
	cout << "s1:" << s << endl;
	cout << "s2:" << s2 << endl;
	cout << "s3:" << s3 << endl;
	s3 = s;
	cout << "s3:" << s3 << endl;
	s3 = s2;
	cout << "s3:" << s3 << endl;

	cout << "s4:" << s4 << endl;
	cout << "s4:" << s5 << endl;

}

void string_test3()
{
	string s("abcdefghijklmn");
	// +重载:支持string,字符数组和char互相随便+
	string s1 = s + "hello";
	string s2 = s + "world";
	cout << "s1:" << s1 << endl;
	cout << "s2:" << s2 << endl;

	// +=重载:支持随便+=string,字符数组和char
	s1 += "hello";
	s2 += "world";
	cout << "s1:" << s1 << endl;
	cout << "s2:" << s2 << endl;

	// []重载:重载了const版本和普通版本
	s1[0] = 'M';
	s2[0] = 'W';
	cout << "s1:" << s1 << endl;
}

int main()
{
    string_test2();
    string_test3();
    return 0;
}

3.string自身属性接口 

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

void string_test4()
{
	string s("abcdefghijklmn");

	cout << s.size() << endl;	// 存储字符的长度,不算尾部的\0*
	cout << s.length() << endl;// length和size是一样的,length是历史问题,我们一般用size即可
	cout << s.capacity() << endl;// 容量
	cout << s.max_size() << endl;// 最大容量,其实就是整型的最大值,基本没用

	s.reserve(30);// 直接给s>=30的容量,是否大于,大多少,标准没有硬性规定
	cout << s.capacity() << endl;// 111
	s.reserve(20);
	cout << s.capacity() << endl;// 是否缩容取决于编译器,但是一定不会改变原来的string存储的内容,size肯定不变

	s.resize(10);// size变成10,容量不变,内容截断
	cout << s.capacity() << endl;
	cout << s.size() << endl;
	cout << "s:" << s << endl;
	//s.resize(40);// 扩容的话,容量会改变,填充\0
	//cout << s.capacity() << endl;
	//cout << s.size() << endl;
	//cout << "s:" << s << endl;
	s.resize(50, 'm');// 也可以指定扩充后的填充字符
	cout << s.capacity() << endl;
	cout << s.size() << endl;
	cout << "s:" << s << endl;

	s.clear();// 清空s,容量不变,size为0,全部都为\0
	cout << s.capacity() << endl;
	cout << s.size() << endl;
	cout << "s:" << s << endl;

	cout << s.empty() << endl;// 是否为空,1或0

	s = "abcdefghijklmn";
	cout << s.capacity() << endl;
	cout << s.size() << endl;
	cout << "s:" << s << endl;

	cout << s.empty() << endl;

	s.shrink_to_fit();// 缩容,就是把容量缩小到刚好装下内容
	cout << s.capacity() << endl;
	cout << s.size() << endl;
	cout << "s:" << s << endl;

}

int main()
{
    string_test4();
    return 0;
}

4.增删查改接口

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

void string_test5()
{
	string s("abcdefghijklmn");

	s.back() = 'x';
	s.front() = 'X';
	// 分别返回最后一个和第一个字符的引用,引用也就意味着可以修改
	cout << s << endl;

	// append  往字符串后面添加
	string str;
	string str2 = "Writing ";
	string str3 = "print 10 and then 5 more";

	str.append(str2);                       // str后面添加"Writing "
	cout << str << endl;
	str.append(str3, 6, 3);                   // 再后面添加"10 ",下标为6开始,3个字符
	cout << str << endl;

	str.append("dots are cool", 5);          // 添加"dots ",5个字符
	cout << str << endl;

	str.append("here: ");                   // 添加"here: "
	cout << str << endl;

	str.append(10, '.');                    // 添加"..........",10个'.',添加一个字符就用1,'字符',也可以写成"字符"
    str.push_back('a');
    // push_back只能往后添加字符
	cout << str << endl;

	str.append(str3.begin() + 8, str3.end());  // 迭代器,也就是begin后面数八个位置(下标为8)到最后" and then 5 more"

	cout << str << endl;
}

void string_test6()
{
	// assign 为字符串分配一个新值,替换其当前内容。

	string str;
	string base = "The quick brown fox jumps over a lazy dog.";

	str.assign(base);  // base给给str(覆盖而不是追加)
	cout << str << '\n';

	str.assign(base, 10, 9);
	cout << str << '\n';         // 指定位置给给str"brown fox"

	str.assign("pangrams are cool", 7);
	cout << str << '\n';         // "pangram" 前七个位置

	str.assign("c-string");
	cout << str << '\n';         // "c-string"

	str.assign(10, '*');
	cout << str << '\n';         // "**********",n个char

	str.assign(base.begin() + 16, base.end() - 12);
	cout << str << '\n';         // "fox jumps over"迭代器区间

}

void string_test7()
{
	// insert 插入
	// 除了尾插效率都不太好,因为要挪动数据

	string str = "to be question";
	string str2 = "the ";
	string str3 = "or not to be";
	string::iterator it;

	str.insert(6, str2);                 // to be (the )question   下标为6之前插入
	str.insert(6, str3, 3, 4);             // to be (not )the question  下标为6之前插入str3下标为3开始4个字符
	cout << str << '\n';
	str.insert(10, "that is cool", 8);    // to be not (that is )the question   下标为10前插入指定字符串的前8个字符
	cout << str << '\n';

	str.insert(10, "to be ");            // to be not (to be )that is the question 下标为10前插入指定字符串
	cout << str << '\n';

	str.insert(15, 1, ':');               // to be not to be(:) that is the question  下标为15前插入一个字符
	cout << str << '\n';

	it = str.insert(str.begin() + 5, ','); // to be(,) not to be: that is the question
	cout << str << '\n';
	str.insert(str.end(), 3, '.');       // to be, not to be: that is the question(...)
	cout << str << '\n';
	str.insert(it + 2, str3.begin(), str3.begin() + 3); // (or )

	cout << str << '\n';
}

void string_test8()
{
	// replace
	// 替换字符串的一部分,也就是部分覆盖,这个除非替换前后的两部分长度相等,不然效率不高,因为要挪动数据
	string base = "this is a test string.";
	string str2 = "n example";
	string str3 = "sample phrase";
	string str4 = "useful.";

	 Using positions:                 0123456789*123456789*12345
	//string str = base;           // "this is a test string."
	//str.replace(9, 5, str2);          // "this is an example string." (1)  从下标为9的位置开始,长度为5,替换为str2
	//str.replace(19, 6, str3, 7, 6);     // "this is an example phrase." (2)  从下标为19的位置开始,长度为6,替换为str3下标为7开始,长度为6
	//str.replace(8, 10, "just a");     // "this is just a phrase."     (3)  从下标为8的位置开始,长度为10,替换为"just a"
	//str.replace(8, 6, "a shorty", 7);  // "this is a short phrase."    (4)  从下标为8的位置开始,长度为6,替换为"a shorty"中的前7个字符
	//str.replace(22, 1, 3, '!');        // "this is a short phrase!!!"  (5)  从下标为22的位置开始,长度为1,替换为3个!
	//cout << str << '\n';

	base.replace(0, 6, base, 6, 6);
	cout << base << endl;

}

void string_test9()
{
	//pop_back
	string str = "hello world";
	cout << str << endl;
	cout << str.capacity() << endl;
	cout << str.size() << endl;
	str.pop_back();
	cout << str << endl;
	cout << str.capacity() << endl;
	cout << str.size() << endl;
	// 尾删,会把size-1,删除的位置上的元素置为\0,容量不变
}

void string_test10()
{
	// erase

	string str("This is an example sentence.");
	cout << str << '\n';
	// "This is an example sentence."
	str.erase(10, 8);                        //  10位置后面erase8个
	cout << str << '\n';
	// "This is an sentence."
	str.erase(str.begin() + 9);               //     9位置后面全erase
	cout << str << '\n';
	// "This is a sentence."
	str.erase(str.begin() + 5, str.end() - 9);  //   迭代器区间erase
	cout << str << '\n';
	// "This sentence."
}

void string_test11()
{
	string str = "We think in generalities, but we live in details.";
	// substr   截取string的一部分返回

	string str2 = str.substr(3, 5);     // "think",3位置5个
	cout << str2 << endl;

	size_t pos = str.find("live");      //   找到live的位置

	string str3 = str.substr(pos);     // live往后所有
	cout << str3 << endl;

	cout << str2 << ' ' << str3 << '\n';
}

void string_test12()
{
	// find系列
	//find  
	// 搜索字符串或单个字符,字符串必须全部匹配
	//	返回第一个匹配项的第一个字符的位置。
	// 如果未找到匹配项,该函数将返回 string::npos。

	string str("There are two needles in this haystack with needles.");
	string str2("needle");

	// different member versions of find in the same order as above:
	size_t found = str.find(str2);
	if (found != string::npos)
		cout << "first 'needle' found at: " << found << '\n';

	found = str.find("haystack");
	if (found != string::npos)
		cout << "'haystack' also found at: " << found << '\n';

	found = str.find('.');
	if (found != string::npos)
		cout << "Period found at: " << found << '\n';

	// refind,类似find,返回倒着找到的第一个
	string str3("The sixth sick sheik's sixth sheep's sick.");
	string key("sixth");

	size_t found2 = str3.rfind(key);
	if (found2 != string::npos)
		cout << found2 << endl;

	// find_first_of			在字符串中搜索与其参数中指定的任何字符匹配的第一个字符。
	// find_first_not_of  在字符串中搜索与参数中指定的任何字符都不匹配的第一个字符。
	// find_last_of          在字符串中倒着搜索与参数中指定的任何字符匹配的最后一个字符。
	// find_last_not_of   在字符串中倒着搜索与参数中指定的任何字符都不匹配的最后一个字符。
}

int main()
{

	//string_test5();
	//string_test6();
	//string_test7();
	//string_test8();
	//string_test9();
	//string_test10();
	//string_test11();
    string_test12();
	return 0;
}

5.其它(比较、输入、交换)

比较compare和交换swap就不演示了,(累了),比较是通过ascll,swap是深度交换,重点说一下getline 

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

void string_test13()
{
	// 默认情况下,string输入会忽略空格,编译器会把空格当成两个字符串的分割
	// 利用getline可以很好的解决这个问题
	// 使用getline可以读入空格,默认以换行结束,也可以指定字符作为输入的结束
	// 指定字符作为结束标志时,换行也依然是结束标志
	string str;
	string str2;
	getline(cin, str);
	getline(cin, str2, 'a');
	cout << str << endl;
	cout << str2 << endl;
}

int main()
{

    string_test13();
	return 0;
}

 ok,以上string的基本的功能都列举完毕, 下面进入模拟实现

三、模拟实现

实现过程注释写的很详细了,不多赘述。

string.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <assert.h>
using namespace std;

namespace muss
{
	class string
	{
	public:
		// 这个重命名必须放到public里面否则默认是私有无法访问
		// string由于其结构原因,迭代器可以用原生指针
		typedef char* iterator;
		typedef const char* const_iterator;


		// 短小且频繁调用的函数写到类里面,默认内联
		
		//string()
		//	:_str(new char[1] {'\0'})
		//	, _size(0)
		//	, _capacity(0)
		//{}
		
		// 加了缺省值就不用写上面那个了
		string(const char* str = "")
		{
			_size = strlen(str);
			_capacity = _size;
			// 要给\0留一个位置
			// 一定是容量+1,不是size + 1
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		string(const string& str)
		{
			// 传引用涉及到深拷贝
			size_t len = str.size();
			_size = len;
			_capacity = len;
			_str = new char[len + 1];
			strcpy(_str, str.c_str());
		}

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

		char* c_str() const
		{
			return _str;
		}

		size_t size() const
		{
			return strlen(_str);
		}

		void clear()
		{
			_size = 0;
			_str[0] = '\0';
		}

		size_t capacity() const
		{
			return _capacity;
		}

		char& operator[](size_t pos)
		{
			assert(pos >= 0 && pos < _size);
			return _str[pos];
		}

		const char& operator[](size_t pos) const
		{
			assert(pos >= 0 && pos < _size);
			return _str[pos];
		}

		string& operator=(const string& s)
		{
			if (this != &s)
			{
				delete[] _str;

				_str = new char[s._capacity + 1];
				strcpy(_str, s._str);
				_size = s._size;
				_capacity = s._capacity;
			}

			return *this;
		}

		iterator begin()
		{
			return _str;
		}

		// 一定注意end是最后一个位置的下一个位置,也就是\0
		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

		void reserve(size_t n);
		void push_back(char ch);
		void append(const char* str);
		string& operator+=(char ch);
		string& operator+=(const char* str);

		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		string& erase(size_t pos, size_t len = npos);

		size_t find(char ch, size_t pos = 0);
		size_t find(const char* str, size_t pos = 0);
		string substr(size_t pos = 0, size_t len = npos);

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
		static const size_t npos = -1;
	};
	bool operator<(const string& s1, const string& s2);
	bool operator<=(const string& s1, const string& s2);
	bool operator>(const string& s1, const string& s2);
	bool operator>=(const string& s1, const string& s2);
	bool operator==(const string& s1, const string& s2);
	bool operator!=(const string& s1, const string& s2);

	ostream& operator<<(ostream& out, const string& s);
	istream& operator>>(istream& in, string& s);
}

string.cpp

#include "string.h"

namespace muss
{
	// 保留n的容量,结果容量大于等于n就行
	// 如果n小于原来的容量,看编译器,这里就不缩小容量了
	void string::reserve(size_t n)
	{
		if (n <= _capacity)
			return;
		char* tmp = new char[n + 1];
		strcpy(tmp, _str);
		delete[] _str;
		_str = tmp;
		_capacity = n;
	}

	// 尾插
	void string::push_back(char ch)
	{
		// 插入前必须判断容量是否足够
		if (_capacity == _size)
		{
			reserve(_capacity == 0 ? 4 : 2 * _capacity);
		}
		_str[_size++] = ch;
		// 不能忘记字符串尾置为\0
		_str[_size] = '\0';
	}

	// 末尾追加字符串
	void string::append(const char* str)
	{
		size_t len = strlen(str);
		// 插入前必须判断容量是否足够
		if (_capacity < _size + len)
		{
			// 能二倍扩就二倍扩,不能就_size + len
			reserve(_capacity * 2 > _size + len ? _capacity * 2 : _size + len);
		}

		// 追加
		strcpy(_str + _size, str);

		// 最后不能忘记修改size
		_size += len;
	}

	string& string::operator+=(char ch)
	{
		// 尾插字符再返回
		//this->push_back(ch);
		push_back(ch);
		return *this;
	}

	string& string::operator+=(const char* str)
	{
		// 追加字符串再返回
		append(str);
		return *this;
	}

	// 插入数据必须要以斜杠0结尾,一定注意这个
	void string::insert(size_t pos, char ch)
	{
		assert(pos >= 0 && pos <= _size);
		// 插入前必须判断容量是否足够
		if (_capacity == _size)
		{
			reserve(_capacity == 0 ? 4 : 2 * _capacity);
		}
		_str[_size + 1] = '\0';
		// 挪
		for (size_t i = _size; i > pos; --i)
		{
			// 左边的往右边挪
			// 终止条件是pos位置挪走
			_str[i] = _str[i - 1];
		}
		// 填
		_str[pos] = ch; 
		// 插入数据之后一定要改变_size
		_size++;
	}

	void string::insert(size_t pos, const char* str)
	{
		size_t len = strlen(str);
		assert(pos <= _size && pos >= 0);
		// 插入前必须判断容量是否足够
		if (_capacity < _size + len)
		{
			// 能二倍扩就二倍扩,不能就_size + len
			reserve(_capacity * 2 > _size + len ? _capacity * 2 : _size + len);
		}
		_str[_size + len] = '\0';
		// 挪
		for (size_t i = _size + len - 1; i > pos + len - 1; --i)
		{
			// 左边的往右边挪
			// 这里len - 1就可以看成上面只插入一个字符的len是1,类比着写
			_str[i] = _str[i - len];
		}
		// 填
		// 这里不能用strcpy,strcpy会把插入三个字符之后的字符串全部清空,坑死人了
		//strcpy(_str + pos, str);
		for (size_t i = 0; i < len; ++i)
		{
			_str[i + pos] = str[i];
		}
		// 插入数据之后一定要改变_size
		_size += len;
	}

	// 擦除字符串的一部分,减少其长度,返回该string
	// 缺省参数只需要头文件给就可以了,这里再给会重定义
	string& string::erase(size_t pos, size_t len)
	{
		assert(pos >= 0 && pos < _size);
		if (len >= _size - pos)
		{
			_str[pos] = '\0';
			// 一定记得改一下_size
			_size = pos;
			return *this;
		}
		for (size_t i = pos; i < _size - len; ++i)
		{
			_str[i] = _str[i + len];
		}
		_size -= len;
		// 最后一定给上\0封上字符串
		_str[_size] = '\0';
		return *this;
	}

	size_t string::find(char ch, size_t pos)
	{
		assert(pos < _size && pos >= 0);

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

	size_t string::find(const char* str, size_t pos)
	{
		assert(pos < _size && pos >= 0);

		char* tmp = strstr(_str, str);
		if (tmp != nullptr)
			return tmp - str;
		return npos;
	}

	// 截取该string一段并返回
	string string::substr(size_t pos, size_t len)
	{
		assert(pos < _size && pos >= 0);
		
		// 如果len给大了就更新一下len
		if (len > _size - pos)
			len = _size - pos;

		string tmp;
		tmp.reserve(len);
		for (size_t i = pos; i < pos + len; ++i)
		{
			tmp += _str[i];
		}
		return tmp;
	}

	// string内字符串的比较,为什么不写类里面?
	// 因为这样会更灵活,可以把一个常量字符串放到前面
	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);
	}
	bool operator!=(const string& s1, const string& s2)
	{
		return !(s1 == s2);
	}

	// 流插入提取重载
	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch : s)
		{
			cout << ch;
		}
		return out;
	}
	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		// 流插入的话,由于输入字符串长短不确定,并且如果不处理,在前期输入会多次扩容导致效率问题
		// 所以最好整出来一个buff数组来暂存输入的字符串,如果够用,不用多次扩容,不够用,后面的扩容也相对而言扩的容量多一点,不会太频繁
		const int N = 256;
		char buff[N];
		int i = 0;

		char ch;
		//in >> ch;
		ch = in.get();
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;

				i = 0;
			}

			//in >> ch;
			ch = in.get();
		}

		if (i > 0)
		{
			buff[i] = '\0';
			s += buff;
		}

		return in;
	}
}

test.cpp

#include "string.h"
using namespace std;

namespace muss
{
	// 遍历
	void string_test1()
	{
		string s("abc");
		string s2(s);
		string s3;
		cout << s.c_str() << endl;
		cout << s2.c_str() << endl;
		cout << s3.c_str() << endl;
		for (int i = 0; i < s.size(); ++i)
		{
			cout << s[i] << " ";
		}

		cout << endl;

		string::iterator it = s.begin();
		while (it < s.end())
		{
			cout << *it << " ";
			++it;
		}

		cout << endl;

		for (auto e : s)
		{
			cout << e << " ";
		}

		cout << endl;
	}

	void test_string1()
	{
		string s1;
		string s2("hello world");
		cout << s1.c_str() << endl;
		cout << s2.c_str() << endl;

		for (size_t i = 0; i < s2.size(); i++)
		{
			s2[i] += 2;
		}

		cout << s2.c_str() << endl;

		for (auto e : s2)
		{
			cout << e << " ";
		}
		cout << endl;

		string::iterator it = s2.begin();
		while (it != s2.end())
		{
			//*it += 2;
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	void test_string2()
	{
		string s1("hello world");
		s1 += 'x';
		s1 += '#';
		cout << s1.c_str() << endl;

		s1 += "hello bit";
		cout << s1.c_str() << endl;

		s1.insert(5, '$');
		cout << s1.c_str() << endl;

		s1.insert(0, '$');
		cout << s1.c_str() << endl;

		string s2("hello world");
		cout << s2.c_str() << endl;

		s2.insert(5, "$$$");
		cout << s2.c_str() << endl;

		s2.insert(0, "$$$&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
		cout << s2.c_str() << endl;
	}

	void test_string3()
	{
		string s1("abcdefghijklmn");
		cout << s1.c_str() << endl;
		s1.erase(6, 100);
		cout << s1.c_str() << endl;

		string s2("abcdefghijklmn");
		s2.erase(6);
		cout << s2.c_str() << endl;

		string s3("abcdefghijklmn");
		s3.erase(6, 3);
		cout << s3.c_str() << endl;
	}

	void test_string4()
	{
		string s("test.cpp.zip");
		size_t pos = s.find('.');
		string suffix = s.substr(pos);
		cout << suffix.c_str() << endl;

		string copy(s);
		cout << copy.c_str() << endl;

		s = suffix;
		cout << suffix.c_str() << endl;
		cout << s.c_str() << endl;

		s = s;
		cout << s.c_str() << endl;
	}

	void test_string5()
	{
		string s1("hello world");
		string s2("hello world");

		cout << (s1 < s2) << endl;
		cout << (s1 == s2) << endl;
		cout << ("hello world" < s2) << endl;
		cout << (s1 == "hello world") << endl;
		//cout << ("hello world" == "hello world") << endl;

		cout << s1 << s2 << endl;

		string s0;
		cin >> s0;
		cout << s0 << endl;
	}
}

int main()
{
	//muss::string_test1();
	muss::test_string5();
	//char c1[] = "abcdefg";
	//char c2[] = "aaa";
	//strcpy(c1 + 1, c2);
	//cout << c1 << endl;
	return 0;
}

完结撒花~~~╰(✿´⌣`✿)╯♡

下一篇大概率是vector...........

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值