C++学习第七天(string类)

1、学习string的原因?

C语言中的字符串

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

一个面试题

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

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

时间复杂度O(N) 

class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1 = num1.size() - 1,end2 = num2.size() - 1;
        string retstr;
        //进位
        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 ret = val1 + val2 + next;
            next = ret / 10;
            ret = ret % 10;
            retstr += ('0'+ ret); 
        }
        if(next==1)
        retstr += '1';
        reverse(retstr.begin(),retstr.end());
        return retstr;
    }
};

 时间复杂度O(N^2)

class Solution {
public:
    string addStrings(string num1, string num2) {
        int end1 = num1.size() - 1,end2 = num2.size()-1;
        string retstr;

        //进位
        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 ret = val1+val2 +next;
            next = ret / 10;
            ret = ret % 10;
            retstr.insert(retstr.begin(),'0'+ret);
        }
        if(next == 1)
        retstr.insert(retstr.begin(),'1');
        return retstr;
    }
};

2、标准库中的string类

string类的常用接口说明

1、string对象的常见构造

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

 

int main()
{
	string s1;//构造空的string对象是
	string s2("hello world!");//用C格式字符串构造string类对象s2;
	string s3(9, 'c');//"ccccccccc"
	string s4(s2);//拷贝构造s3
	return 0;
}

2、string类对象的容量操作

函数名称功能说明
size(重点)返回字符串有效字符长度
length返回字符串有效字符长度
capacity返回总空间的大小
empty(重点)检测字符串是否为空串,是返回true,否则返回false
clear(重点)清空有效字符
reserve(重点)为字符串预留空间
resize(重点)将有效字符的个数改成n个,多出的空间用c填充
int main()
{
	string s("hello world!!!");
	cout << s.size() << endl;//14
	cout << s.length() << endl;//14
	cout << s.capacity() << endl;//15(vs 环境下)
	return 0;
}
int main()
{
	string s("hello world!!!");
	s.clear();
	cout << s.size() << endl;//0
	cout <<s.capacity()<<endl;//15(vs 环境下)
	return 0;
}
int main()
{
	string s1;
	cout << s1.empty() << endl;//1
	return 0;
}
int main()
{
	string s1("hello world!!!");
	s1.resize(20,'a');
	cout << s1 << endl;//hello world!!!aaaaaa
    s1.resize(10,'a');
    cout << s1 << endl;//hello worl
	return 0;
}
int main()
{
	string s;
	// 测试reserve是否会改变string中有效元素个数
	s.reserve(100);
	cout << s.size() << endl;//0
	cout << s.capacity() << endl;//111

	// 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
	s.reserve(50);
	cout << s.size() << endl;//0
	cout << s.capacity() << endl;//111
	return 0;
}

以上就是关于string类对象的容量操作

【Attention】

  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的底层空间总大小时,reserve不会改变容量大小

3、string类对象的访问及便利操作

函数名称功能说明
operator[](重载)返回pos位置的字符,const string类对象调用
begin + endbegin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器
rbegin + rendbegin获取一个字符的迭代器 + end获取最后一个字符的下一个位置的迭代器
范围forC++11支持更简介的范围for的新便利方式
int main()
{
	string s1("hello world!!!");
	const string s2("hello!!!");
	s1[0] = 'H';
	//s2[0] = 'H';编译失败,因为const类型对象不能修改
	return 0;
}
int main()
{
	string s1("hello world!!!");
	//3种遍历方式
	//需要注意的以下三种方式除了便利string对象,还可以遍历修改string中的字符
	//且第一种使用最多
	//1、for+operator[]
	for (size_t i = 0; i < s1.size(); i++)
		cout << s1[i] << endl;

	//2、迭代器
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << endl;
		++it;
	}

	//也可以这样子写
	//string::reverse_iterator rit = s.rbegin();
	//C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
	auto rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit << endl;
		++rit;
	}//遍历出来是!!!dlrow olleh

	//3、范围for
	for (auto ch : s1)
		cout << ch << endl;

	return 0;
}

5、string类非成员函数

函数功能说明
operator+尽量少用,因为传值返回,导致深拷贝的效率
operator>>(重点)输入运算符重载
operator<<(重点)输出运算符重载
getline(重点)获取一行字符串
relational operators(重点)大小比较
int main()
{
	string firstlevel("com");
	string secondlevel("cplusplus");
	string scheme("http://");
	string hostname;
	string url;

	hostname = "www." + secondlevel + '.' + firstlevel;
	url = scheme + hostname;

	cout << url << '\n';
	//http://www.cplusplus.com

	return 0;
}
int main()
{
	string name;

	cout << "Please, enter your name: ";
	cin >> name;
	cout << "Hello, " << name << "!\n";

	return 0;
}
int main()
{
	string str = "Hello world!";
	cout << str << endl;
	//Hello world!
	return 0;
}
int main()
{
	string name;

	cout << "Please, enter your full name: ";
	getline(cin, name);//Get line from stream into string
	cout << "Hello, " << name << "!\n";

	return 0;
}
int main()
{
	string foo = "alpha";
	string bar = "beta";

	if (foo == bar) cout << "foo and bar are equal\n";
	if (foo != bar) cout << "foo and bar are not equal\n";
	if (foo < bar) cout << "foo is less than bar\n";
	if (foo > bar) cout << "foo is greater than bar\n";
	if (foo <= bar) cout << "foo is less than or equal to bar\n";
	if (foo >= bar) cout << "foo is greater than or equal to bar\n";
	//foo and bar are not equal
	//foo is less than bar
	//foo is less than or equal to bar
	return 0;
}

6、几道OJ题目

1.仅仅反转字母

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

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

返回反转后的 s 。

示例1:

     输入:s = "a-bC-dEf-ghIj"

     输出:"j-Ih-gfE-dCba"

class Solution {
public:
    string reverseOnlyLetters(string s) {
        int n = s.size();
        int left = 0, right = n - 1;
        while (true) {
            while (left < right && !isalpha(s[left])) { // 判断左边是否扫描到字母
                left++;
            }
            while (right > left && !isalpha(s[right])) { // 判断右边是否扫描到字母
                right--;
            }
            if (left >= right) {
                break;
            }
            swap(s[left], s[right]);
            left++;
            right--;
        }
        return s;
    }
};

 字符串中的第一个唯一字符

给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。

class Solution {
public:
    int firstUniqChar(string s) {
        int count[256] = {0};
        int size = s.size();
        for(int i = 0; i < size; ++i)
        count[s[i]] += 1;
        for(int i = 0; i < size;i++)
        {
            if(1 == count[s[i]])
            return i;
        }
        return -1;
    }
};

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

输入:hello nowcoder

输出:8

int main() {
    string s1;
    getline(cin,s1);
    int count = 0;
    int size = s1.size()-1;
    while(s1[size]!=' ')
    {
        size--;
        count++;
        if(size == 0)
        {
        count++;
        break;
        }
    }
    cout << count <<endl;
}

 验证回文串

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

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

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

输入: s = "A man, a plan, a canal: Panama"
输出:true
解释:"amanaplanacanalpanama" 是回文串。
class Solution {
public:
    bool isPalindrome(string s) {
        int left = 0, right = s.size()-1;
        while(left < right)
        {
            while(left < right && !isalnum(s[left]))
            {
                left++;
            }
             while(left < right && !isalnum(s[right]))
            {
                right--;
            }
            if(tolower(s[left]) != tolower(s[right]))
            return false;
            left++;
            right--;
        } 
        return true;
    }
};

3、string的模拟实现

容易出现的string类问题

//为了和标准库区分,这里使用String
class String
{
public:
	String(const char* str = "")
	{
		if (nullptr == str)
		{
			assert(false);
			return;
		}
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	~String()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};

void TestString()
{
	String s1("hello world!!!");
	String s2(s1);
}

int main()
{
	TestString();
	return 0;
}

这里程序会报错,因为上述String类没有显示定义其拷贝构造函数与赋值运算符重载,此时编译器会合成默认的,当用s1构造s2时,编译器会调用默认的拷贝构造,最终导致的问题是,s1与s2共用了一块内存空间,在释放时同一块空间被释放多次而引发程序崩溃,这种拷贝方式,被称为浅拷贝

浅拷贝

概念:也叫位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象工享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为还有效,所以当继续对该资源进行该项操作时,就会发生访问违规

深拷贝

如果一个类中涉及到资源的管理,其拷贝构造函数,赋值运算符重载以及析构函数必须要显式给出。一般情况都是按照深拷贝方式提供

传统写法的深拷贝

class String
{
public:
	String(const char* str = "")
	{
		if (nullptr == str)
		{
			assert(false);
			return;
		}
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	String(const String& s)
		:_str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}
	String& operator=(const String& s)
	{
		if (this != &s)
		{
			char* pStr = new char[strlen(s._str) + 1];
			strcpy(pStr, s._str);
			delete[] _str;
			_str = pStr;
		}
		return *this;
	}
private:
	char* _str;
};

现代写法的String类

class String
{
public:
	String(const char* str = "")
	{
		if (nullptr == str)
		{
			assert(false);
			return;
		}

		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	String(const String& s)
		:_str(nullptr)
	{
		String strTmp(s._str);
		swap(_str, strTmp._str);
	}

	String& operator=(String s)
	{
		swap(_str, s._str);
		return *this;
	}

	~String()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
		}
	}
private:
	char* _str;
};

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

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

相关文章

浅析扩散模型与图像生成【应用篇】(七)——Prompt-to-Prpmpt

7. Prompt-to-Prompt Image Editing with Cross Attention Control 本文提出一种利用交叉注意力机制实现文本驱动的图像编辑方法&#xff0c;可以对生成图像中的对象进行替换&#xff0c;整体改变图像的风格&#xff0c;或改变某个词对生成图像的影响程度&#xff0c;如下图所示…

Django 管网项目 三

Django 官网文档 ​​Writing your first Django app, part 2 | Django documentation | Django 本文内容涉及创建视图 View&#xff0c;路由&#xff0c;和模版。并对内容进行渲染。 创建视图 在我们的投票应用中&#xff0c;我们需要下列几个视图&#xff1a; 问题索引页—…

LabVIEW管道缺陷智能检测系统

LabVIEW管道缺陷智能检测系统 管道作为一种重要的输送手段&#xff0c;其安全运行状态对生产生活至关重要。然而&#xff0c;随着时间的推移和环境的影响&#xff0c;管道可能会出现老化、锈蚀、裂缝等多种缺陷&#xff0c;这些缺陷若不及时发现和处理&#xff0c;将严重威胁到…

外包干了10天,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;2019年我通过校招踏入了南京一家软件公司&#xff0c;开始了我的职业生涯。那时的我&#xff0c;满怀热血和憧憬&#xff0c;期待着在这个行业中闯出一片天地。然而&#xff0c;随着时间的推移&#xff0c;我发现自己逐渐陷入…

《程序员的职业迷宫:选择你的职业赛道》

程序员如何选择职业赛道&#xff1f; 大家好&#xff0c;我是小明&#xff0c;一名在编程迷宫中探索的程序员。作为这个庞大迷宫的探险者&#xff0c;我深知选择适合自己的职业赛道有多么重要。今天&#xff0c;我将分享一些关于如何选择职业赛道的心得&#xff0c;希望能够帮…

JWT令牌实现登陆校验

一、JWT出现的背景 jwt令牌出现的背景&#xff0c;比如我们通过一个路由访问网站的时候&#xff0c;有些游客在知道url的情况下会跳过用户登录直接访问其他网页&#xff0c;这样不仅在逻辑上说不通&#xff08;我没登陆咋就能使用其他功能&#xff1f;&#xff09;还会造成信息…

指针乐园--下

大家好这里是指针乐园下&#xff0c;下面我们开始喽&#xff01;&#xff01; 文章目录 目录 文章目录 前言 一、字符以及数组指针 二、函数指针变量以及函数指针数组 函数指针变量的使⽤ 通过函数指针调⽤指针指向的函数。 函数指针数组 总结 前言 我们今天会学习数组指针&…

LeNet训练集详细实现

一、下载训练集 导包 import torch import torchvision import torch.nn as nn from model import LeNet import torch.optim as optim import torchvision.transforms as transforms import matplotlib.pyplot as plt import numpy as npToTensor()函数&#xff1a; 把图像…

npm 私服以及使用

在工作中&#xff0c;公司有很多内部的包并不希望发布到npm官网仓库&#xff0c;因为可能涉及到一些私有代码不能暴露。对于前端来讲&#xff0c;这时就可以选择在公司内网搭建npm私有仓库。当前比较主流的几种解决方案&#xff1a;verdaccio、nexus、cnpm。大家可以按照自己的…

限时特惠,立即购买CST电磁仿真软件,享受超值优惠与高质量服务

在电磁仿真领域&#xff0c;CST软件以其卓越的性能和广泛的应用成为了行业内的佼佼者。现在&#xff0c;我们非常高兴地宣布&#xff0c;为庆祝CST软件的持续创新与客户支持&#xff0c;我们推出限时特惠活动&#xff01;&#xff08;联系CST软件中国区代理亿达四方&#xff0c…

RabbitMQ如何保证消息不丢

如何保证Queue消息能不丢呢&#xff1f; RabbitMQ在接收到消息后&#xff0c;默认并不会立即进行持久化&#xff0c;而是先把消息暂存在内存中&#xff0c;这时候如果MQ挂了&#xff0c;那么消息就会丢失。所以需要通过持久化机制来保证消息可以被持久化下来。 队列和交换机的…

React Vite 构建工具如何查看代码占用体积

首先安装 Vite 中的 rollup-plugin-visualizer 插件 cnpm install rollup-plugin-visualizer 接着在你的 vite.config.ts 中引入并且使用到 plugins 中 import { visualizer } from "rollup-plugin-visualizer";export default defineConfig({plugins: [react(),vi…

现代信号处理学习笔记(三)现代谱估计

现代谱估计是信号处理和统计领域的一个重要主题&#xff0c;它涉及从信号中估计其频谱内容的方法。频谱表示一个信号在不同频率上的成分强度。谱估计在许多应用中都很重要&#xff0c;如通信系统、雷达、音频处理、生物医学工程等领域。 目录 前言 一、基础知识 1、功率谱估…

同步通信和异步通信(RabbitMq学习前篇)

MQ学习前篇 文章目录 MQ学习前篇1、同步和异步通讯1.1、同步通讯和异步通讯1.2、同步调用存在的问题1.3、异步调用方案1.4、异步通信的缺点 1、同步和异步通讯 学习mq之前&#xff0c;就要先知道同步通讯和异步通讯的区别。 1.1、同步通讯和异步通讯 同步通讯就像是打电话&am…

【网络安全】漏洞挖掘入门教程(非常详细),小白是如何挖漏洞(技巧篇)0基础入门到精通!

温馨提示&#xff1a; 初学者最好不要上手就去搞漏洞挖掘&#xff0c;因为漏洞挖掘需要很多的系统基础知识和一些理论知识做铺垫&#xff0c;而且难度较大…… 较合理的途径应该从漏洞利用入手&#xff0c;不妨分析一些公开的CVE漏洞。很多漏洞都有比较好的资料&#xff0c;分…

Java开发人员不得不收集的代码,java软件开发面试常见问题

前言 今年的金三银四已经过去一大半了&#xff0c;在这其中参与过不少面试&#xff0c;2021都说工作不好找&#xff0c;这也是对开发人员的要求变向的提高了。 之前在Github上收获15Kstar的Java核心神技&#xff08;这参数&#xff0c;质量多高就不用我多说了吧&#xff09;非…

C++与 Fluke5500A设备通过GPIB-USB-B通信的经验积累

C与 Fluke5500A设备通过GPIB-USB-B通信的经验积累 以下内容来自&#xff1a;C与 Fluke5500A设备通过GPIB-USB-B通信的经验积累 - JMarcus - 博客园 (cnblogs.com)START 1.需要安装NI-488.2.281&#xff0c;安装好了之后&#xff0c;GPIB-USB-B的驱动就自动安装好了 注意版本…

13. C++类使用方式

【类】 C语言使用函数将程序代码模块化&#xff0c;C通过类将代码进一步模块化&#xff0c;类用于将实现一种功能的全局数据、以及操作这些数据的函数集中存储在一起&#xff0c;同时可以设置类成员的访问权限&#xff0c;禁止外部代码使用和篡改本类成员&#xff0c;类成员访…

SMT贴片加工——品质检验要求

一、元器件贴装工艺品质要求 1.元器件贴装需整齐、正中&#xff0c;无偏移、歪斜 2.贴装的元器件型号规格应正确&#xff1b;元器件应无漏贴、错贴 3.贴片元器件不允许有反贴 4.有极性要求的贴片器件安装需按正确的极性标示安装 二、元器件焊锡工艺要求 1.FPC板面应无影响…

Java实现读取转码写入ES构建检索PDF等文档全栈流程

背景 之前已简单使用ES及Kibana和在线转Base64工具实现了检索文档的demo&#xff0c;并已实现WebHook的搭建和触发流程接口。 传送门&#xff1a; 基于GitBucket的Hook构建ES检索PDF等文档全栈方案 使用ES检索PDF、word等文档快速开始 实现读取本地文件入库ES 总体思路&…