首页 > 其他分享 >string 的基本用法

string 的基本用法

时间:2024-12-01 11:31:32浏览次数:12  
标签:基本 string s2 s1 cout 用法 字符串 size


前言

string是一个非常常见的数据类型,用于表示文本或字符序列。以下是关于它的详细介绍:
string(字符串)是由零个或多个字符组成的有限序列。字符可以是字母、数字、标点符号、空格或其他符号。例如,“Hello”、“123”、“!@#$” 等都是字符串。

在 C++ 中,string是标准库(<string>头文件)中的一个类。可以通过以下方式定义和使用字符串:
#include <iostream>
#include <string>
int main() {
    std::string str = "Hello, World!";
    std::cout << str << std::endl;
    return 0;
}

在这里插入图片描述


一、string类对象的构造函数

string实现了多个构造函数的重载,常用的构造函数如下:

string();构造空字符串(默认构造函数) .
string (size_t n, char c);生成n个C 字符的字符串
string (const char* s);	复制由 s 指向的以 null 结尾的字符序列(C 字符串)or 用C-string来构造string类对象 .
string (const char* s, size_t n);复制s所指的前n个字符序列
string(const string& str);生成str的复制品(拷贝构造) .
string(const string& str, size_t pos, size_t len = npos);//复制str中从字符位置 pos位置开始并跨越len个字符的部分(如果len超过npos,那就取到npos停止)

使用示例 :

string s1;                 构造空字符串 .
string s2("hello world");  C格式字符串构造string类对象s2 .
string s3("hello world",3);复制"hello world"的前三个字符
string s4(10, 's');        生成10个's'字符的字符串
string s3(s2);             拷贝构造 .
string s4(s2, 6, 1000);    取不到这么多,到npos就停下了;
string s5(s2, 6);          不给具体取多少,那就自动取到npos结束

二、sring元素的访问

有三种模式进行遍历

string底层结构:

namespace ky
{
    class string
    {
    public:
        char& operator[](size_t pos)
        {
            assert(pos < _size);
            return _str[_size];
        }
        const char& operator[](size_t pos) const 
        {
            assert(pos < _size);
            return _str[_size];
        }
    private:
        //两段存储
        char _buff[16];//<16,存到对象本身里面,不用去堆上开空间,效率提高
        char* _str;//如果>=16个字符就到堆开辟空间存储,之前的_buff浪费掉,(以空间换时间),减少内存碎片,提高效率
        size_t _size;
        size_t _capacity;
    };
}

下标法
operator [ ]
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;

void teststring1()
{
string s1;                
string s2("hello world");

const string s6 = "xxxxxx";
s6[0] = 'y';//权限放大,不能修改

1.下标 + []
    for (size_t i = 0; i < s2.size(); i++)
	    {
			//[]+下标修改对象元素内容
	        s2[i] += 1;
	        //s2.operator[](i) += 1;编译器会翻译成这样
	    }
    for (size_t i = 0; i < s2.size(); i++)
	   {
	   		//[]+下标访问对象元素
	       cout << s2[i] << " ";
	   }
    cout << endl;
}

正向迭代器 :
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
反向迭代器 :
reverse_iterator rbegin()
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;

2.迭代器
 [)
 
	//char*
	string::iterator it = s2.begin();
	//auto it = s2.begin();
	while (it != s2.end())    //最好不要用 < 因为string底层是数组,空间连续,但是其他的就不一定连续无法比较大小
	{
	    *it += 1;
	    cout << *it << " ";
	    ++it;
	}
	cout << endl;

   //const char*
   string::const_iterator it5 = s5.begin(); //迭代器本身可以修改,指向的内容不能修改
   //auto it5 = s5.begin();
   while (it5 != s5.end())   
   {
       cout << *it5 << " ";
       ++it5;
   }
   cout << endl;

    //反向迭代器遍历;
    string::reverse_iterator rit = s2.rbegin();
    while (rit != s2.rend())
    {
        *rit += 1; //没有const限制可修改本身
        cout << *rit << " ";
        ++rit;
    }
    cout << endl;

    string::const_reverse_iterator rit2 = s2.rbegin();
    while (rit2 != s2.rend())
    {
        //*rit += 1;//const限制,要修改权限就会放大
        cout << *rit2 << " ";
        ++rit;
    }
    cout << endl;
  3.基于for循环遍历(底层还是用迭代器)
  在编译器的前置处理阶段就替换成了iterator,把 *it 给了 ch
   编译器编译到语法层面就没有这个基于范围for
  for (auto ch : s2)
  {
      cout << ch << " ";
  }
  cout << endl;
 at.( )
 char& at (size_t pos);
 const char& at (size_t pos) const;
  at 方法和operator[ ]无本质区别,且operator[ ]更加常用, at()方法很少用到
{
	string s1 = "hello world";
	for (size_t i = 0;i < s1.size();i++)
	{
		cout << s1.at(i) << " ";
	}
	cout << endl;
}

三、 string的大小和容量

1.size( )

size()用来计算字符串中有效字符的个数,不包含’\0’

2. capacity( )

返回当前为字符串分配的存储空间的大小,以字节表示
capacity() 用来计算当前字符串的容量,最多能够存放的有效字符的个数
同样的一个字符串, 不同编译器下给定的capacity的大小可能会不太一样,没有规律~

3. clear( )

clear用于清空字符串,使得字符串中有效字符的个数为0,因此size为0,capacity不变

4. empty( )

empty()用于判断字符串是否为空,为空返回1,不为空返回0


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

int main()
{
    string s1;
    cout << sizeof(s1.max_size()) << endl;//实际开不出这么大的空间

    string s2("hello world");
    cout << s2.size() << endl; //11 '\0'只起标识符作用
    cout << s2.length() << endl;//length和size功能一样但为了和其他容器使用规则一样统一用size().
    cout << s2.capacity() << endl;//15 不算'\0',只计算存在的有效字符, 实际上空间一共有16个
	
    //size和capacity均不包含'\0'

    s2.clear();
    cout << s2.size() << endl; 
    cout << s2.capacity() << endl;

   string s4 = "hello";
   string s5;
   cout << s4.empty() << endl;//1
   cout << s5.empty() << endl;//0

}

5. shrink_to_fit( )

shrink_to_fit()是用来向系统请求把容量capacity减小到和有效字符个数size一样大

注意,这只是一个请求,实际情况下即使用了该方法,capacity也不一定改变

string s2("hello world");
cout << s2.size() << endl; //11
cout << s2.capacity() << endl;//15 
s2.shrink_to_fit();
cout << s2.size() << endl; //11
cout << s2.capacity() << endl;//15 

clear()只能清空字符串,不会改变容量,这时再用shrink_to_fit就可以完美地将capacity置成0

6. reserve( )

在这里插入图片描述
请求更改容量
请求根据计划的大小更改调整字符串容量,长度最多为 n 个字符

reserve一般是用来提前申请空间的,有些情况下使用reserve可以很好地避免频繁扩容
因为缩容有不确定性
系统实际分配的空间都是略大于我们指定的n个字符的~

namespace ky
{
    class string
    {
    public:
        char& operator[](size_t pos)
        {
            assert(pos < _size);
            return _str[_size];
        }
        const char& operator[](size_t pos) const 
        {
            assert(pos < _size);
            return _str[_size];
        }
    private:
        //两段存储
        char _buff[16];//<16,存到对象本身里面,不用去堆上开空间,效率提高
        char* _str;//如果>=16个字符就到堆开辟空间存储,之前的_buff浪费掉,(以空间换时间),减少内存碎片,提高效率
        size_t _size;
        size_t _capacity;
    };
}
//扩容
void teststring4()
{
    这两行代码为了展示分段存储
    string s1("1111111");//_buff
    string s2("12152484845548848455");
    cout << s1.size() << endl; 7
    cout << s1.capacity() << endl; 15
    s2.reserve(40);//s2本身的size和capacity比40要大,但是reserve不会改变size和capacity,
    实际中reserve只用于扩容因为缩容不确定,比如这里capacity没有缩小到和size一样大,但是gcc下会缩容.
    cout << s2.size() << endl; 20
    cout << s2.capacity() << endl; 47


    string s;
    s.reserve(1000);//这里就是reserve的用武之地,下面就不会再扩容了,避免频繁扩容
    
    vs2022下的扩容规律 
    
    size_t old = s.capacity();
    cout << "capacity changed :" << old  << '\n';
    cout << "making s grow:\n";
    for (int i = 0; i < 100; ++i)
    {
        //s.push_back('c');
        s += 'c';
        if (old != s.capacity())
        {
            old = s.capacity();
            cout << "capacity changed: " << old << '\n';
        }
    }
}

在这里插入图片描述
在VS2022编译器下可以看出从_buff到 _str转换的时候是异地扩容,当_buff空间不够的时候把_buff复制下来在_str上开辟一块_buff 2倍的空间来存放原来_buff的数据,如果后面频繁扩容,就1.5倍扩容,这种扩容机制是由编译器底层决定的
例如,在gcc下就是2倍扩容

7. resize

在这里插入图片描述
在这里插入图片描述

void teststring5()
{
    string s5("hhhhhhhh");
    cout << s5.size() << endl;8
    cout << s5.capacity() << endl;15
    s5.resize(5);
    cout << s5.size() << endl;5
    cout << s5.capacity() << endl;15
    s5.resize(20);//扩容 + 插入null characters
    //原来的size数据不变,后面+ null characters
    cout << s5.size() << endl;20
    cout << s5.capacity() << endl;31
}

四、增删查改

1. push_back( )

在这里插入图片描述

int main()
{
    string s1;
    s1.push_back('x');
    s1.push_back('x');
    s1.push_back('x');
    cout << s1 << endl; // xxx
}

2. append( )

在这里插入图片描述

append是用于追加到字符串,也就是尾插
通过在字符串的当前值末尾附加其他字符来扩展字符串

 1. 追加整个字符串
int main() 
{
	string s1 = "hello";
	s1.append("w");
	s1.append("world");
	
	string s2("hello world");
	string s3("hello ky");
	s2.append(s3);
	cout << s2 << endl;	
}
2. 追加字符串的一部分
int main()
{
    string s1 = "hello";
    string s2 = "world";
    s1.append(s2, 0, 3);//从s2下标为0开始尾插三个字符
    cout << s1 << endl;
    
	  //取迭代器区间
	  string s2("hello world");
	  s1.append(s2.begin() + 6, s2.end());
	  cout << s1 << endl;

3. operator+=( )

在这里插入图片描述
operator+=( ) 也是追加字符,字符串,尾插到字符串末尾

 string s1;
 string s2 = "hahahahihihi"
 s1 += " ";
 s1 += "hahaha";
 s1 += s2;
 cout << s1 << endl;

4 . assign( )

在这里插入图片描述
assign( )和赋值差不多

    //赋值 string对象
    string s1 = "hello";
    string s2 = "world";
    s1.assign(s2); //将s2赋值给s1
    cout << s1 << endl; //world

    //赋值 常量字符串
    string s3 = "hello";
    s3.assign("world"); //将"world"赋值给s3
    cout << s3 << endl; //world
    
   //赋值 常量字符串的前n个字符
   string s4 = "hello";
   s4.assign("world", 2); //将"world"的前2个字符赋值给s4
   cout << s4 << endl; //wo

   //赋值 n个字符
   string s5 = "hello ";
   s5.assign(2, 'w'); //赋值2个'w'字符给s5
   cout << s5 << endl; //ww

   //赋值 string的子串
   string s6 = "hello";
   string s7 = "Syntactic sugar";
   s6.assign(s7, 3, 6); //赋值s7从下标为3的位置开始的6个字符给s6
   cout << s6 << endl; //tactic

5. insert( )

在这里插入图片描述
insert()是在指定位置插入字符或者字符串

insert一般用处不大,效率太低

int main()
{
    插入单个字符
    
    string s1 = "hello world";
    s1.insert(0, 3, 'h'); //下标为0的位置插入3个'h'
    cout << s1 << endl; //hehhh llo world

    string s2 = "hello world";
    s2.insert(s2.begin(), 'w'); //开始位置插入字符'x'
    cout << s2 << endl; //xhello world

    string s3 = "hello world";
    s3.insert(s3.begin(), 2, 'w'); //开始位置插入2个字符'w'
    cout << s3 << endl; //wwhello world
    
    插入字符串
   
	 //插入整个字符串
	 string s1 = "hello world";
	 s1.insert(2, "come"); //下标为2位置开始插入字符串"come"
	 cout << s1 << endl; //hecomello world
	
	 //插入字符串的一部分
	 string s2 = "hello world";
	 string s3 = "Syntactic sugar";
	 s2.insert(2, s3, 2, 7); //取s3字符串下标从2开始的7个字符插入s2下标为2的位置
	 cout << s2 << endl; //hentactic world
	
	 string s4 = "hello world";
	 s4.insert(2, "world", 2); //取world下标为0(默认)开始的2个字符插入到s4中下标为2的位置
	 cout << s4 << endl; //hewollo world

6. erase( )

在这里插入图片描述

从字符串中擦除字符
erase()是用于删除指定位置起的一个或若干个字符
这个效率也低

   string s("555555555555")
   s.erase(5, 3);//删除s下标从5开始的3个子符
   cout << s << endl;
   s.erase(5);删除s下标从5开始的后面的字符(直到npos)
   cout << s << endl;

   //都可以达到头删的效果
   s.erase(0, 1);
   s.erase(s.begin());

7. replace( )

在这里插入图片描述
replace是用新的字符或者字符串替换原字符串部分字符
效率也一般


    string s1("2222222");
    string s2("3333333333");
    s1.replace(0, 2, s2);把s1从下标为0开始的2个字符替换成s2
    cout << s1 << endl;
    cout << s2 << endl;
    
    string s1 = "hello world";
	s1.replace(2, 5, "xxxxxxxxxxxx"); //将s1从下标2开始的5个字符替换 
	//成"xxxxxxxxxxxx"
	cout << s1 << endl; //hexxxxxxxxxxxxorld
	
	string s4 = "hello world";
	s4.replace(2, 5, 3, '*'); //将s4下标从2开始的5个字符替换成3个'*'
	cout << s4 << endl; //he***orld
	
    //空格替换成%号 
    string s2("hello world hello c++");
    size_t pos = s2.find(' ');
    while (pos != string::npos)
    {
        s2.replace(pos, 1, "%%");//从下标为pos的位置开始的1个字符换成%%
        pos = s2.find(' ', pos + 2);//从替换的这里接着找不用从头再来
    }
    cout << s2 << endl;
    
    //以空间换时间,效率提高
    string s2("hello world hello c++");
    string s3;
    for (auto ch : s2)
    {
        if (ch == ' ')
            s3 += "%%";
        else
            s3 += ch;
    }
    cout << s3 << endl;

8. find( )

在这里插入图片描述

	//find会返回找到的字符串的首字符或者字符的下标
	string s1 = "hello world";
	size_t pos1 = s1.find("llo",1); //从下标1开始查找字符串"llo"
	cout << pos1 << endl; //2
	size_t pos2 = s1.find("llx", 1);
	cout << pos2 << endl; //找不到返回npos(size_t类型,值为-1,是一个很大的整数在X86下接近2个G)
 
	string s2 = "hello world";
	size_t pos3 = s1.find('l'); //默认从s2的第一个位置开始找'l'字符首次出现的位置,直到npos
	cout << pos3 << endl; //2

9. rfind( )

在这里插入图片描述

find()是从左到右查找,而rfind()是从右到左查找

10. substr( )

在这里插入图片描述
substr()用于获取子串,返回获取到的子串

	string s1 ="hello world";
	string s2 = s1.substr(1,3);//获取从下标为1开始的3个字符作为原字符串子串返回
	cout << s2 << endl;

	string s3 = s1.substr(1); //s1从下标为1开始取完赋值给s3
	cout << s3 << endl; //ello world
 
	string s4 = s1.substr(); //取完整个s1
	cout << s4 << endl; //hello world

	取后缀名就能用到substr
    string file("test.cpp");
    string file("test.cpp.tar.zip");//linux下取真实的后缀名;
    size_t pos = file.rfind('.');倒着找就可取最后一个真实的后缀名
    size_t pos = file.find('.');
    if (pos != string::npos)
    {
        //string str = file.substr(pos, file.size() - pos);
        string str = file.substr(pos);//直接用给的缺省值npos,直接取到结尾
        cout << str << endl;
    }

五 、输入getline( )

在这里插入图片描述

在控制台,终端上输入的数据是在缓冲区中的,如流提取,cin,scanf()实际中我们可能会输入多个数据,整型,string,
c/c++规定 空格和回车默认是分隔符
如果遇到空格就会认为当前串已经结束了,后面的数据就拿不到了,后面的内容是给下一个提取串的,只是我们还没有提取.

getline( ) 不指定分隔符,默认以回车结束,因此可以直接读取一行
也可以自定义终止符

#include<iostream>
#include<string>
using namespace std;
int main()
{
    string s1;
    cin >> s1;
    cout << s1 << endl;
    //abcdef T
    //取不到 T 遇到空格或回车自动结束

    string s1;
    string s2;
    cin >> s1;
    cin >> s2;
    cout << s1 << endl;
    cout << s2 << endl;

    string s;
    getline(cin, s);
    getline(cin, s,'#');//可以自定义终止符号

    cout << s << endl;

}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


标签:基本,string,s2,s1,cout,用法,字符串,size
From: https://blog.csdn.net/2301_79262802/article/details/144133418

相关文章

  • String类的三种常见构造方法
    1.根据构造方法创建字符串对象1.publicString()创建一个空字符串,里面不包含任何内容2.publicString(char[]chs)创建一个字符数组,将其拼接成字符串对象3.publicString(Stringoriginal)根据输入的字符串,创建字符串对象2.疑惑:1.我们原来创建了对象,将其直接打印,出来的是一......
  • How can I fix that my variable goes into the formatted string of my html code in
    题意:我该如何修复我的变量正确地插入到Python中HTML代码的格式化字符串中?问题背景:ForaprojectI'mrunningaraspberrypiPicowhbasedwebserverthatshouldgettheinputsofthetemperaturesensoranddisplayitonthewebsite.Iamhowevernotvery......
  • SQL注入--基本概念
    SQL注入的定义SQL:是操作数据库数据的结构化查询语言,网页的应用数据和后台数据库中的数据进行交互时会采用SQL。SQL注入:是将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以执行数据库命令。这时相当于用户控制了后端S......
  • Type definition error: [array type, component type: [simple type, class java.lan
     详细报错信息:Typedefinitionerror:[arraytype,componenttype:[simpletype,classjava.lang.String]];nestedexceptioniscom.fasterxml.jackson.databind.exc.InvalidDefinitionException:Cannotconstructinstanceof`java.lang.String[]`:noString-argu......
  • AspectRatio组件的用法
    文章目录1概念介绍2使用方法3示例代码我们在上一章回中介绍了CardWidget相关的内容,,本章回中将介绍AspectRatioWidget.闲话休提,让我们一起TalkFlutter吧。1概念介绍我们将要介绍的AspectRatioWidget是一个布局约束类组件,在二十一章回中介绍过这方面......
  • 函数与嵌套函数基本概念
    只要不输入中文,那么所有的参数以及标点都必须是英文输入法1、在单元格里直接输入=sum(sum大小写混搭都可以),双击下面弹出的SUM,会显示=SUM(),然后拖动要求和的单元格,看到公式=SUM(C2:E2),点击回车就能看到结果,可以往下拖动,也可以把鼠标放到第一个求和的单元格上,看到+,双击即可求出所有......
  • 0day圣乔E*P系统NamedParameterSingleRowQueryConvertor.queryForString.dwr存在SQL注
         0x01产品概述    圣乔E*P系统NamedParameterSingleRowQueryConvertor.queryForString.dwr存在SQL注入漏洞 通用描述管理和发布于一体的智能化平台,广泛应用于新闻、媒体和各类内容创作机构。该平台支持多终端、多渠道的内容分发,具备素材管理、编辑加工、智......
  • 泷羽sec学习--Burp Suite之基本介绍
     学习内容来自B站UP:泷羽sec微信公众号:泷羽sec一、基本介绍BurpSuite是一款用于Web应用程序安全测试的集成平台。它是由PortSwigger公司开发的,是渗透测试人员、安全研究人员和Web开发人员检查和分析Web应用程序安全问题的重要工具。它提供了一个直观的图形化界......
  • 硬盘的基本知识与选购指南
    1、3.5和2.5英寸硬盘的英寸,不是指外壳的尺寸,而是硬盘盘片的直径尺寸。无论是2.5英寸的硬盘还是3.5英寸的硬盘,都是使用SATA接口。1.1、3.5英寸3.5英寸的硬盘在1984年就已经诞生,直到在1991年出现首款容量为1GB的机械硬盘,3.5英寸硬盘开始成为标准规格。3.5英寸硬......
  • AI开发平台ModelArts-基本配置-在ECS中创建ma-user和ma-group
    在ModelArts训练平台使用的自定义镜像时,默认用户为ma-user、默认用户组为ma-group。如果在训练时调用ECS中的文件,需要修改文件权限改为ma-user可读,否则会出现Permissiondenied错误,因此需要在ECS中提前创建好ma-user和ma-group。在terminal中执行以下命令:default_user=$(gete......