当前位置: 首页 > news >正文

了解string

1.为什么要学习String

(1) c语言的字符串是以‘\0’结尾的字符集合,为了方便操作,c标准库提供了一系列str系列函数。但是这些库函数与字符串是分离的,不太符合OOP的思想,而且底层空间需要用户自己管理,会有越界等的分险。

(2)在Oj题或者平常工作使用中,String的出现会让对字符串的操作更加检点,方便和快捷。

2.认识String

2.1 了解string

(1).字符串是表示字符序列的对象

(2).标准的字符串类提供了对此对象的支持,其接口类似于标准子符容器的接口,但添加了专门用于操作单字符串的设计特性。

(3).string类是使用char(即作为它的字符类型, 使用它的默认char_traits和分配器类型)

(4).string类是basic_string模版类的一个实例, 它使用char来实例化basic_string模版类, 并用char_traits和allocator作为basic_taring的默认参数。
(5). 注意:这个类独立于左右的编码来处理字节,如果用来处理多字节或变长字符(如UTF-8)的序列, 这个类的做优成员(如长度或大小)以及她的迭代器, 将任然按照字节(而不是实际编码的字符)来操作。

总结:

1.string是表示字符串的字符串类
2.该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3.string在底层实际是:basic_string类模板的别名,typedef basic_sting<char, char_traits, allocator> string;
4.不能操作多字节或者变长字符的序列。

在使用string 类时, 必须包含#include头文件以及using namespace std;

2.2 string的常用接口说明
函数名称功能说明
string()构造函数,构造空的string类对象, 即空字符串
string(const char* s)用C-string来构造string类对象
string(size_t n, char c)string类对象中包含n个字符C
string(const string&s)拷贝构造函数



示例


 
void Teststring ()                                                  
{                                                                         
string s1 ; // 构造空的 string 类对象 s1
         string s2 ( "hello bit" ); // C 格式字            
符串构造
string 类对象 s2                 
string s3 ( s2 ); // 拷贝构造 s3           
}                                                                      
size()返回字符串有效字符长度
length()返回字符串有效字符长度
capacity()返回空间总大小
empty()检测字符串释放为空串, 是返回true 否则返回false
clear()清空有效字符
reserve()为空字符串预留空间
resize()将有效祖父的个数改成n个,多出来的用字符c填充
operator[]返回pos位置的字符, coset string类对象调用
begin + endbegin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭代器
 
rbegun + readbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
范围forc++支持更简洁的范围for的新遍历方式
push_back在字符串后尾插字符c
append在字符串后追加一个字符串
operator+=在字符串后追加字符串str
c_str返回c格式字符串
find + npos从字符串pos位置开始往后找字符c, 返回改字符在字符串中的位置
rfind
从字符串 pos 位置开始往前找字符 c ,返回该字符在字符串中的位置
substr
str 中从 pos 位置开始,截取 n 个字符,然后将其返回
operator+尽量少用,传值返回,导致深拷贝效率低
operator>>输入运算符重载
operator<<输出运算符重载
grtline获取一行字符串
relational_operators比较两个string的大小

注:1.在string尾部追加字符时, s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般 情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

2. string 操作时,如果能够大概预估到放多少字符,可以先通过 reserve 把空间预留好。

3.vs 和 g++ 下string结构的说明

32位平台下

vs下string的结构共占28个字符, 内部结构稍微复杂一点, 先是有一个联合体,联合体用来定义string 中祖父床的存储空间:

1.当字符串长度小于1时,使用内部固定的字符数组来存放
2.大于等于16 ,从堆上开辟

union _Bxty
{ // storage for small buffer or pointer to larger one
 value_type _Buf[_BUF_SIZE];
 pointer _Ptr;
 char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
这种设计也是有一定道理的,大多数情况下字符串的长度都小于 16 ,那 string 对象创建好之后,内
部已经有了 16 个字符数组的固定空间,不需要通过堆创建,效率高。
其次:还有 一个 size_t 字段保存字符串长度,一个 size_t 字段保存从堆上开辟空间总的容量
最后:还 有一个指针 做一些其他事情。
故总共占 16+4+4+4=28 个字节。
g++下string的结构是通过写时拷贝,string对象总共占4个字节,内部只包含一些指针,该指针将来指向一块堆内存空间
struct _Rep_base
{
 size_type _M_length; // 字符串有效长度
 size_type _M_capacity; // 空间总大小
 _Atomic_word _M_refcount; //引用计数
};

4.实现简单的string,以便于理解

mystring.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <string.h>

using namespace std;
namespace my_string
{
	class string {
		typedef char* iterator;
		typedef const char* const_iterator;

	public:
		string(const char* str = "");
		~string();
		string(const string& s);
		string& operator=(const string& s);

		size_t capaccite();
		size_t szie();
		char* c_str();
		size_t find(char ch, size_t pos = 0);
		size_t find(char* str, size_t pos = 0);
		void insert(size_t pos, char ch);
		void swap(string& s);
		void reserve(size_t n);
		void resize(size_t n, char c = '\0');
		void append(const char* str);
		void push_back(char ch);

		iterator begin();
		iterator end();
		const_iterator begin() const;
		const_iterator end() const;
		string& operator+=(char ch);
		string& operator+=(char* str);
		char& operator[](size_t pos);
		const char& operator[](size_t pos) const;
		void clear();
		void insert(size_t pos, const char* str);
		void erase(size_t pos, size_t len = npos);
	private:
		size_t __capacity;
		size_t __size;
		char* __str;
	public:
		const static size_t npos;
	};
	ostream& operator<<(ostream& out, const string& s);
	istream& operator >> (istream& in, string& s);
}

//istream& operator>>(my_string::string::istream& _cin, my_string::string& s);
//ostream& operator<<(my_string::string::ostream& _cout, const my_string::string& s);

mystring.cpp

#include "myString.h"
const size_t my_string::string::npos = -1;

my_string::string::string(const char* str)
	:__capacity(strlen(str))
	,__size(__capacity)
{
	__str = new char[__capacity + 1];
	strcpy(__str, str);
}

my_string::string::string(const string& s)
{
	string tmp(s.__str);
	swap(tmp);
}

my_string::string& my_string::string::operator=(const string& s)
{
	string tmp(s);
	swap(tmp);
	return *this;
}

void my_string::string::swap(string& s)
{
	std::swap(__str, s.__str);
	std::swap(__capacity, s.__capacity);
	std::swap(__size, s.__size);
}
size_t my_string::string::capaccite()
{
	return __capacity;
}
size_t my_string::string::szie()
{
	return __size;
}
char* my_string::string::c_str()
{
	return __str;
}

my_string::string::~string()
{
	delete[] __str;
}

void my_string::string::reserve(size_t n)
{
	if (n <= __capacity) return;
	if (n > __capacity)
	{
		char* new_str = new char[n + 1];
		if (__str)
		{
			strcpy(new_str, __str);
		}
		else 
		{
			new_str[0] = '\0';
		}
		delete[] __str;
		__str = new_str;
		__capacity = n;

	}
}
void my_string::string::resize(size_t n, char c)
{
	if (n <= __capacity) {
		__str[n] = '\0';
		__size = n;
	}
	else {
		reserve(n);
		while(__size < n)
		{
			__str[__size++] = c;
		}
		__str[__size] = '\0';
	}
}

void my_string::string::push_back(char ch)
{
	if (__size >= __capacity)
	{
		__capacity = __capacity == 0 ? 4 : __capacity * 2;
		reserve(__capacity);
	}
	__str[__size++] = ch;
	__str[__size] = '\0';
}

my_string::string::iterator my_string::string::begin()
{
	return __str;
}
my_string::string::iterator my_string::string::end()
{
	return __str + __size;
}

my_string::string::const_iterator my_string::string::begin() const
{
	return __str;
}
my_string::string::const_iterator my_string::string::end() const
{
	return __str + __size;
}
char& my_string::string::operator[](size_t pos)
{
	return __str[pos];
}

const char& my_string::string::operator[](size_t pos) const
{
	return __str[pos];
}

size_t my_string::string::find(char ch, size_t pos)
{
	while (__size > pos)
	{
		if (__str[pos] == ch)
		{
			return pos;
		}
		pos++;
	}
	return npos;
}

size_t my_string::string::find(char* str, size_t pos)
{
	const char* p = strstr(__str + pos, str);
	if (p)
	{
		return p - __str;
	}
	return  npos;
}

void my_string::string::clear()
{
	__str[0] = '\0';
	__size = 0;
}

void my_string::string::append(const char* str)
{
	size_t len = strlen(str);
	if (__size + len > __capacity)
	{
		reserve(__size + len);
	}
	strcpy(__str + __size, str);
	__size += len;
}

my_string::string& my_string::string::operator+=(const char ch)
{
	push_back(ch);
	return *this;
}
my_string::string& my_string::string::operator+=(const char* str)
{
	append(str);
	return *this;
}

void my_string::string::insert(size_t pos, char ch)
{
	if (pos <= __size) return;

	if (__size == __capacity)
	{
		reserve(__capacity == 0 ? 4 : __capacity * 2);
	}
	size_t end = __size + 1;
	while (end > pos)
	{
		__str[end] = __str[end + 1];
		--end;
	}
	__str[pos] = ch;
	__size++;

}

void my_string::string::insert(size_t pos, const char* str)
{
	if(pos <= __size) return;

	size_t len = strlen(str);
	if (__size + len > __capacity)
	{
		reserve(__size + len);
	}

	// 挪动数据
	int end = __size;
	while (end >= (int)pos)
	{
		__str[end + len] = __str[end];
		--end;
	}

	strncpy(__str + pos, str, len);
	__size += len;
}

void my_string::string::erase(size_t pos, size_t len)
{
	if(pos < __size) return;

	if (len == npos || pos + len >= __size)
	{
		__str[pos] = '\0';
		__size = pos;
	}
	else
	{
		size_t begin = pos + len;
		while (begin <= __size)
		{
			__str[begin - len] = __str[begin];
			++begin;
		}
		__size -= len;
	}
}
ostream& operator<<(ostream& out, const my_string::string& s)
{
	for (auto ch : s)
	{
		out << ch;
	}
	return out;
}

istream& operator >> (istream& in, my_string::string& s)
{
	s.clear();
	char buff[129] = { 0 };
	size_t i = 0;
	char ch = in.get();
	while (ch != ' ' && ch != '\n')
	{
		buff[i++] = ch;
		if (i == 128)
		{
			buff[i] = '\0';
			s += buff;
			i = 0;
		}
		ch = in.get();
	}

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

int main(){

	my_string::string s("str");
	s += "string";
	for (auto str : s)
	{
		std::cout << str << " ";
	}
	std::cout << std::endl;

	const my_string::string s1 = s;
	for (const auto str : s1)
	{
		std::cout << str << " ";
	}
	std::cout << std::endl;

	my_string::string s2(s);
	for (auto str : s2)
	{
		std::cout << str << " ";
	}
	std::cout << std::endl;

	
	return 0;
}

http://www.dtcms.com/a/30863.html

相关文章:

  • Apache Spark 的主要特点
  • 工厂车辆排队系统
  • 关于解决springcloud 创建bean失败的问题
  • 【python】解析自动化脚本文件并按照=测试周期=存储记录
  • react hook useReducer
  • 如何解决服务器被黑客爬虫攻击:全面防护与优化策略
  • Android TabLayout 实现随意控制item之间的间距
  • rk3588/3576板端编译程序无法运行视频推理
  • vue-element-admin 打包部署到SpringBoot
  • Linux Python 调试/堵塞/性能分析与定位工具
  • 【Cesium学习(十三)】Cesium学习主要优秀资源资料总结
  • python用 PythonNet 从 Python 调用 WPF 类库 UI 用XAML
  • 支持向量机 (Support Vector Machine, SVM)
  • ProfiNet转EtherNet/IP罗克韦尔PLC与监控系统通讯案例
  • hydra docker版本
  • 云原生监控体系建设:Kubernetes架构下的全面监控策略
  • DeepSeek R1本地Linux服务器Docker部署<实现网页访问/本地终端访问>完整教程
  • vxe-grid 通过配置式给单元格字段格式化树结构数据,转换树结构节点
  • CentOS7设置静态IP
  • 细分数字货币钱包的不同种类
  • CSS文本属性
  • 网工项目实践2.4 北京公司安全加固、服务需求分析及方案制定
  • CSS基础(浮动、相对定位、绝对定位、固定定位、粘性定位、版心、重置默认样式)
  • 22爬虫:使用Drission Page的两个案例
  • 网络安全高级软件编程技术
  • Java八股文(下)
  • Mac安装配置Tomcat 8
  • C++栈与队列:数据结构的“单行道”与“流水线
  • QML Component 与 Loader 结合动态加载组件
  • ES6相关操作