C++ における文字列の文法と一般的なインターフェイスの使用法

C 言語では、string は文字列を処理するための標準ライブラリ クラス (クラス) です。これは、文字列を操作するためのより高度で便利な方法を提供します。string クラスは、文字列の操作と処理を容易にするために、一連のメンバー関数とオーバーロードされた演算子を提供します。 。

1.文字列クラス

文字列を学習する前に、まず文字列クラスとは何なのか、またその用途は何なのかを理解したほうがよいでしょうか。まずは基本的な概念を理解しましょう

C++ 標準ライブラリはすべて英語で解釈されます。私たちも適応するように努めるべきです、理解できない場合はそれを参照してください。もちろん、ここでは主に次のような訳を直接示します。

String は文字のシーケンスを表すクラスです。

  • 標準の文字列クラスは、標準の文字コンテナと同様のインターフェイスを備えたこのようなオブジェクトのサポートを提供しますが、特にシングルバイト文字列を操作するための設計機能が追加されています。

  • string クラスは char を使用しています (つまり、文字型として、デフォルトの char_traits およびアロケーター型を使用します) (テンプレートの詳細については、basic_string を参照してください)。

  • string クラスは、basic_string テンプレート クラスのインスタンスであり、char を使用して Basic_string テンプレート クラスをインスタンス化し、char_traits と allocator を Basic_string のデフォルト パラメーターとして使用します (テンプレートの詳細については、basic_string を参照してください)。

  • このクラスは、使用されるエンコーディングとは独立してバイトを処理することに注意してください。マルチバイト文字または可変長文字 (UTF-8 など) のシーケンスを処理するために使用された場合、このクラスのすべてのメンバー (長さまたはサイズなど) とその反復は引き続き処理されます。 (実際のエンコードされた文字ではなく) バイトを操作します。

次に、文字列の一般的な使用法

2.1 文字列オブジェクトの構築

2.1.1 文字列オブジェクトの構築の使用方法

最も一般的に使用されるのは、文字列を使用してオブジェクトを構築すること、つまり文字を格納することです。一般的に使用されるメソッドは次のとおりです。

  • string() - 空の文字列クラス オブジェクト、つまり空の文字列を構築します。

  • string(const char* s) - char* を使用して文字列クラス オブジェクトを構築します。

  • string(size_t n, char c)—文字列クラス オブジェクトには n 個の文字 c が含まれます

  • string(const string&s) - コンストラクターをコピーします

以下に、使用方法を理解するために使用方法に対応する例を示します。

3. 一般的に使用される文字列構造の基礎となる実装

3.1 初期構造

上記の構造により、文字列の最下層が実際には配列を指す文字ポインタであることを見つけて理解するのは難しくありませんもちろん、有効長 (_size)配列容量 (_capacity)を維持するために 2 つの変数も必要です。

次に、自分で実装した文字列クラスの std 名前空間を区別するために、自分で名前空間を設定できます。型シミュレーションの実装は次のとおりです。

namespace gtm
{
	class string
	{
     public:
        //string()
		//	:_str(new char[1])
		//	, _size(0)
		//	,_capacity(0)
		//{
		//}
		//string(const char* str)
		//	:_str(new char[strlen(str) + 1])  //三次strlen函数,效率低。
		//	,_size(strlen(str))
		//	,_capacity(strlen(str))
		//{
		//	strcpy(_str, str);
		//}
		// 不再使用strlen函数,初始化列表与变量声明顺序固定
		string(const char* str = "") //默认空串。注意:空串是以 \0 结尾
		{
			_size = strlen(str);
			_capacity = _size;
			_str = new char[_size + 1];
			strcpy(_str, str);
		}
        ~string()
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
     private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};

3.2 返品のサイズと容量

これら 2 つの部分は実装が比較的簡単です。これは最も一般的に使用される 2 つの部分でもあります。詳細は次のとおりです。

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

3.3 コピー構築と代入のオーバーロード

これら 2 つの部分は、2 つの部分のうちより複雑です。これらはすべて完了するために深いコピーを必要としますが、浅いコピーは不可能です。注:コピー構築では、定義された変数を使用して別の変数を初期化し、代入のオーバーロードは 2 つの定義された変数の代入です

具体的な実装は以下の通りです。

//深拷贝
		//string(const string& s)
		//	:_str(new char[s._capacity+1])
		//	,_size(s._size)
		//	,_capacity(s._capacity)
		//{
		//	strcpy(_str, s._str);
		//}
		void swap(string& tmp)
		{
			//调用全局的swap
			::swap(_str, tmp._str);
			::swap(_size, tmp._size);
			::swap(_capacity, tmp._capacity);
		}
		//借助变量tmp
		string(const string& s)
			:_str(nullptr) 
			, _size(0)
			, _capacity(0)
		{
			string tmp(s._str);
			swap(tmp);
		}
		//赋值
		//string& operator=(const string& s)
		//{
		//	if(this == &s)
		//	{
		//		return *this;
		//	}
		//	//先开空间拷贝数据,以防new失败销毁原来的空间
		//	char* tmp = new char[s._capacity + 1];
		//	strcpy(tmp, s._str);
		//	delete[] _str;
		//	_str = tmp;
		//	_size = s._size;
		//	_capacity = s._capacity;
		//	return *this;
		//	//delete[] _str;
		//	//_str = new char[s._capacity + 1];
		//	//strcpy(_str, s._str);
		//	//_size = s._size;
		//	//_capacity = s._capacity;
		//	return *this;
		//}
		//string& operator=(const string& s)
		//{
		//	if(this == &s)
		//	{
		//		return *this;
		//	}
		//	string tmp(s._str);
		//	swap(tmp);
		//  return *this;
		//}
		string& operator=(string s)
		{
			if (this == &s)
			{
				return *this;
			}
			swap(s);
			return *this;
		}

前述の補助的なオーバーロードでは、一時変数 s を巧みに使用しています。割り当てが完了すると、 が自動的に呼び出され、スコープが外れた後に破棄されるため、繰り返し理解する必要があります。

3.4 拡張(予備)

予約を拡張として単純に理解できますが (拡張の前提は、必要な容量が元の容量よりも大きいことです)、元の内容を文字配列にコピーし、以前に動的に開かれたスペースを解放することを忘れないでください。具体的な実装は以下の通りです。

void reserve(size_t capacity)
		{
			if (capacity > _capacity)
			{
				char* tmp = new char[capacity + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = capacity;
			}
		}

3.5 挿入 (push_back、append、operator+=、insert)

挿入の実装においては、容量を拡張するかどうかがポイントとなります次に、push_back と append を実装すると、他の構造を実装に再利用できます。具体的な実装は以下の通りです。

        void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			_str[_size] = ch;
			_size++;
			_str[_size] = '\0';
		}
		void append(const char* str)
		{
			size_t len = strlen(str);
			if (len + _size > _capacity)
			{
				reserve(len + _size >= _capacity * 2 ? len + _size : _capacity * 2);
			}
			strcpy(_str + _size, str);
			_size += len;
		}
		void append(const string& s)
		{
			append(s._str);
		}
		void append(int n, char ch)
		{
			reserve(_size + n);
			for (int i = 0; i < n; i++)
			{
				push_back(ch);
			}
		}
		string& operator+= (char ch)
		{
			push_back(ch);
			return *this;
		}
		string& operator+= (const char* str)
		{
			append(str);
			return *this;
		}
		string& insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			//注意,当运算数一个是有符号,另一个是无符号时,有符号的运算数会强制类型转换为无符号数。pos等于0的位置插入,end--后为超大数据,会出错。
			//int end = _size;
			//while (end >= (int)pos)
			//{
			//	_str[end + 1] = _str[end];
			//	end--;
			//}
			size_t end = _size+1;
			while (end > pos)
			{
				_str[end] = _str[end - 1];
				end--;
			}
			_str[pos] = ch;
			_size++;
			return *this;
		}
		string& insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (len + _size > _capacity)
			{
				reserve(len + _size >= _capacity * 2 ? len + _size : _capacity * 2);
			}
			size_t end = _size + len;
			while (end >= pos+len)
			{
				_str[end] = _str[end - len];
				end--;
			}
			for (int i = pos,j=0; j < len;j++, i++)
			{
				_str[i] = str[j];
			}
			_size += len;
			return *this;
		}

string は C++ において比較的重要であり、開始時に学習する必要があるコンテナでもあります。これは日常生活で頻繁に使用されるため、単純な使用法をマスターするだけでなく、その基礎となる実装を理解する必要があります。これは、その後の使用と理解に役立ちます。この記事では、string で一般的に使用される構文と、その基盤となるインターフェイスの実装をリストします。これらは、習熟する必要がある内容です。

おすすめ

転載: blog.csdn.net/shiwei0813/article/details/132371693