C++string类

目录

一、为什么学习string

二、标准库中的string类

2.1 string类的简介

2.2 成员类型

2.3 成员函数

2.3.1 构造、析构与运算符重载      

2.3.2 迭代器

2.3.3 容量

2.3.4 元素的存取        

2.3.5 修改

2.3.6 字符串操作

2.4 成员常量

2.5 非成员函数重载

三、string编程题练习

1. 仅仅反转字母        

2. 字符串最后一个单词的长度

3. 字符串相加        

4. 验证回文串

四、string类的模拟实现



一、为什么学习string

        string的诞生略早于STL(STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架),与STL里面的vector、list相比存在一些不成熟的地方。string与STL里面的vector、list具有相似之处,但是string是被包含在标准库中的。在接下来的学习过程中,我们务必需要阅读一些文档,可能需要一点点英语的基础(尽量不去使用翻译,因为翻译不一定能精确地表达出原意,理解的些许偏差可能对你的学习产生不好的影响,遇到陌生的单词搜索一下它的中文意思即可)

string - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/string/string/?kw=string        C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP(面向对象编程)的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。学习string可以更好地对字符串整体进行操作,而不是像C语言那样对字符串的字符进行操作。


二、标准库中的string类

注意:2.1 ~ 2.5 中并不会详细介绍每一个函数,仅介绍部分常用函数的常规用法(并且以代码运行的截图搭配文字说明展现出来),具体的内容请以文档为准,希望大家能够通过阅读文档学到需要的知识并提升自己相应的能力

2.1 string类的简介

        

2.2 成员类型

        

2.3 成员函数

2.3.1 构造、析构与运算符重载      

        

        

2.3.2 迭代器

        

        

        

        

2.3.3 容量

        

        

        

        

         

2.3.4 元素的存取        

        

2.3.5 修改

        

        

        

2.3.6 字符串操作

        

        

2.4 成员常量

        

2.5 非成员函数重载

        

        string设计了近百个函数,相对有些冗余,学习的时候掌握一些常用的函数(你在学习或者刷题的时候经常遇到的),其它的在需要的时候查看文档即可


三、string编程题练习

1. 仅仅反转字母        

917. 仅仅反转字母 - 力扣(LeetCode)        

给你一个字符串 s ,根据下述规则反转字符串:

  • 所有非英文字母保留在原有位置。
  • 所有英文字母(小写或大写)位置反转。

返回反转后的 s 。

class Solution {
public:
    bool isLetter(char ch)
    {
        if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
            return true;
        else
            return false;
    }
    // 注意isalpha()用于判断字符而不是字母
    string reverseOnlyLetters(string s) 
    {
        int begin = 0, end = s.size() - 1;
        while(begin < end)
        {
            // 注意:缺少判断条件 begin < end 会出现问题
            while(begin < end && !isLetter(s[begin]))
            {
                begin++;
            }
            while(begin < end && !isLetter(s[end]))
            {
                end--;
            }
            swap(s[begin], s[end]);
            begin++, end--;    // 
        }
        return s;
    }
};

2. 字符串最后一个单词的长度

字符串最后一个单词的长度_牛客题霸_牛客网 (nowcoder.com)        

描述

计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾)

输入描述:

输入一行,代表要计算的字符串,非空,长度小于5000。

输出描述:

输出一个整数,表示输入字符串最后一个单词的长度。

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

int main() {
    string str = "";
    // cin >> str;
    // cin 默认 空格&换行 终止读取
    // 使用 getline() 控制读取的结束条件
    getline(cin, str);
	size_t i = str.rfind(' ');
    if(i != string::npos)
	{
        cout << str.size() - (i+1) << endl;
    }
    else 
    {
        cout << str.size() << endl;
    }
    return 0;
}

//我们也可以利用cin 默认 空格&换行 终止读取 写出更简约的代码

int main()
{
    string str = "";
    while(cin >> str)
    {}
    cout << str.size();
}

3. 字符串相加        

415. 字符串相加 - 力扣(LeetCode)        

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

class Solution {
public:
    string addStrings(string num1, string num2) 
    {
        string ans = "";
        int end1 = num1.size()-1, end2 = num2.size()-1;
        int next = 0; // 进位
        // 注意:while(end1 >= 0 && end2 >= 0) 无法处理连续进位的情况(999999+11)
        while(end1 >= 0 || end2 >= 0)
        {
            int x1 = end1 >= 0 ? num1[end1] - '0' : 0;
            int x2 = end2 >= 0 ? num2[end2] - '0' : 0;
            int ret = x1 + x2 + next;
            next = ret / 10;
            ret %= 10;
            ans += (ret + '0');
            end1--, end2--;
        }
        if(next == 1) 
            ans += '1';
        reverse(ans.begin(), ans.end());
        return ans;
    }
};
// 效率:尾插 + 逆置 > 头插

4. 验证回文串

125. 验证回文串 - 力扣(LeetCode)        

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 

class Solution {
public:
    bool isPalindrome(string s)
    {
        string s1;
        auto it = s.begin();
        while (it != s.end())
        {
            if (*it >= 'A' && *it <= 'Z')
                s1 += (*it + 32);
            if (*it >= 'a' && *it <= 'z')
                s1 += *it;
            if(*it >= '0' && *it <= '9')
                s1 += *it;
            ++it;
        }cout << s1 << endl;
        string rs1;
        auto rit = s1.rbegin();
        while (rit != s1.rend())
        {
            rs1 += *rit;
            ++rit;
        }cout << rs1 << endl;
        if (s1 == rs1)
            return true;
        return false;
    }
};

        


四、string类的模拟实现

注意:本文string类的模拟实现并不够专业标准,仅供初学者连续参考   

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

namespace mystring
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;
        
        // 迭代器
		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}
        
        // 全缺省构造函数
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		/*string(const string& s)
		{
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}*/
		
		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)
			, _size(0)
			, _capacity(0)
		{
			string tmp(s._str);
			swap(tmp);
		}

		// operator=

		/*string& operator=(const string& s)
		{
			if (&s != this)
			{
				char* tmp = new char[s._capacity + 1];
				strcpy(tmp, s._str);
				delete[] _str;

				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}*/

		/*string& operator=(const string& s)
		{
			if (this != &s)
			{
				string tmp(s);
				//this->swap(tmp);
				swap(tmp);
			}
			return *this;
		}*/

		string& operator=(string tmp)
		{
			swap(tmp);

			return *this;
		}

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

		char& operator[](size_t pos)
		{
			assert(pos < _size);

			return _str[pos];
		}

		const char& operator[](size_t pos) const
		{
			assert(pos < _size);

			return _str[pos];
		}

		size_t capacity() const
		{
			return _capacity;
		}

		size_t size() const
		{
			return _size;
		}

		const char* c_str() const
		{
			return _str;
		}

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

		bool empty()const
		{
			return _str == nullptr;
		}

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

				_capacity = n;
			}
		}

		void resize(size_t n, char ch = '\0') {
			if (n < _size) {
				_str[n] = '\0';
				_size = n;
			}
			else {
				if (n > _capacity) {
					reserve(n);
				}
				for (size_t i = _size; i < n; i++) {
					_str[i] = ch;

				}
				_str[n] = '\0';
				_size = n;
			}

		}

		void push_back(char ch)
		{
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}

			_str[_size++] = ch;
			_str[_size] = '\0';
		}

		void append(const char* str)
		{
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}

			strcpy(_str + _size, str);
			_size += len;
		}

		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

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

		// insert(0, 'x')
		void insert(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			// 类型提升会导致 -1 > 0
			//size_t end = _size;
			//while (end >= pos)		
			//{
			//	_str[end + 1] = _str[end];
			//	--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++;
		}

		void insert(size_t pos, const char* str)
		{
			assert(pos <= _size);
			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;
		}
		
		string& insert_s(size_t pos, char ch)
		{
			assert(pos <= _size);
			if (_size == _capacity)
			{
				reserve(_capacity == 0 ? 4 : _capacity * 2);
			}
			char* end = _str + _size;
			while (end >= _str + pos)
			{
				*(end + 1) = *end;
				--end;
			}
			_str[pos] = ch;
			_size++;
			return *this;
		}

		string& insert_s(size_t pos, const char* str)
		{
			assert(pos <= _size);
			size_t len = strlen(str);
			if (_size + len > _capacity)
			{
				reserve(_size + len);
			}
			char* end = _str + _size;
			while (end >= _str + pos)
			{
				*(end + len) = *end;
				--end;
			}
			strncpy(_str + pos, str, len);
			_size += len;
			return *this;
		}
        
        void erase(size_t pos, size_t len = npos)
		{
			assert(pos <= _size);
			if (len == npos || pos + len >= _size)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				size_t begin = pos + len;
				while (begin <= _size)
				{
					_str[pos] = _str[begin];
					pos++, begin++;
				}
				_size -= len;
			}
		}

		string& erase_s(size_t pos, size_t len = npos)
		{
			assert(pos < _size);
			size_t left = _size - pos;
			if (len >= left)
			{
				_str[pos] = '\0';
				_size = pos;
			}
			else
			{
				strcpy(_str + pos, _str + pos + len);
				_size -= len;
			}
			return *this;
		}

		bool operator<(const string& s) const
		{
			return strcmp(_str, s._str) < 0;
		}
		bool operator==(const string& s) const
		{
			return strcmp(_str, s._str) == 0;
		}
		bool operator<=(const string& s) const
		{
			return *this < s || *this == s;
		}
		bool operator>(const string& s) const
		{
			return !(*this <= s);
		}
		bool operator>=(const string& s) const
		{
			return !(*this < s);
		}
		bool operator!=(const string& s) const
		{
			return !(*this == s);
		}

		// 返回字符ch在string中第一次出现的位置
		size_t find(char ch, size_t pos = 0)
		{
			for (size_t i = pos; i < _size; i++)
			{
				if (_str[i] == ch)
				{
					return i;
				}
			}
			return npos;
		}
		// 返回子串s在string中第一次出现的位置
		size_t find(const char* s, size_t pos = 0)
		{
			const char* ret = strstr(_str + pos, s);
			if (ret == nullptr)
			{
				return npos;
			}
			else
			{
				return ret - _str;
			}
		}

		string substr(size_t pos, size_t len = npos)
		{
			string s;
			size_t end = pos + len;
			if (len == npos || pos + len >= _size)
			{
				len = _size - pos;
				end = _size;
			}
			s.reserve(len);
			for (size_t i = pos; i < pos + len; i++)
			{
				s += _str[i];
			}
			return s;
		}
	private:
		char* _str;
		size_t _size;
		size_t _capacity;

		//static size_t npos;
	public:
        const static size_t npos;
		//const static size_t npos = -1;	// 特例(static 修饰的变量不能在此处初始化)
	};									    // const static 修饰的整型变量除外
	//size_t string::npos = -1;
	const  size_t string::npos = -1;

	ostream& operator<<(ostream& out, const string& s)
	{
		for (auto ch : s)
			out << ch;

		return out;
	}

	istream& operator>>(istream& in, string& s)
	{
		s.clear();
		char buff[129];
		size_t i = 0;

		char ch;
		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;
	}
}

        


        

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Unity3D赛车游戏】【六】如何在Unity中为汽车添加发动机和手动挡变速?

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

【NVIDIA CUDA】2023 CUDA夏令营编程模型(二)

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

高中信息技术教资考试模拟卷(22下)

2022 年下半年全国教师资格考试模考卷一 &#xff08;高中信息技术&#xff09; 一、单项选择题&#xff08;本大题共 15 小题&#xff0c;每小题 3 分&#xff0c;共 45 分&#xff09; 1.2006 年 10 月 25 日&#xff0c;深圳警方成功解救出一名被网络骗子孙某…

创作2周年纪念日-特别篇

创作2周年纪念日-特别篇 1. 与CSDN的机缘2. 收获3. 憧憬 1. 与CSDN的机缘 很荣幸&#xff0c;在大学时候&#xff0c;能够接触到CSDN这样一个平台&#xff0c;当时对嵌入式开发、编程、计算机视觉等内容比较感兴趣。后面一个很偶然的联培实习机会&#xff0c;让我接触到了Pych…

基于PyTorch深度学习遥感影像地物分类与目标检测、分割及遥感影像问题深度学习优化

我国高分辨率对地观测系统重大专项已全面启动&#xff0c;高空间、高光谱、高时间分辨率和宽地面覆盖于一体的全球天空地一体化立体对地观测网逐步形成&#xff0c;将成为保障国家安全的基础性和战略性资源。未来10年全球每天获取的观测数据将超过10PB&#xff0c;遥感大数据时…

Python爬虫网络安全:优劣势和适用范围分析

各位Python程序猿大佬们&#xff01;在当今数字化时代&#xff0c;网络安全是至关重要的。保护你的网络通信安全对于个人和组织来说都是非常重要的任务。在本文中&#xff0c;我将与你一起探讨Python网络安全编程中的代理、虚拟专用网络和TLS这三个关键概念&#xff0c;分析它们…

django自动创建model数据

目前使用的环境&#xff1a;django4.2.3&#xff0c;python3.10 django通过一些第三方库&#xff0c;可以轻易的自动生成一系列的后台数据。 首先先创建一个数据库&#xff1a; 然后&#xff0c;在setting.py中就可以指定我们新创建的数据库了。 DATABASES {default: {ENGI…

土豆叶病害识别(图像连续识别和视频识别)

效果视频&#xff1a;土豆叶病害识别&#xff08;Python代码&#xff0c;pyTorch框架&#xff0c;视频识别&#xff09;_哔哩哔哩_bilibili 代码运行要求&#xff1a;Torch库>1.13.1&#xff0c;其它库无版本要求 1..土豆叶数据集主要包好三种类别&#xff08;Early_Blight…

单片机基础知识 06 (中断-2)

一. 定时器中断概念 51单片机的内部有两个16位可编程的定时器/计数器&#xff0c;即定时器T0和定时器T1。 52单片机内部多一个T2定时器/计数器。 定时器/计数器的实质是加1计数器&#xff08;16位&#xff09;&#xff0c;由高8位和低8位两个寄存器组成。 TMOD是定时器/计数器…

人工智能在机器学习中的八大应用领域

文章目录 1. 自然语言处理&#xff08;NLP&#xff09;2. 图像识别与计算机视觉3. 医疗诊断与影像分析4. 金融风险管理5. 预测与推荐系统6. 制造业和物联网7. 能源管理与环境保护8. 决策支持与智能分析结论 &#x1f389;欢迎来到AIGC人工智能专栏~探索人工智能在机器学习中的八…

亚马逊云科技CEO分享企业内决策流程、领导力原则与重组下的思考

亚马逊云科技首席执行官Adam Selipsky几乎从一开始就在那里&#xff1a;他于2005年加入&#xff0c;在效力亚马逊11年后于2016年离开&#xff0c;转而经营Tableau&#xff0c;并于2021年成为亚马逊云科技首席执行官。当时亚马逊云科技前首席执行官安迪贾西(Andy Jassy)接替杰夫…

姜启源数学模型第五版第五章火箭发射升空

姜启源数学模型第五版第五章例题内容复现 数学建模背景1.学习内容火箭发射升空理论知识 2.例题3.问题分析不考虑空气阻力的模型考虑空气阻力的模型 4.代码内容复现不考虑空气阻力考虑空气阻力模型 数学建模背景 首先先简单的介绍数学建模是一个怎么样的内容 数学建模是一种将数…

时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测

时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测 目录 时序预测 | MATLAB实现SSA-XGBoost(麻雀算法优化极限梯度提升树)时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实现SSA-XGBoost时间序列预测&#xff0c;麻…

老胡的周刊(第105期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 Piwigo[2] Piwigo 是一个开源的网络照片库软…

iOS App逆向之:iOS应用砸壳技术

在iOS逆向&#xff0c;有一项关键的技术叫做“iOS砸壳”&#xff08;iOS App Decryption&#xff09;。自iOS 5版本以来&#xff0c;苹果引入了应用程序加密机制&#xff0c;使得大部分应用都需要进行砸壳操作才能进行逆向分析。因此作为开发者、逆向工程师和安全研究人员都需要…

Wireshark流量分析例题

目录 前言 一、题目一(1.pcap) 二、题目二(2.pcap) 三、题目三(3.pcap) 四、题目四(4.pcap) 前言 Wireshark流量包分析对于安全来说是很重要的&#xff0c;我们可以通过Wireshark来诊断网络问题&#xff0c;检测网络攻击、监控网络流量以及捕获恶意软件等等 接下来我们…

OpenCV基础知识(9)— 视频处理(读取并显示摄像头视频、播放视频文件、保存视频文件等)

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。OpenCV不仅能够处理图像&#xff0c;还能够处理视频。视频是由大量的图像构成的&#xff0c;这些图像是以固定的时间间隔从视频中获取的。这样&#xff0c;就能够使用图像处理的方法对这些图像进行处理&#xff0c;进而达到…

Vue 中hash 模式与 history 模式的区别

hash 模式&#xff1a; - 地址中永远带着 # 号&#xff0c;不美观。 - 兼容性比较好。 - 通过手机 app 分享地址时&#xff0c;如果 app 效验严格&#xff0c;该地址会被标记为不合法。 history 模式&#xff1a; - 地址干净&#xff0c;美观。 - 兼容性和 hash 模式相比…

Hadoop入门机安装hadoop

0目录 1.Hadoop入门 2.linux安装hadoop 1.Hadoop入门 定义 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下&#xff0c;开发分布式程序。充分利用集群的威力进行高速运算和存储。 优势 高可靠性&#xff1a;Hadoop底层维护多…

校招算法题实在不会做,有没有关系?

文章目录 前言一、校招二、时间复杂度1、单层循环2、双层循环 三、空间复杂度四、数据结构五、校招算法题实在不会做&#xff0c;有没有关系&#xff1f;六、英雄算法集训 前言 英雄算法联盟八月集训 已经接近尾声&#xff0c;九月算法集训将于 09月01日 正式开始&#xff0c;目…