【C++】string 的使用和模拟实现

string类对象的常见构造:

如何初始化类的对象是由类本身决定的。一个类可以定义很多种构造函数。当然每种构造函数在在初始值得数量或者类型都有差别(函数重载)。

string() 构造空的string类对象,即空字符串
string(const char* s) 用C-string来构造string类对象
string(size_t n, char c) string类对象中包含n个字符c
string(const string&s) 拷贝构造函

	string s0;//默认初始化,s0是一个空字符串
	string s1("hello world");//用字面值"hello world",构造s1
	string s2(s1);//用s1拷贝构造 s2
	string s3 = s2;//等价于s3(s2),用s2拷贝构造s3
	
	//先用字面值"hello world"构造一个string类型的临时对象,再用临时对象拷贝构造s4.
	string s4 = "hello  world";
	
	string s5(10,'c');//将s5初始化为,由10个字符'c'组成的串

读写string对象:

(1)用IO操作符(<<,>>)读写string对象

我们可以使用标准库的iostream来读写int,double,等内置类型。也可以在string类里边通过运算符重载的方式,用IO操作符(<<,>>)读写string对象。

int main(){
    string s; //空字符串
    cin >> s;//将string 对象读入s遇到空白停止
    cout << s << endl;//输出s
    retrun 0;
}

需要注意的是:在文件读取时,string类对象会忽略所有的空白(空格符,换行符,制表符等),从的一个真正的字符开始到空白结束。
所以程序输入的如果是" Hello world".输出的将会是"Hello"。

在运算符>> 和 << 重载时函数的返回值是运算符左侧的操作对象。所以所以多个输入或者输出可以连在一起:

int main(){
    sting s1,s2;//定义两个空字符串
    cin >> s1 >> s2;// 把第一个串读到s1中,第二个读到s2中
    cout << s1 << s2 << endl;//输出    
}

如果这次依然输入" Hello world" 输出为“Helloword“
(2)使用getline读取一整行:
istream& getline (istream& is, string& str);
有时候我们希望等在最终得到的字符串中,保留空白符。这时应该用getline函数代替>>运算符。函数从输入流is中读入内容到str中,直到遇到换行为止。geline只要一遇到换行符就结束读取操作并返回结果。如果一开始就输入换行符,那么就会得到一个空的sting对象。
getline也会返回他的流参数,因此可以使用getline的结果作为条件:

int main(){
    string s0;//定义一个空串
    //读入未知个string对象,每次读入一整行,直到文件的结束
    while( getline(s0) )
        cout<< s0 << endl;
    return 0;
}

关于容量的操作:

size_t size() const;返回字符串有效字符长度。
size_t length() const;返回字符串有效字符长度
size_t capacity() const; 返回空间总大小
bool empty() const; 检测字符串释放为空串,是返回true,否则返回false
void clear(); 清空有效字符 ,clear仅在逻辑层面进行数据清理,而不会进行内存释放。
void reserve (size_t n = 0);为字符串预留空间。
void resize (size_t n); void resize (size_t n, char c);将有效字符的个数该成n个,多出的空间用字符c填充
需要注意的是:

  • size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。

  • clear()只是将string中有效字符清空,不改变底层空间大小,只是将对象的_size置为0。

  • resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。操作后string对象有效元素的多少改变成了n。

  • reserve(size_t res_arg=0):为容器预留足够的空间,避免不必要的重复分配。不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,容器不会发生任何改变。如果大于将底层空间,则扩容。而对象有效元素的多少始终不发生改变。
    关于size_t 和 size_type:

  • 标准定义中,size_t和size_type被定义为unsigned int。但是sizt_t是C++的一个标准的typedef,全局有效,定义在全局名称空间中,size_type是STL定义的,size_t不是容器概念,而size_type是容器概念,没有容器不能使用。

  • size_t的引入增强了程序在不同平台上的可移植性。经测试发现,在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的,这样利用该类型可以增强程序的可移植性。

处理string对象中的字符:

(1)使用范围for处理对象的每个字符;

c++11新标准提供了一种语句:范围for语句。这种语句遍历给定序列的每个元素

string str("Hello world");
for (auto a : str )
    cout << c << endl;//输出当前字符,并换行

范围for把变量a 和 序列 str联系起来。auto是让编译器确定a的类型,a的类型是char。每次循环将序列的下一个字符拷贝给变量a,然后输出。但是如果在范围for中修改str序列,上边变量的定义显然是不行的,因为每次循环都只是将str的字符拷贝一份给变量a。所以如果要改变序列str,就应该把循环变量定义成引用类型:

string str("Hello world");
for (auto &a : str )
    a = 'H';//将str序列的每个字符换成'H'
cout << str << endl;

(2)用下标运算符[],处理string对象某个字符:

string s0 = "hello";
for(size_t i = 0; i < s0.size(); i++){
	cout << s0[i];
}
cout << endl;

string对象的下标必须大于等于0,而小于s.size()。使用超出此范围的下标将引发不可预知的结果,以此推断,使用下标访问空string会引发不可预知的结果。
(3)用迭代器处理string对象的某个字符:

  • 最常见的迭代器:
string s = "hello";
string::iterator it = s.begin();
while( it != s.end() ){
    cout<< *it <<" ";
    ++it;
}
cout << endl;

需要注意的是,s.begin()是‘h’,但是s,end()是最后一个 字符’o’的下一个位置。

  • 反向迭代器:
string s = "hello";
string :: reverse_iterator it = s.rbegin();
while( it != s.rend() ){
    cout<< *it <<" ";
    ++it;
}
cout << endl;

程序会输出: o l l e h

  • const迭代器;
const string s = "hello";
string :: const_iterator it = s.begin();
while( it != s.end() ){
    cout<< *it <<" ";
    ++it;
}
cout << endl;

string类对象的修改操作

(1)尾插一个字符
void push_back (char c);在字符串后尾插字符c
(2)尾插一个字符串。
string& append (const string& str);//str的所有内容,拼接到对象的后边
string& append (const string& str, size_t subpos, size_t sublen);//str字符串从subpos开始共sublen位拼接到对象后边。
string& append (const char* s);//将c格式的字符串拼接到,对象的后边。
string& append (const char* s, size_t n);//字符串的前 n、位拼接到对象后边。
string& append (size_t n, char c);// 将5个字符c拼接到,对象后边。
(3)在字符串后追加字符串str
string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);
(4)返回C格式字符串
const char* c_str() const noexcept;
c_str()函数返回一个指向正规C字符串的指针常量, 内容与本string串相同。这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。
注意:一定要使用strcpy()函数 等来操作方法c_str()返回的指针
(5)从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
size_t find (const string& str, size_t pos = 0) const; //查找对象–string类对象
size_t find (const char* s, size_t pos = 0) const; //查找对象–字符串
size_t find (const char* s, size_t pos, size_t n) const; //查找对象–字符串的前n个字符
size_t find (char c, size_t pos = 0) const; //查找对象–字符
找到 – 返回 第一个字符的索引,没找到–返回 string::npos(代表 -1 表示不存在)
(6)在str中从pos位置开始,截取n个字符,然后将其返回
string substr (size_t pos = 0, size_t len = npos) const;

模拟实现string类

(1)实现一个简单的string类包括 构造 拷贝构造 赋值运算符重载 析构 reserve(szie_t) push_back(char) 等

namespace LZH{
	struct string{
		string(char* str = ""){//构造
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_capacity + 1];
			strcpy(_str, str);//strcpy 会连'\0' 一起拷贝
		}
		void swap(string& s){
			std::swap(_str, s._str);
			std::swap(_size, s._size);
			std::swap(_capacity, s._capacity);
		}
		string(const string& s):_str(nullptr){//拷贝构造
			string tem(s._str);
			swap(tem);
		}
		~string(){//析构
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
		string& operator=(string s){//赋值运算符重载  先调用拷贝构造初始化形参
			swap( s );
			return *this;
		}
		void reserve(size_t  newcapacity){
			if (newcapacity <= _capacity){
				return;
			}
			char* newstr = new char[newcapacity + 1];
			strcpy(newstr, _str);
			delete[] _str;
			_capacity = newcapacity;
			_str = newstr;
		}
		void push_back(char c){
			if (_size == _capacity){//扩容
				int newcapacity = _capacity == 0 ? 1 : 2 * _capacity;
				reserve(newcapacity);
			}
			_str[_size++] = c;
			_str[_size] = '\0';
		}
	private:
		size_t _size;
		size_t _capacity;
		char* _str;
		static size_t npos;
	};
	size_t string :: npos = -1;
}//namespace LZH

(2)具体实现:
https://github.com/WhynotHH/Simulate-STL/blob/master/string.h

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值