【C++】透析string类

news2024/12/23 12:41:13

                                个人主页:CSDN_小八哥向前冲~

                                 所属专栏:C++入门


目录

string类介绍

auto和范围for

auto关键字

范围for

string类常用接口说明

string类常见构造

string类容量操作

string类的访问及遍历操作

string类修改操作

string的结构说明

vs下的结构

G++下的结构

string经典题目

仅仅反转字母

字符串中的第一个字符

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

验证回文字符

字符串相加

string类的模拟实现

码源


string类介绍

关于string的详细介绍,我们可以去C++官网查询!

官网:https://cplusplus.com/

下面我只做一些简单介绍!

auto和范围for

auto关键字

  • 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个 不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型 指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期 推导而得。
  • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
  • auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
  • auto不能直接用来声明数组

范围for

  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此 C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围 内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
  • 范围for可以作用到数组和容器对象上进行遍历
  • 范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

使用:

string类常用接口说明

注意:这些所有函数可以去C++官网查看,有详细讲解!

string类常见构造

我们来详细演示一下!

string类容量操作

注意一下这些函数的要点!

我们依然来演示一下!

string类的访问及遍历操作

函数:

我们来演示一下!

string类修改操作

这些重要函数我们要了然于心!

演示一下!

string的结构说明

vs下的结构

真实的情况:

G++下的结构

我们来试试几个题目练习一下!

string经典题目

仅仅反转字母

题目:【力扣】仅仅反转字符

思路:

定义两个指针,一个在前,一个在后,当两个指针指向的都是字母的时候就开始交换!

代码:

class Solution {
public:
    //判断是不是字母
    bool isnumber(const char& tmp)
    {
        if(tmp<='z'&&tmp>='a') return true;
        if(tmp<='Z'&&tmp>='A') return true;
        return false;
    }
    string reverseOnlyLetters(string s) {
        size_t begin=0,end=s.size()-1;
        while(begin<end)
        {
            //找到字母
            while(begin<end&&!isnumber(s[begin])) begin++;
            while(begin<end&&!isnumber(s[end])) end--;
            //交换字母
            swap(s[begin++],s[end--]);
        }
        return s;
    }
};

字符串中的第一个字符

题目:字符串中的第一个字符

思路:

遍历字符串,利用映射原理将字符全部映射进一个数组,然后再次遍历字符串!

代码:

class Solution {
public:
    int firstUniqChar(string s) {
        int count[26]={0};
        //利用映射
        for(auto& e:s) count[e-'a']++;
        //再次遍历一遍数组
        for(int i=0;i<s.size();i++)
        {
            if(count[s[i]-'a']==1) return i;
        }
        return -1;
    }
};

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

题目:【牛客】字符串最后一个单词的长度

思路:

注意如果我们用cin去输入,那么到了空格就会停下,我们用getline就能避免这个情况!

代码:

int main() {
    string s1;
    getline(cin, s1, '\n');
    size_t pos = s1.rfind(' ');
    cout << s1.size() - (pos + 1) << endl;
    return 0;
}

验证回文字符

题目:【力扣】验证回文字符

思路:

先将字符串转化成小写,定义双指针,一前一后,如果两指针指向的是字母或数字,开始判断是否一样!

代码:

class Solution {
public:
    bool isnumber(char& ch)
    {
        return (ch >= 'a' && ch <= 'z')
            || (ch >= '0' && ch <= '9');
    }
    bool isPalindrome(string s) {
        //转换小写
        for (auto& e : s)
        {
            if (e <= 'Z' && e >= 'A') e += 32;
        }
        int begin = 0, end = s.size() - 1;
        while (begin < end)
        {
            while (begin < end && !isnumber(s[begin])) begin++;
            while (begin < end && !isnumber(s[end])) end--;
            if (s[begin++] != s[end--]) return false;
        }
        return true;
    }
};

字符串相加

题目:【力扣】字符串相加

思路:

我们按照数学里面的加减法进位的方式,从各自的字符串末尾开始相加,只是注意好进位,我们算好每位的数字,然后尾插进一个新字符串中,最终将它们翻转一下就行!

代码:

class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1=num1.size()-1,end2=num2.size()-1;
        string s;
        //进位变量
        int next=0;
        while(end1>=0||end2>=0)
        {
            int val1=end1>=0?num1[end1--]-'0':0;
            int val2=end2>=0?num2[end2--]-'0':0;
            int sum=val1+val2+next;
            next=sum/10;
            sum%=10;
            s+=sum+'0';
        }
        if(next==1) s+='1';
        //翻转
        reverse(s.begin(),s.end());
        return s;
    }
};

string类的模拟实现

在这里我们重点说一下拷贝构造,赋值构造,字符串的输入

拷贝构造

通常我们的拷贝构造是这样写的:

string(const string& s)
{
	//传统写法
	_str = new char[s._capacity];
	_capacity = s._capacity;
	_size = s._size;
	strcpy(_str, s._str);
}

我们可以改善一下:

		void swap(string& tmp)
		{
			std::swap(_str, tmp._str);
			std::swap(_size, tmp._size);
			std::swap(_capacity, tmp._capacity);
		}
		string(const string& s)
		{
			//传统写法
			//_str = new char[s._capacity];
			//_capacity = s._capacity;
			//_size = s._size;
			//strcpy(_str, s._str);

			//现代写法
			string tmp(s.c_str());
			swap(tmp);
		}

解释:构造一个和 s 相同的string类对象tmp,然后将tmp里面的数据和this里面的数据交换 ,最后无用数据tmp出作用域被销毁!

赋值构造也是如此!

传统写法:

string& operator=(string& s)
{
	//传统写法
	if (this != &s)
	{
		delete[] _str;
		_str = new char[_capacity + 1];
		strcpy(_str, s._str);
		_size = s._size;
		_capacity = s._capacity;
	}
}

我们也可以相同的手法来改善它!

string& operator=(string& s)
{
	//传统写法
	//if (this != &s)
	//{
	//	delete[] _str;
	//	_str = new char[_capacity + 1];
	//	strcpy(_str, s._str);
	//	_size = s._size;
	//	_capacity = s._capacity;
	//}

	//现代写法
	if (this != &s)
	{
		string tmp(s.c_str());
		swap(tmp);
	}
	return *this;
}

甚至可以进一步完善!

		//或者(现代写法)
		string& operator=(string tmp)
		{
			swap(tmp);
			return *this;
		}

构造一个新string 类对象这一步浓缩在了函数参数这一步!

字符串的输入jieshi

	istream& operator>>(istream& in, string& s)
	{
		const size_t N = 256;
		char buff[N] = { 0 };
		char ch = 0;
		ch = in.get();
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;//尾插
				i = 0;//重置i
			}
			ch = in.get();
		}
		if (i > 0)//将剩下的数据尾插
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}

解释:我们相当于创建了一个数组容器,将字符不断插入进这个容器,当容器满的时候,将这些数据插入string 类对象里,如果暂停输入,将剩下的数据再插入进string 类对象里!

码源

String.h文件

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

namespace ywc
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}
		string(const char* str="")
		{
			_size = _capacity = strlen(str);
			_str = new char[_size + 1];
			strcpy(_str, str);
		}
		void swap(string& tmp)
		{
			std::swap(_str, tmp._str);
			std::swap(_size, tmp._size);
			std::swap(_capacity, tmp._capacity);
		}
		string(const string& s)
		{
			//传统写法
			//_str = new char[s._capacity];
			//_capacity = s._capacity;
			//_size = s._size;
			//strcpy(_str, s._str);

			//现代写法
			string tmp(s.c_str());
			swap(tmp);
		}
		string& operator=(string s)
		{
			swap(s);
			return *this;
		}
		const char* c_str() const
		{
			return _str;
		}
		size_t size()
		{
			return _size;
		}
		size_t capacity()
		{
			return _capacity;
		}
		char operator[](size_t pos)
		{
			assert(pos >= 0);
			return _str[pos];
		}
		void reserve(size_t n);
		void push_back(char ch);
		string& append(const char* str);
		string& operator+=(char ch);
		string& operator+=(const char* str);
		string& insert(size_t pos, char ch);
		string& insert(size_t pos, const char* str);
		string& erease(size_t pos, size_t len);
		size_t find(char ch, size_t pos = 0);
		size_t find(const char* str, size_t pos = 0);
		string substr(size_t pos, size_t len);
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;

		static const size_t npos;
	};
	ostream& operator<<(ostream& out, string& s);
	istream& operator>>(istream& in, string& s);
}

String.cpp文件

namespace ywc
{
	const size_t string::npos = -1;
	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			//"\0"
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			_str = tmp;
			_capacity = n;
		}
	}
	void string::push_back(char ch)
	{
		if (_size == _capacity)
		{
			reserve(_capacity == 0 ? 4 : 2 * _capacity);
		}
		_str[_size++] = ch;
		_str[_size] = '\0';
	}
	string& string::append(const char* str)
	{
		size_t len = strlen(str);
		if (len + _size >= _capacity)
		{
			reserve(len + _size > 2 * _capacity ?
				len + _size : 2 * _capacity);
		}
		strcpy(_str + _size, str);
		_size += len;
		return *this;
	}
	string& string::operator+=(char ch)
	{
		push_back(ch);
		return *this;
	}
	string& string::operator+=(const char* str)
	{
		append(str);
		return *this;
	}
	string& string::insert(size_t pos, const char ch)
	{
		assert(pos <= _size);
		if (_size == _capacity)
		{
			reserve(_capacity = 0 ? 4 : 2 * _capacity);
		}
		size_t end = _size + 1;
		while (end > pos)
		{
			_str[end] = _str[end - 1];
			end--;
		}
		_str[pos] = ch;
		_size++;
		return *this;
	}
	string& string::insert(size_t pos, const char* str)
	{
		assert(pos < _size);
		size_t len = strlen(str);
		if (len + _size >= _capacity)
		{
			reserve(len + _size > 2 * _capacity 
				? len + _size : 2 * _capacity);
		}
		size_t end = len + _size;
		while (end - len >= pos)
		{
			_str[end] = _str[end - len];
			end--;
		}
		for (size_t i = 0; i < len; i++)
		{
			_str[pos + i] = str[i];
		}
		_size += len;
		return *this;
	}
	string& string::erease(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (len >= _size - pos)
		{
			_size = pos;
			_str[pos] = '\0';
		}
		else
		{
			for (size_t i = pos;i<=_size-len;i++)
			{
				_str[i] = _str[i + len];
			}
			_size -= len;
		}
		return *this;
	}
	size_t string::find(char ch, size_t pos)
	{
		assert(pos < _size);
		for (size_t i = 0; i < _size; i++)
		{
			if (_str[i] == ch)
				return i;
		}
		return npos;
	}
	size_t string::find(const char* str, size_t pos)
	{
		assert(pos < _size);
		char* tmp = strstr(_str + pos, str);
		if (tmp == nullptr)
			return npos;
		else
			return tmp - _str;
	}
	string string::substr(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (len > _size - pos)
		{
			len = _size - pos;
		}
		string sub;
		sub.reserve(len);
		for (size_t i = 0; i < len; i++)
		{
			sub += _str[pos + i];
		}
		return sub;
	}
	ostream& operator<<(ostream& out, string& s)
	{
		for (auto& ch : s)
		{
			cout << ch;
		}
		return out;
	}
	istream& operator>>(istream& in, string& s)
	{
		const size_t N = 256;
		char buff[N] = { 0 };
		char ch = 0;
		ch = in.get();
		int i = 0;
		while (ch != ' ' && ch != '\n')
		{
			buff[i++] = ch;
			if (i == N - 1)
			{
				buff[i] = '\0';
				s += buff;//尾插
				i = 0;//重置i
			}
			ch = in.get();
		}
		if (i > 0)//将剩下的数据尾插
		{
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}
}

好了,我们下期见!

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

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

相关文章

LibJPEG库使用_通过LibJPEG将RGB数据保存为JPG图片存储到磁盘

一、前言 LibJPEG库是一个广泛使用的开源C库&#xff0c;用于处理JPEG图像的压缩和解压缩。该库由独立JPEG小组&#xff08;Independent JPEG Group, IJG&#xff09;开发&#xff0c;提供了功能强大的API&#xff0c;用于创建和读取JPEG文件。LibJPEG库支持JPEG的所有常见功能…

Cpp快速入门语法(上)(1)

文章目录 前言一、C关键字(C98)二、命名空间命名空间的定义命名空间的使用 三、C输入 & 输出四、缺省参数总结 前言 其实有时候我也会尝试代入下祖师爷本杰明当年在贝尔实验室的心理活动&#xff0c;我心想&#xff0c;他可能一开始是大抵受不了C语言的某些缺点&#xff0c…

梦想之家|AI技术赋能家居,重塑生活空间

人工智能&#xff08;AI&#xff09;在智能家居方面的应用非常广泛&#xff0c;极大地提升了家庭的便利性、安全性和能源效率。当前&#xff0c;AI技术的迅速发展&#xff0c;为传统家居产品带来了智能化升级。从智能单品到智能互联&#xff0c;AI技术的融入使得这些家居产品具…

DC-DC降压10A电源降压可调模块24V转12V9V5V3V-AH1514芯片

AH1514&#xff1a;一款高效率小体积的DC-DC降压电源芯片 摘要&#xff1a;本文介绍了一款高性能的DC-DC降压电源芯片——AH1514&#xff0c;该芯片具有24V转12V、9V、5V、3V可调输出&#xff0c;支持7V-38V输入&#xff0c;20A峰值输出电流&#xff0c;且具有小体积、高效率的…

C++速通LeetCode简单第19题-只出现一次的数字

方法一&#xff1a;暴力求解&#xff0c;排序后两个两个比较&#xff0c;两者不同时前者为答案&#xff1a; class Solution { public:int singleNumber(vector<int>& nums) {if(nums.size() 1) return nums[0];list<int> l;int ans 0;for(int i 0;i< n…

3.js - THREE.CubeTextureLoader() 添加环境纹理,以创建立方体贴图

使用 THREE.CubeTextureLoader() 添加环境纹理&#xff0c;以创建立方体贴图 不使用 THREE.CubeTextureLoader() 的时候 源码 import * as THREE from three import { OrbitControls } from three/examples/jsm/controls/OrbitControls import { RGBELoader } from three/exam…

【话题讨论】AI时代程序员核心力:技术深耕,跨界学习,软硬兼备

目录 引言 一、AI辅助编程对程序员工作的影响 1.1 AI工具如何提升工作效率 1.2 AI工具的风险 1.3 应对策略 二、程序员应重点发展的核心能力 2.1 核心竞争力 2.2 企业和教育机构的调整 三、人机协作模式下的职业发展规划 3.1 持续学习的重要性 3.2 选择适合自己的…

电脑提示‘由于找不到 msvcr120.dll,无法继续执行代码’的科学解决方案分析

如果你在启动特定的应用程序或游戏时遇到错误提示&#xff1a;“由于找不到 msvcr120.dll&#xff0c;无法继续执行代码”&#xff0c;这表明你的系统可能缺少运行某些基于 Visual C 2013 开发的程序所需的关键组件。不过&#xff0c;不必担心&#xff0c;有几种方法可以解决这…

使用C++程序编写5 个浮点数,求平均值后输出

源代码如下&#xff1a; #include <iostream>using namespace std;int main() {float arr[5]{7,10,3,9,8};int i;float sum 0;float avg 0;for(i0;i<5;i){sum sum arr[i];}avg sum/5;cout << "平均值是&#xff1a;" << avg << endl…

VoIP协议

VoIP协议是VoIP业务的规范标准。我们都知道VoIP业务有着压倒性的优势。随着网络应用的多元化和低成本化发展&#xff0c;VoIP业务直接冲击着传统通信市场&#xff0c;那么目前VoIP协议目前常用的协议,如H.323、SIP、MEGACO和MGCP。 H.248 H.248是定义网关控制协议的ITU建议书…

squid代理及常见的代理上网(Squid Proxy and Common Proxy Internet Access)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

【学术会议征稿】第九届计算机技术与机械电气工程国际学术论坛(ISCME 2024)

第九届计算机技术与机械电气工程国际学术论坛&#xff08;ISCME 2024&#xff09; 2024 9th International Seminar on Computer Technology, Mechanical and Electrical Engineering 第九届计算机技术与机械电气工程国际学术论坛&#xff08;ISCME 2024&#xff09;将于2024…

还在为机器学习中,层出不穷的概念烦恼么?不妨看看这边,南瓜书第1,2章学习总结-task01

第一章&#xff1a;绪论 这里面讲了机器学习的基本概念&#xff0c;包括基本术语 1.1.基本概念 数据集和样本集的区别。原始检测数据是总体,总体是统计所研究对象的全体,是包含所研究变量的全部个体的集合,具有同质性、差异性、大量性。构成总体的个别事物叫总体单位。样本检测…

idea插件开发的第四天-完善JSON工具

介绍 Demo说明 本文基于maven项目开发,idea版本为2022.3以上,jdk为1.8本文在Tools插件之上进行开发本次demo将使用idea的一些组件优化 Tools插件说明 Tools插件是一个Idea插件,此插件提供统一Spi规范,极大的降低了idea插件的开发难度,并提供开发者模块,可以极大的为开发者开…

nodejs 009: 使用nvm进行node版本管理(包括Could not retrieve的手动处理办法)

nvm 有些问题类似&#xff1a;“v8::Object::Set": No overloaded function accepts 2 Arguments”可能需要通过更换nodejs的版本来解决&#xff08;如下图所示&#xff0c;需要看当时的项目的时间&#xff0c;查找当时的流行nodejs版本&#xff09;。这时可以使用nvm进行…

干耳朵里的耳屎结坨了怎么弄出来?可视挖耳勺推荐

干耳朵里的耳屎结坨了怎么弄出来&#xff1f;这个是很多干耳朵小伙伴的一个难题。用棉签掏根本掏不出来&#xff0c;反而会越推越进。用普通耳勺掏不仅不够精准还会因为盲掏&#xff0c;弄伤自己的耳膜或者刮破耳道。所以干耳朵里的耳屎结坨了&#xff0c;建议用可视挖耳勺来掏…

robosuite基础教程(一)——基本概念

robosuite和robomimic都是由ARISE Initiative开发的开源工具&#xff0c;旨在推进机器人学习和机器人操作领域的研究。 一、基本概念 robosuite是一个由MuJoCo物理引擎驱动的模拟框架&#xff0c;专为机器人学习设计。它提供了一套基准环境&#xff0c;是Advancing Robot Int…

C++/CLI编程知识点小记

1.前言 本篇博文并非详细的C/CLI教程&#xff0c;仅是博主就学习和实践总结的部分知识点记录。 第一次接触C/CLI是2017年了&#xff0c;用C编写底层库&#xff0c;C/CLI编写wrapper层&#xff0c;在C#项目中进行调用&#xff0c;开发应用。 2.内容 C/CLI是一种混合编程&…

不要沉迷大模型的技术与理论,学习大模型的方法——从做一个小应用开始

“ 在应用中学习技术&#xff0c;而不是沉迷于技术本身 ” 不知道大家都是怎么学习大模型技术的&#xff0c;但从个人的经验和公众号的反馈来看&#xff0c;有些人在学习大模型技术时转进了牛角尖&#xff0c;导致很多东西学不明白&#xff0c;事倍功半。 今天就从个人的学习…