C++(十六):STL之容器

容器

1. String

String是C++风格的字符串,其本质上是一个类,内部封装了char*。

1.1 构造函数与赋值函数

String作为一个类自然具有构造函数以及重载的operator=()函数,而这些函数则代表了一个string对象及有哪些初始化的方式。

首先,其构造函数包含以下几个:

  • string(); ------无参构造,用于创建一个空的字符串
  • string(const char* s);------一种有参构造,使用字符串常量对string类型对象进行初始化
  • string(const string& str);------拷贝构造,使用一个string对象初始化另一个对象
  • string(int n, char c);------使用n个字符c初始化string对象

具体使用方式可以参考曾经写过的类型初始化的文章,这里简单列举一下:

string s1;  //利用默认构造创建空的string对象
string s2("asbjkg");    //利用字符串常量初始化s2
string s3(s2);     //将s2的副本赋值给s3
string s4(3,'c');   //s4="ccc"

String赋值操作的函数有重载的operator=()函数和assign()函数:

  • string& operator=(const char* s);------利用字符串常量赋值
  • string& operator=(const string& s);------利用string对象赋值
  • string& operator=(char c);------利用字符赋值
  • string& assign(const char* s);------利用字符串常量赋值
  • string& assign(const char* s,int n);------将字符串s的前n个字符赋给当前对象
  • string& assign(const string& s);------将字符串s赋给当前字符串
  • string& assign(int n,char c);------将n个字符c赋值给string对象

示例:

string s1="sdks";
string s2=s1;
string s3='c';

string s4;
s4.assign("sohfs");
string s5;
s5.assign("fskhs",3);
string s6;
s6.assign(s5);
string s7;
s7.assign(3,'c');

以上示例分别对应前面所列举的赋值函数。

1.2 方法与函数

1.2.1 字符串拼接

这一节讲述如何在字符串尾部拼接另一个字符串。

具有此功能的函数包括重载的+=操作符:

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

PS:事实上,除了重载的+=操作符,还有重载的+运算符也可以进行字符串的拼接。
但是,如果用+运算符的话,必须保证+号左右两侧 至少有一个是string对象

string s1 = "sjkfks";
string s2 = "klll";
string s3 = s1 + s2;   //这是合法的
s3 = s1 + "fsf";       //这也是合法的,+号左侧为string对象
s3 = "fsdhjf" + s2;    //同样合法
s3 = "fsk" + "kjf";    //非法,因为均为字面值常量,无法自动转换为string对象

这种错误往往出现在连续+号的地方:

string s4 = "hello " + ',' + s1; //由于第一个+号左右两侧均为字面值常量,因此出现了错误

在这里我们需要切记的是,C++的string对象并不是字符串字面值,从以上的例子可以看出,它们并不是一个概念。往往我们可以用字符串字面值初始化string对象,这是因为编译器帮我们做了一个 隐式类型转换

以及append()函数:

  • string& append(const char* s);
    把字符串s连接到当前字符串尾部
  • string& append(const char* s,int n);
    把s的前n个字符连接到当前字符串的尾部
  • string& append(const string& s);
  • string& append(const string& s,int pos,int n);
    s中从pos开始的n个字符连接到字符串结尾

这里就不展示示例了。暂时没想到什么需要注意的点。

1.2.2 查找与替换

查找用于寻找指定的字符串是否存在;替换用于在指定的位置替换字符串。

查找的函数包括find(),rfind():

  • int find(const string& str, int pos=0) const;
    查找str第一次出现的位置,从pos开始找;pos默认从首位开始;返回str第一个字符所在的位置。
  • int find(const char* s,int pos = 0) const;
    查找字符串s第一次出现的位置,从pos开始找;pos默认从首位开始;返回s所在的位置。
  • int find(const char* s,int pos,int n) const;
    从pos位置开始查找s的前n个字符第一次出现的位置。
  • int find(const char c,int pos = 0) const;
    查找字符c第一次出现的位置,从pos开始查找;pos默认首位。
  • int rfind(const string& str, int pos = npos) const;
  • int rfind(const char* s, int pos = npos) const;
  • int rfind(const char* s, int pos, int n) const;
  • int rfind(const char c, int pos = 0) const;

注意,find()函数倘若没有找到想查找的字符串,则会返回-1。

find()与rfind()的区别在于 find()正向查找,而rfind()逆向查找

string str1 = "abcdefgdeg";

int pos_f = str1.find("de");
int pos_rf = str1.rfind("de");

cout << "pos_f= " << pos_f << endl;       //输出pos_f = 3
cout << "pos_rf= " << pos_rf << endl;     //输出pos_rf = 7

替换的函数为replace():

  • string& replace(int pos, int n, const string& str);
    替换从pos开始的n个字符为字符串str
  • string& replace(int pos, int n, const char* s);
string str1="abcdefg";
str1.replace(1,3,"4234");
cout << str1 << endl;  //输出为 a4234efg
1.2.3 字符串比较

字符串之间的比较是利用字符的ASCII码进行大小的判定的。具有以下几个规则:

  1. 如果两个string对象的长度不同,而且较短string对象的每个字符都与较长string对象对应位置上的字符相同,则认为较短的string对象小于较长的string对象;
  2. 如果两个string对象在某些对应的位置上不一致,则string对象比较的结果其实是第一对相异字符的比较结果;
  3. 字符的比较根据ASCII码进行判定。

比较函数是compare(),倘若相等则返回0;大于则返回1;小于则返回-1:

  • int compare(const string& s) const;
    与字符串s比较大小
  • int compare(const char* s) const;
    利用重载的运算符也可以比较两个字符串是否相等:
s1 == s2;
s1 != s2;
s1 < s2;
1.2.4 其余操作
  1. 单个字符的读写

string中单个字符的读写方式有两种:

  • char& operator[](int n);
    通过重载的[]运算符获取第n位的字符,下标从零开始计算。
  • char& at(int n);
    用法与[]类似,通过at方法进行字符的读取。

可以通过这两种方式读取string对象中的字符:

string s1 = "abcdefg";
for(int i = 0; i != s1.size(); ++i)
{
   
    //这两个的结果是一致的
    cout << s1[i] << endl;
    //cout << s1.at(i) << endl;
}

也可以通过这两种方式修改string对象中的字符:

s1[2] = s;
s1.at(3) = g;
  1. 插入与删除字符

插入和删除的函数为insert()与erase():

  • string& insert(int pos, const char* s);
    在指定的pos位置插入字符串s

  • string& insert(int pos, const string& str);

  • string& insert(int pos, int n, char c);
    在指定位置插入n个字符c

  • string& erase(int pos, int n=npos);
    删除从pos开始的n个字符

    示例:

    string s = "hello";
    s.insert(2,"qwer");   //输出为  heqwerllo
    cout << s << endl;    //可以看出,在第二个位置前即l之前插入了qwer
    s.erase(2,4);
    cout << s << endl;    //输出为hello
    
  1. empty()与size()方法

empty根据string对象是否为空返回一个对应的布尔值,如果为空,则返回true。
size返回string对象的长度。

对于size函数来说,其返回的值的类型并非int亦或unsigned,而是一个string::size_type类型值。
size_type是标准库定义的一个配套类型,体现了标准库类型与机器无关的特性。它是一个无符号类型值,且可以存放任何string对象的大小。理论上我们应该使用string::size_type类型存放size函数返的值。
因此,我们建议,如果一条表达式中已经有了size函数,就不要使用int了。这样可以避免混用int和unsigned可能带来的问题,比如若n < 0,则s.size() < n几乎可以肯定是true了,因为负值n会自动换为较大的无符号值。这还是该死的类型转换带来的问题。

  1. 处理string对象中的字符

上面说过如何通过[]运算符和at()方法读取string对象的字符,这边讲的是一些处理字符相关的函数。
头文件cctype中定义了一组标准库函数处理这些工作。

函数名
功能
isalnum(c) 当c是字母或数字时为真
isalpha(c) 当c是字母时为真
iscntrl(c) 当c是控制字符时为真
isdigit(c) 当c是数字时为真
isgraph(c) 当c不是空格但可以打印时为真
islower(c) 当c是小写字母时为真
isprint(c) 当c是可打印字符时为真
ispunct(c) 当c是标点符号时为真
isspace(c) 当c是空白时为真
isupper(c) 当c是大写字母时为真
isxdigit(c) 当c是16进制数时为真
tolower(c) 若c是大写字母,将其变为小写字母;否则原样输出
toupper(c) 与tolower相反的操作

如果想对string对象中的每个字符做点啥操作,目前最好的办法是利用C++11提供的范围for语句

//一个例子
for(auto &c : str)
{
   
  c=toupper(c);   //将str中每个字符变为大写
}

如果想对string对象的一部分进行操作,那么可以使用下标索引和迭代器

其实严格地说string对象不属于容器类型,但是string对象支持很多与容器类似的操作,迭代器就是一个例子。迭代器的使用目前还未学习,将会放在以后写下来。

  1. 子串获取

string对象的子串获取可以使用substr()方法。

  • string substr(int pos=0, int n=npos);
    返回由pos开始的n个字符组成的字符串

这是一个比较实用的方法,比如说如果我们有很多邮箱账号,然后我们需要截取所有邮箱账号的用户名就可以用这个方法。

string str = "zhangsan@qq.com";
int pos = find('@');
string subs = str.substr(0,pos);

2. Vector

Vector数据结构与数组很相似,但是vector可以动态扩展,而数组是一段静态的空间。

所谓动态扩展,并非是在原空间后接续新空间,而是寻找跟大的新空间,将原数组拷贝到新空间并释放原空间。这一点与之前设计的指针控制的数组有相似之处。

Vector本身是一段左闭右开的链式内存区间,它只支持在容器的尾部添加元素。
另外,vector的迭代器是支持随机访问的迭代器。

2.1 构造函数与赋值函数

vector的构造函数的原型大概有这么几种:

  • vector<T> v;
    默认构造函数,采用模板制作的类。
  • vector(v.begin(),v.end());
    将v的begin()到end()区间内的元素拷贝过来,区间范围是左开右闭
  • vector(n,elem);
    构造函数将n个elem拷贝给本身。
  • vector(const vector &vec);
    拷贝构造函数。

示例:

vector<int> v1;   //默认构造函数构建一个空的对象
for(int i=0; i!=10;++i)
{
   
  v1.push_back(i);   //利用push_back方法在容器尾部添加元素
}                    //这样就构造了一个含有十个元素的vector<int>对象

vector<int> v2(v1.begin(),v1.end(
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值