C++入门篇之string使用

Posted 捕获一只小肚皮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++入门篇之string使用相关的知识,希望对你有一定的参考价值。

前言

此篇文章主要是讲解的容器之一—string,内容分为对象构造,容量操作,访问遍历,修改操作及其非成员函数,下面博主就一一介绍.


basic_string模板介绍

不是说今天的主角是string吗,为什么要介绍basic_string呢?因为我们需要知道string到底是什么,以及怎么来的.现在我们打开C++文档,发现basic_string是一个类模板,定义如下:

template < class charT,
           class traits = char_traits<charT>,    // basic_string::traits_type
           class Alloc = allocator<charT>        // basic_string::allocator_type
           > class basic_string;

也就是说,basic_string有三个模板参数,后两个都有缺省值,然后我们再打开string的文档,查看发现如下:

typedef basic_string<char> string;

这说明了什么呢?原来string是通过basic_string类模板进行实例化出来的一个类,其显示调用的时候,告诉编译器charT类型是char,另外两个类型就是默认缺省值,然后编译器通过该类型进行推演出了一个对应的类,而该类就是string.

也就是说,string只是basic_string的一个推演实例之一.


string的对象构造(初始化)

我们现在已经知道了string是通过模板实例化出来的类,那么也就会定义一个string类对象了,比如:

string s1;
string s2;

注意点:使用string必须要包头文件,即写上#include <string>,此外如果不写using namespace std;,定义对象会有差别.

有全局空间展开时候:

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

无全局空间展开时候:

#include <string>
std::string s1;

知道了怎么定义string对象,那怎么对其进行初始化呢?C++目前提供了8种以上的接口,博主这里挑最常用的4个给大家进行讲解,分别是:

构造函数样例功能说明
string()构造空的string类对象,即空字符串
string(const char s)*常量字符串或字符数组来构造string类对象
string(const string& s)拷贝构造函数
string(size_t n,char c)string类对象中包含n个字符c

string()

空对象,即创造对象时候,没有任何值.

string s;  //s就是一个空字符串

string (const char* s)

即可以传入常量字符串或者char数组.

string s1("123456");   //s1的内容就是123456
char str[20] = "hello you~";
string s2(str);       //s2的内容就是hello you~

string(const string& s)

即还可以传同类型的 string对象.

string s("hello~");
string s1(s);        //s1 的内容和s一模一样 

string(size_t n,char c)

把n个字符c组成的字符串赋给对象.

string s0(6,'a');   //s0的内容就是"aaaaaa"
string s1(4,'p');   //p的内容就是"pppp"


string的容量操作

什么叫容量操作呢?顾名思义,就是对string的大小进行操作,比如访问,缩减,增加等,同样的,博主还是选取最常用的接口进行讲解,主要如下:

函数名称功能说明
size()返回有效字符串长度
capacity()返回string对象的容量
empty()检测string对象是否为空
clear()情况对象内容
resize()改变长度
reserve()预留容量

size()和capacity()

文档定义分别为:size_type size() const;size_type capacity() const;

string s("12345");   //定义对象s,并初始化为12345
cout<<"size为:"<<s.size()<<endl;                 //返回有效字符串大小
cout<<"capacity为:"<<s.capacity()<<endl;         //返回对象的容量

测试:

能够发现capacity和size是不一样的,那侧面来说我们就能够知道string的底层实现是用的顺序表.


empty()和clear();

官方文档定义分别为:bool empty() const;void clear();

string s("12345");
cout<<"string对象s是否为空?"<<s.empty()<<endl;           //判空
s.clear();
cout<<"清空以后的s内容是否为空?"<<s.empty()<<endl;         //判空

测试:

注意哦~,clear清理的是size,即有效字符长度,而capacity并没有变.


resize()

对于resize来说,官方给了其两个重载函数,分别定义如下:

  • void resize (size_t n); 让对象有效字符串大小变为n.
  • void resize (size_t n, char c); 让对象有效字符串大小变为n.

咦~,怎么是一样的功能呢?其实博主觉得可以分情况讲上述两种定义进行综合,什么意思呢?

  • 当n小于原来的字符串大小时候,那么resize就相当于变成void resize (size_t n);,即只会缩短到n长度
  • 当n大于原来的字符串大小时候,那么resize就相当于变成void resize (size_t n, char c = '\\0');,即多出来的部分,用c初始化

注意哦~,博主上面说的分情况是指可以这样理解,并不是真的变成这样了,只是为了把官方文档的所有功能进行综合一下.

string s("1234567");
cout <<"原字符串:                     "<< s << endl;
s.resize(5);         //小于原长度7,说明s变成了12345;
cout <<"缩减成5个长度后:              " << s << endl;
s.resize(9);         //大于原长度5,且只输入了一个参数,说明多出来的4个空间,全部用'\\0'初始化了.
cout <<"增加长度到9,但是用的\\\\0初始化: " << s << endl;
s.resize(13, 'x');    //大于原长度9,且传入了两个参数,多出来的4空间则用字符'x'初始化.
cout <<"增加长度到13,用x初始化:       " <<s << endl;
s.resize(3,'p');     //小于原长度13,即相当于缩减,那么传入的字符'p'无效.
cout <<"缩减后的字符串:              "<<s<<endl;

测试:

注意哦,resize()该表的大小并不是capacity哦,而是size,即有效字符串大小,至于capacity是否会改变则是根据实际情况而定.


reserve()

官方文档定义如下: void reserve (size_t n = 0);

其作用是预先改变capacity,记住哦~,这里和resize不一样,并且只有n大于原来capacity才起效果,效果指的是编译器可能会把capacity调整到大于等于n的地步.

string s("123456");
cout<<"原capacity为:"<<s.capacity()<<endl;
s.reserve(8);   //8小于原来的capacity(一般默认为15或20),则没有效果.
cout<<"现capacity为:"<<s.capacity()<<endl;
s.reserve(60);  //60大于原来的capacity,起效果
cout<<"现capacity为:"<<s.capacity()<<endl;
cout<<"现在的s为:"<<s<<"----说明capacity的改变并不会引起有效字符串的改变"<<endl;

测试:


string的访问和遍历操作

说了对象的定义初始化,以及其容量操作后,那么我们怎么进行访问其单个元素呢?C++也提供了3种方法:分别是迭代器,[],以及范围遍历;

大概操作有以下:

函数名称功能说明
operator[n]获取第n个字符
begin + endbegin获取第一个字符位置迭代器,end获取最后一个字符的下一个位置迭代器
rbegin + rendrbegin获取最后一个字符的下一个位置迭代器,rend获取第一个字符位置迭代器
范围for一种新的C++遍历形式

[]形式访问

官方文档定义了两个重载:

  • char& operator[] (size_t pos);
  • const char& operator[] (size_t pos) const;

大部分时候我们调用的是第一个,但如果是const修饰的string对象,则会调用第二个.

string s("123456");
const string s1("123456");
for (int i = 0; i < s.size(); i++) {
    cout << s[i] << " ";              //调用的第一个
}
cout << endl;

s1[0] = '9';   //这里就会报错,以为s1[0]调用的是第二个,不允许对象修改.

迭代器访问

由于我们才刚开始接触迭代器,对于迭代器的概念理解有点困难,因此在目前阶段我们可以将其理解成指针.

目前我们最常用的迭代器有4个,分别是begin(),end(),rbegin(),rend();,我称作为pp;

string迭代器语法:

string::iterator name = object.pp;   //创建迭代器,并初始化
*name   //通过迭代器访问

示例:

string s("123456");
string::iterator itb = s.begin();
string::iterator ite = s.end();
while(itb != ite) 
{
    cout<<*itb<<" "; 
    itb++;
}
cout<<endl;

测试:


const迭代器和reverse迭代器

对于const修饰的string对象,则需要给迭代器类型加上const_,例如:

const string s("123456");
string::const_iterator it = s.begin();

如果我们赋值的是rbegin()rend(),则需要给迭代器类型加上revese_

string s("123456");
string::reverse_iterator it = s.rbegin();

而reverse迭代器主要用来倒着遍历,如下:

string s("123456");
string::reverse_iterator itb = s.rbegin();
string::reverse_iterator ite = s.rend();
while(itb!=ite)
{
    cout<<*itb<<" ";
    itb++;
}

测试:


范围遍历

范围遍历的格式如下:

for(type i : object)
{}

其中i可以是任何名字,而i就是object中的单个元素,object是对象,因为博主比较懒,type博主喜欢用auto

示例:

string s("123456");
for(auto i : s)
{
    cout<<i<<' ';
    i += 1;             //这一步并没有用,因为i的类型不是auto&
}
cout<<endl;
cout <<s<<endl;

for(auto& i : s)
{
    i += 1;             //现在有用了
}
cout <<s<<endl;

测试:


string的查找和修改

在c语言中,我们知道字符串的查找和修改操作在生活中使用比较频繁,那么到了C++这里,怎么能少掉这些操作呢?

我们就看看string有哪些主要操作:

函数名称作用说明
push_back()在对象末尾插入字符
append()在对象末尾添加字符串
operator+=给对象拼接字符串或字符
c_str()把string对象转为c格式字符串,如char*
find + npos从某一位置开始向后查找
rfind()从某一位置开始向前查找
substr()获取子串

push_back()

官方文档定义:void push_back (char c);,即在原对象末尾添加一个字符.

string s("abcde");
s.push_back('1');
s.push_back('2');
s.push_back('3');
cout<<s<<endl;

结果:


append()

对于append,官方文档给出了7个重载,博主这里便挑选出最常用的几个,分别是:

  • string& append (const string& str); 末尾添加string对象.
  • string& append (const char* s); 末尾添加c格式字符串
  • string& append (const char* s, size_t n); 末尾添加字符串的前n个字符.
  • string& append (size_t n, char c); 末尾添加n个字符c

示例:

string s1("123456");
string s2("abcd");
s1.append(s2);   // 末尾添加string对象

char str[10] = "++2233++";
s1.append(str);   //末尾添加c格式字符串
s1.append(str,3);   //末尾添加str的前3个字符给s1
s1.append(5,'0');

cout<<s1<<endl;

结果:


operator+=

官方文档定义如下:

string& operator+= (const string& str);

string& operator+= (const char* s);

string& operator+= (char c);

往简单的说,就是其支持拼接字符和字符串

string s("abcd");
string s1("qqq");
s += ' ';                //   拼接一个空格
s += "1234 ";            //   拼接字符串
s += s1;                 //   拼接string对象,其实也是字符串
cout<<s<<endl;

结果:


c_str()

有时候函数形参并不是string对象,而是c格式字符串,那么传入string对象则会报错,为了解决这种麻烦,便提供了该接口.

示例:

string s("abcdef");
char* str = new char[s.size()+1];
strcpy(str,s.c_str());
cout<<str<<endl;

测试:


find()

在介绍该接口之前,我们先介绍string中的一个值npos,其定义为static const size_t npos = -1;,也就是说npos是整型最大值.

而find()虽然有很多重载,但是其返回值为,如果找到目标,就返回目标出现的第一个位置.如果找不到就返回size_t类型的-1,也就是npos.

官方文档定义的几种最常见的重载:

size_t find (const string& str, size_t pos = 0) const;

size_t find (const char* s, size_t pos = 0) const;

size_t find (char c, size_t pos = 0) const;

上面3种大家可以记忆成,只有3个参数,一个是传字符串或者字符,一个是传开始查找的位置,如果不穿,默认从0开始.

size_t find (const char* s, size_t pos, size_t n) const;

传C格式的字符串,从pos位置开始,查找s的前n个字符.

string s("hello world");
string s1("rld");
cout<<s.find("llo")<<endl;        //从0位置开始查找
cout<<s.find(s1,4)<<endl;         //从4位置开始查找
cout<<s.find('h',3)<<endl;        //从3位置开始查找
cout<<s.find("world",5,2)<<endl;     //从5位置开始,查找是否存在"wo"

结果:


rfind()

rfind的用法和find一模一样,只是大家需要在注意一点的是,rfind()查找方向是右向左.


substr()

官方文档定义如下:string substr (size_t pos = 0, size_t len = npos) const;

即返回对象从pos位置开始,长度为len个的子串.len如果不写,则默认是从pos位置开始,一直到末尾.

string s("123456789");
string s1 = s.substr(3,4);     //从位置3开始,向后获取长度为4的子串
string s2 = s.substr();        //从0位置开始,获取整个字符串
string s3 = s.substr(6);       //从6位置开始获取后面所有与字符串
cout<<s1<<endl;
cout<<s2<<endl;
cout<<s3<<endl;

结果:


以上是关于C++入门篇之string使用的主要内容,如果未能解决你的问题,请参考以下文章

C++入门篇之引用,内联函数,auto和范围遍历

C++入门篇之6大默认函数

C++入门篇之关键字,命名空间,输入输出和函数重载

C++入门篇之内存处理

C++入门篇之内存处理

C++入门篇之模板基础讲解