学习笔记—C++—string(一)

news2025/7/18 17:27:33

目录

string

为什么学习string的类

string类的常用接口

string类对象的常见构造

string类对象的访问及遍历操作

operator[]

迭代器

范围for

auto

迭代器(二)

string类对象的容量操作

size,length,max_size,capacity,clear基本用法

reserve 提前开空间,避免扩容的操作

resize

string类对象的修改操作

push_back尾插一个字符

append

operator+=

insert

erase

replace

c_str

rfind

find_first_of

find_last_not_off

substr

to_string

string类非成员函数

getline

总结


string

为什么学习string的类

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

● 在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数

● string是一个管理字符数组的类

string类的常用接口

string类对象的常见构造

string::string - C++ Reference

int main()
{
	string s1;
	string s2("1111122222");       
	string s3("111111111111", 3);    //前三个拷贝
	string s4(100, 'x');             //拷贝100个x初始化
	string s5(s2, 4, 3);             //拷贝第四个字符起后三个字符
	string s6(s2, 4);                //拷贝第四个字符后所以的字符,直到结束

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
	cout << s6 << endl;

	//s2.operator[](0) = 'x';
	s2[0] = 'x';                     //修改第零个位置的字符为x
	s2[5] = 'x';                     //修改第五个位置的字符为x
	cout << s2 << endl;

	//让s2里的所以字符++
	for (size_t i = 0; i < s2.size(); i++)
	{
		s2[i]++;
	}
	cout << s2 << endl;

	return 0;
}

string类对象的访问及遍历操作

operator[]

结构

class string
{
public:
	char& operator[](size_t pos)
	{
		assert(pos < _size);
	}
private:
	char* _str;
	size_t _size;
	size_t _capacity;
};

使用operator[]进行数组元素的遍历操作

int main()
{
	//operator[]可以访问数组的第pos位置的元素,越界就会直接报错的
	string s1("hello world");

	for (size_t i = 0; i < s1.size(); i++)
	{
		cout << s1[i];//直接访问第i个位置的字符
	}

	return 0;
}

迭代器

通过迭代器进行遍历的实现操作,迭代器可以理解为像指针一样的东西。

int main()
{
	string s1("hello world");

	//string::iterator it1 = s1.begin();//用这个类型定义一个对象
	//我们这里的话begin访问的是h这个字符,end指向的是\0
	//这里将begin给到了it1

    it1 = s1.begin();
	while (it1 != s1.end())//end是最后一个数据的下一个位置
	{
		//下面的用法非常像指针,但是不是指针
		cout << *it1 << " ";
		++it1;
	}

	return 0;
}
//这个s1是一个类对象,然后我们利用这个string类里面的运算符

日常的通过下标[]访问很方便,但是这个不是通用的访问方式,这个只适合string和vector结构,不适合后面的结构,string和vector结构底层是连续的空间,才回去重载operator[]。

下标+[]不是通用的方式,但是迭代器是所有容器通用的方式。

列表的遍历

int main()
{
  list <int> lt;//创建一个模版对象lt
  //然后进行数据的插入操作
  lt.push_back(1);
  lt.push_back(2);
  lt.push_back(3);
  lt.push_back(4);

  //列表
  list <int>::iterator it =lt.begin();
  while (it != lt.end())
  {
	  cout << *it << " ";
	  ++it ;
  }

  return 0;
}
范围for

范围for进行遍历

	// 范围for C++11 语法糖
  // 适用于容器遍历和数组遍历
	// 自动取容器的数据赋值给左边的对象
	// 自动++,自动判断结束
	// 原理:范围for底层是迭代器
	//for (char ch : s1)
  //auto可以代替类型
	for (auto ch : s1)
	{
		cout << ch << " ";
	}
	cout << endl;

     // 修改
	for (auto& ch : s1)
	{
		ch++;
	}

	for (auto ch : s1)
	{
		cout << ch << " ";
	}
	cout << endl;

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

String而言有三种遍历方式:下标+[],迭代器,范围for。

范围for用于容器遍历和数组遍历。

因为迭代器底层根指针相似,所以范围for也可以遍历数组。

auto

	int i = 1;
	int y = i;
	//自动推导类型
	auto z = y;     //int
	auto x = 1.1;   //double
	auto n = &i;    //int*
	int& r1 = i;
	auto r2 = r1;   //int
	auto& r3 = r1;  //int&
	//list<int>::iterator it = It.begin();
	auto it = It.begin();
	while (it != It.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	//auto语法糖
	// 简化代码,替代写起来长的类型
	std::map<std::string, std::string> dict;
	//std::map<std::string, std::string>::iterator dit = dict.begin();
	auto dit = dict.begin();

auto真正的价值是为了方便,简化代码,替换长类型,写起来长的类型。

auto当前是不能作为形参的,C++20开始支持auto作参数,auto可以支持作为返回值的,谨慎使用。

// C++20开始支持
void func1(auto x);

auto func3()
{
	auto y = func4();
	return y;
}

auto func2()
{
	auto x = func3();
	//...
	return x;
}

整理代码

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

//int main()
//{
//	string s1("hello,word");
//
//	//下标[]+
//	for (size_t i = 0; i < s1.size(); i++)
//	{
//		s1[i]++;
//	}
//
//	for (size_t i = 0; i < s1.size(); i++)
//	{
//		cout<<s1[i]<<" ";
//	}
//	cout << endl;
//
//	//迭代器
//	string::iterator it1 = s1.begin();
//	while (it1 != s1.end())
//	{
//		(*it1)--;
//		++it1;
//	}
//	cout << endl;
//
//	it1 = s1.begin();
//	while (it1 != s1.end())
//	{
//		cout << *it1 << " ";
//		++it1;
//	}
//	cout << endl;
//
//	list<int> It;
//	It.push_back(1);
//	It.push_back(2);
//	It.push_back(3);
//	It.push_back(4);
//
//	//list<int>::iterator it = It.begin();
//	auto it = It.begin();
//	while (it != It.end())
//	{
//		cout << *it << " ";
//		++it;
//	}
//	cout << endl;
//
//
//	//auto语法糖
//	// 简化代码,替代写起来长的类型
//	std::map<std::string, std::string> dict;
//	//std::map<std::string, std::string>::iterator dit = dict.begin();
//	auto dit = dict.begin();
//
//	// 范围for C++11 语法糖
//  // 适用于容器遍历和数组遍历
//	// 自动取容器的数据赋值给左边的对象
//	// 自动++,自动判断结束
//	// 原理:范围for底层是迭代器
//	//for (char ch : s1)
//  //auto可以代替类型
//	for (auto ch : s1)
//	{
//		cout << ch << " ";
//	}
//	cout << endl;
//
//     // 修改
//	for (auto& ch : s1)
//	{
//		ch++;
//	}
//
//	for (auto ch : s1)
//	{
//		cout << ch << " ";
//	}
//	cout << endl;
//
//	for (auto e : It)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//
//	int i = 1;
//	int y = i;
//	//自动推导类型
//	auto z = y;     //int
//	auto x = 1.1;   //double
//	auto n = &i;    //int*
//	int& r1 = i;
//	auto r2 = r1;   //int
//	auto& r3 = r1;  //int&
//
//	int a[] = { 1,2,3,4,5,6 };
//	for (size_t i = 0; i < sizeof(a)/sizeof(int); i++)
//	{
//		cout << a[i] << " ";
//	}
//	cout << endl;
//	
//	for (auto e : a)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//
//	return 0;
//}

 C++20开始支持
//void func1(auto x);
//
//auto func3()
//{
//	auto y = func4();
//	return y;
//}
//
//auto func2()
//{
//	auto x = func3();
//	//...
//	return x;
//}

迭代器(二)

反向迭代器

Const 无法调用迭代器

这种方法const就能使用迭代器,但不能修改

const反向迭代器

int main()
{
	string s1("hello world");
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit << " ";
		++rit; 
	}
	cout << endl;

	const string s2(s1);
	//string::const_iterator it1 = s2.begin();
	auto it1 = s2.begin();
	while (it1 != s2.end())
	{
		//*it1 += 1;
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;

	//string::const_reverse_iterator rit1 = s2.rbegin();
	auto rit1 = s2.rbegin();
	while (rit1 != s2.rend())
	{
		cout << *rit1 << " ";
		++rit1;
	}
	cout << endl;

	return 0;
}

string类对象的容量操作

注意:

1. size()length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接

口保持一致,一般情况下基本都是用size()

2. clear()只是将string中有效字符清空,不改变底层空间大小。

3. resize(size_t n) resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不

同的是当字符个数增多时:resize(n)0来填充多出的元素空间,resize(size_t n, char

c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数

增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。

4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参

数小于string的底层空间总大小时,reserver不会改变容量大小。

size,length,max_size,capacity,clear基本用法

int main()
{
	string s1("hello world");
  //size和length结果是一样的
	cout << s1.size() << endl;
	cout << s1.length() << endl;
  //看最大开辟空间,无意义
	cout << s1.max_size() << endl;
  //空间大小
	cout << s1.capacity() << endl;
	cout << endl << endl;

  //清除空间,让size变成0
	s1.clear();
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	return 0;
}

reserve 提前开空间,避免扩容的操作

// reserve  保留 预留
// reverse  反向 翻转
int main()
{
	string s1;
	// 提前开空间,避免扩容
	s1.reserve(200);

	size_t old = s1.capacity();
	cout << "capacity:" << old << endl;
	for (size_t i = 0; i < 200; i++)
	{
		s1 += 'x';
		if (s1.capacity() != old)
		{
			cout << "capacity:" << s1.capacity() << endl;
			old = s1.capacity();
		}
	}

	string s3("11111111");
	string s4("111111112222222222222222222222222222222222222222222");
	cout << sizeof(s3) << endl;

	return 0;
}

resize

int main()
{
	string s1("11111111111111111111");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	//删除
	//<size
	s1.resize(15);
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	//插入
	//size<  <capacity
	//把空间扩容到25,并把后面空间全部插入x; s1.resize(25)如果是这样,那么插入\0
	s1.resize(25,'x');
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;

	//<capacity
	//扩容到40,并插入x
	s1.resize(40,'x');
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	return 0;
}

string类对象的修改操作

push_back尾插一个字符

int main()
{
	string s1("hello world");
    //尾插字符
	s1.push_back(',');
	s1.push_back('x');
	cout << s1 << endl;

	return 0;
}

append

​
//int main()
//{
//
//  //尾插字符串
//  //插入字符串
//	s1.append("orld");
//	cout << s1 << endl;
//
//  //插入十个感叹号
//	s1.append(10, '!');
//	cout << s1 << endl;
//
//  //插入函数
//	string s2("hello,wuguo");
//	s1.append(s2.begin(), s2.end());
//	cout << s1 << endl;
// 
//  //插入第六个函数之后的字母
//  string s3("hello,wuguo");
//	s1.append(s2.begin()+6, s2.end());
//	cout << s1 << endl;
// 
//	return 0;
//}

​

operator+=

//  //直接+=,唯一真神
//	string s4("hello");
//	s4 += ',';
//	s4 += "world";
//	cout << s4 << endl;

insert

​//int main()
//{
//  //Insert相当于插入
//	string s1("hello,world");
//  //后面的数据就是往后面进行挪动的
//	s1.insert(5, "xxxxx");
//	cout << s1 << endl;
//
//	return 0;
//}

​

​

erase

相当于删除

replace

//int main()
//{
//  //replace相当于替换
//	string s1("hello,world");
//	cout << s1 << endl;
//	s1.replace(5, 1, "%%");
//	cout << s1 << endl;
//
//	return 0;
//}

加上find就能把空格也能替换了

find的默认位置是从0开始找的,我们给什么值就从什么位置开始找。

c_str

rfind

int main()
{
	string s3("test.cpp");
	//现在我们想将后缀取出来
	//那么我们后缀的特征就是前面有一个点,以点进行区分操作
	//那么这个时候就可以使用rfind了
	size_t pos = s3.rfind('.');
	if (pos != string::npos)//找到的话
	{
		//这个时候我们就找到位置了,那么我们就要利用substr这个从pos位置开始取子串
		string sub = s3.substr(pos);//从pos位置开始取;
		cout << sub << endl;
	}
}

find就是正向找,rfind就是倒着找。

find_first_of

//	std::string str("Please, replace the vowels in this sentence by asterisks.");
//	std::size_t found = str.find_first_of("aeiou");
//	while (found != std::string::npos)
//	{
//		str[found] = '*';
//		found = str.find_first_of("aeiou", found + 1);
//	}
//	
//	std::cout << str << '\n';
//
//	return 0;
//}

只要你这个字符串里面有我给的这个字符串里面任意一个字符的话,我们就将这个字符变成*。

find_last_not_off

int main()
{
    std::string str("Please, replace the vowels in this sentence by asterisks.");
    cout << str << endl;
    std::size_t found = str.find_first_not_of("aeiou");
    while (found != std::string::npos)
    {
        str[found] = '*';
        found = str.find_first_not_of("aeiou", found + 1);
    }

    std::cout << str << '\n';

    return 0;
}

保留元音字母,其他字母全部屏蔽掉,只有aeiou留下来了。

substr

从pos位置取len个字符,然后将这几个衣服构成资格子串string

//	string s3("test.cpp.zip");
//	size_t pos = s3.rfind('.');
//	if (pos != string::npos)
//	{
//		string sub = s3.substr(pos);
//		cout << sub << endl;
//	}

to_string

将数据转换为字符串

//int main()
//{
//    string s3 = to_string(11.11);
//
//    string s1, s2;
//    cin >> s1 >> s2;
//    cout << s1 << endl;
//    cout << s2 << endl;
//
//    return 0;
//}

string类非成员函数

getline

遇到#号才停止

总结

常用的:构造、迭代器、容量里面的几个。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2341396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GPLT-2025年第十届团体程序设计天梯赛总决赛题解(共计266分)

今天偶然发现天梯赛的代码还保存着&#xff0c;于是决定写下这篇题解&#xff0c;也算是复盘一下了 L1本来是打算写的稳妥点&#xff0c;最后在L1-6又想省时间&#xff0c;又忘记了insert&#xff0c;replace这些方法怎么用&#xff0c;也不想花时间写一个文件测试&#xff0c…

MySQL数据库精研之旅第十期:打造高效联合查询的实战宝典(一)

专栏&#xff1a;MySQL数据库成长记 个人主页&#xff1a;手握风云 目录 一、简介 1.1. 为什么要使用联合查询 1.2. 多表联合查询时的计算 1.3. 示例 二、内连接 2.1. 语法 2.2. 示例 三、外连接 4.1. 语法 4.2. 示例 一、简介 1.1. 为什么要使用联合查询 一次查询需…

15.FineReport动态展示需要的列

1.首先连接自带的sqlite数据库&#xff0c;具体方法参考下面的链接 点击查看连接sqlite数据库 2.文件 – 新建普通报表 3.新建数据库查询 4.查询自带的销售明细表 5.把数据添加到格子中&#xff0c;并设置边框颜色等格式 6.查询新的数据集&#xff1a;column 7.点笔 8.全部添…

Windows云主机远程连接提示“出现了内部错误”

今天有人反馈说有个服务器突然连不上了&#xff0c;让我看下什么问题&#xff0c;我根据他给的账号密码试了下发现提示“出现了内部错误”&#xff0c;然后就是一通排查 先是查看安全组&#xff0c;没发现特别的问题&#xff0c;因为也没有调过这块的配置 然后通过控制台登录进…

最新扣子(Coze)案例教程:Excel数据生成统计图表,自动清洗数据+转换可视化图表+零代码,完全免费教程

大家好&#xff0c;我是斜杠君。 知识星球群有同学和我说每天的工作涉及很多数据表的重复操作&#xff0c;想学习Excel数据表通过大模型自动转数据图片的功能。 今天斜杠君就带大家一起搭建一个智能体&#xff0c;以一个销售行业数据为例&#xff0c;可以快速实现自动清洗Exc…

如何安装Visio(win10)

首先下载下面这些文件 HomeStudent2021Retail.img officedeploymenttool_17531-20046.exe office中文语言包.exe 确保这些文件都在一个文件夹内&#xff08;我已经上传这些资源&#xff0c;这些资源都是官网下载的&#xff09; 官网资源下载教程 1.下载Office镜像&#xff0…

建筑安全员 A 证与 C 证:差异决定职业方向

在建筑行业的职业发展道路上&#xff0c;安全员 A 证和 C 证就像两条不同的岔路&#xff0c;它们之间的差异&#xff0c;在很大程度上决定了从业者的职业方向。 从证书性质和用途来看&#xff0c;A 证是从业资格证书&#xff0c;更像是一把开启安全管理高层岗位的 “金钥匙”。…

(19)VTK C++开发示例 --- 分隔文本读取器

文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;VTK开发 &#x1f448; 1. 概述 本例采用坐标和法线&#xff08;x y z nx ny nz&#xff09;的纯文本文件&#xff0c;并将它们读入vtkPolyData并显示…

Redis从入门到实战先导篇

前言&#xff1a;本节内容包括虚拟机VMware的安装&#xff0c;Linux系统的配置&#xff0c;FinalShell的下载与配置&#xff0c;Redis与其桌面客户端的安装指导,便于后续黑马Redis从入门到实战的课程学习 目录 主要内容 0.相关资源 1.VMware安装 2.Linux与CentOS安装 3.Fi…

JavaScript 防抖和节流

方法一&#xff1a;使用lodash库的debounce方法 方法二&#xff1a;手写防抖函数 function debounce(fn,t){// 1.声明一个定时器变量 因为需要多次赋值 使用let声明let timer // 返回一个匿名函数return function(){if(timer){// 如果定时器存在清除之前的定时器 clearTimeout(…

Spring Boot 启动时 `converting PropertySource ... to ...` 日志详解

Spring Boot 启动时 converting PropertySource ... to ... 日志详解 1. 日志背景 在 Spring Boot 应用启动过程中&#xff0c;会加载并处理多种 配置源&#xff08;如 application.properties、系统环境变量、命令行参数等&#xff09;。这些配置源会被封装为 PropertySource…

分割数据集中.json格式标签转化成伪彩图图像

一、前言 图像分割任务中&#xff0c;分割数据集的转换和表示方式对于模型训练至关重要。目前主要有两种常见的分割结果表示方法&#xff1a; 1. 转化为TXT文件 这种方式通常使用一系列的点&#xff08;坐标&#xff09;来表示图像中每个像素的类别标签。每个点通常包含像素…

Linux之彻底掌握防火墙-----安全管理详解

—— 小 峰 编 程 目录&#xff1a; 一、防火墙作用 二、防火墙分类 1、逻辑上划分&#xff1a;大体分为 主机防火墙 和 网络防火墙 2、物理上划分&#xff1a; 硬件防火墙 和 软件防火墙 三、硬件防火墙 四、软件防火墙 五、iptables 1、iptables的介绍 2、netfilter/…

# 构建和训练一个简单的CBOW词嵌入模型

构建和训练一个简单的CBOW词嵌入模型 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;词嵌入是一种将词汇映射到连续向量空间的技术&#xff0c;这些向量能够捕捉词汇之间的语义关系。在这篇文章中&#xff0c;我们将构建和训练一个简单的Continuous Bag of Words…

Collection集合,List集合,set集合,Map集合

文章目录 集合框架认识集合集合体系结构Collection的功能常用功能三种遍历方式三种遍历方式的区别 List集合List的特点、特有功能ArrayList底层原理LinkedList底层原理LinkedList的应用场list:电影信息管理模块案例 Set集合set集合使用哈希值红黑树HashSet底层原理HashSet集合元…

使用DDR4控制器实现多通道数据读写(九)

一、本章概括 在上一节中&#xff0c;我们概括了工程的整体思路&#xff0c;并提供了工程框架&#xff0c;给出了读写DDR4寄存器的接口列表和重点时序图。当然&#xff0c;对于将DDR4内存封装成FIFO接口&#xff0c;其中的重点在于对于读写DDR4内存地址的控制&#xff0c;相对于…

深度解析n8n全自动AI视频生成与发布工作流

工作流模版地址&#xff1a;Fully Automated AI Video Generation & Multi-Platform Publishing | n8n workflow template 本文将全面剖析基于n8n平台的这个"全自动AI视频生成与多平台发布"工作流的技术架构、实现原理和关键节点&#xff0c;帮助开发者深入理解…

pycharm调试typescript

前言 搜索引擎搜索调试typescript&#xff0c;都是vscode&#xff0c;但是没看懂。 vscode界面简洁&#xff0c;但是适配起来用不习惯&#xff0c;还是喜欢用pycharm。 安装软件 安装Node.js https://nodejs.org/zh-cn 判断是否安装成功 node -v npm install -g typescrip…

spring-ai之Advisors API

1、 Spring AI Advisors API 提供了一种灵活而强大的方法来拦截、 修改和增强 Spring 应用程序中的 AI 驱动的交互。 通过利用 Advisors API&#xff0c;开发人员可以创建更复杂、可重用和可维护的 AI 组件。主要优势包括封装重复的生成式 AI 模式、转换发送到大型语言模型 &…

JVM 系列:JVM 内存结构深度解析

你点赞了吗&#xff1f;你关注了吗&#xff1f;每天分享干货好文。 高并发解决方案与架构设计。 海量数据存储和性能优化。 通用框架/组件设计与封装。 如何设计合适的技术架构&#xff1f; 如何成功转型架构设计与技术管理&#xff1f; 在竞争激烈的大环境下&#xff0c…