1.1 C
语言中的字符串
C
语言中,字符串是以
'\0'
结尾的一些字符的集合,为了操作方便,
C
标准库中提供了一些
str
系列
的库函数,但是这些库函数与字符串是分离开的,不太符合
OOP
的思想,而且底层空间需要用户
自己管理,稍不留神可能还会越界访问。
2.1 string
类
(
了解
)
在
使用
string
类时,必须包含
#include
头文件以及
using namespace std
;
2.2 auto
和范围
for
auto
关键字
在这里补充
2
个
C++11
的小语法,方便我们后面的学习。
在早期
C/C++
中
auto
的含义是:使用
auto
修饰的变量,是具有自动存储器的局部变量,后来这个
不重要了。
C++11
中,标准委员会变废为宝赋予了
auto
全新的含义即:
auto
不再是一个存储类型
指示符,而是作为一个新的类型指示符来指示编译器,
auto
声明的变量必须由编译器在编译时期
推导而得
。
用
auto
声明指针类型时,用
auto
和
auto*
没有任何区别,但用
auto
声明引用类型时则必须加
&
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际
只对第一个类型进行推导,然后用推导出来的类型定义其他变量
。
auto
不能作为函数的参数,可以做返回值,但是建议谨慎使用 ,
auto
不能直接用来声明数组
范围
for
对于一个
有范围的集合
而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此
C++11
中引入了基于范围的
for
循环。
for
循环后的括号由冒号
“
:
”
分为两部分:第一部分是范围
内用于迭代的变量,第二部分则表示被迭代的范围
,自动迭代,自动取数据,自动判断结束。
范围
for
可以作用到数组和容器对象上进行遍历
范围
for
的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。
#include<iostream>
using namespace std;
int main()
{
int array[5] = { 1,2,3,4,5 };
for (auto e : array)
{
e *= 2;
}
int array2[5] = { 1,2,3,4,5 };
for (auto& e : array2)
{
e *= 2;
}
return 0;
}
可以看到这两个代码中一个auto是采用引用,一个并没有,导致数组中的内容没有被修改.

2.3 string
类的常用接口说明

#include<iostream>
using namespace std;
int main()
{
string s1;//创建对象
string s2("hello");//创建对象并初始化
string s3(s2);//拷贝构造
return 0;
}
函数名称
功能说明
size
(重点)
返回字符串有效字符长度
length
返回字符串有效字符长度
capacity
返回空间总大小
empty
(重点)
检测字符串释放为空串,是返回
true
,否则返回
false
clear
(重点)
清空有效字符
reserve
(重点)
为字符串预留空间
*
*
resize
(重点)
将有效字符的个数该成
n
个,多出的空间用字符
c
填充
2.
string
类对象的容量操作
注意:
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
的底层空间总大小时,
reserver
不会改变容量大小。
接口代码的实现
#include<iostream>
using namespace std;
int main()
{
string s1;//创建对象
string s2("hello");//创建对象并初始化
string s3(s2);//拷贝构造
cout << s2.size ()<< endl;
cout << s2.length() << endl;
cout << s2.capacity() << endl;
bool ret = s1.empty();
cout <<"s1是否为空" << ret << endl;
// 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
s2.clear();
cout <<"s2的数据 " << s2 << endl;
cout << s2.size() << endl;
cout << s2.capacity() << endl;
// 将s中有效字符个数增加到10个,多出位置用'a'进行填充
s2.resize(10, 'a');
cout <<"s2的数据 "<<s2 << endl;
cout << s2.size() << endl;
cout << s2.capacity() << endl;
return 0;
}
运行结果:
3.
string
类对象的访问及遍历操作
函数名称
功能说明
operator[]
(重点)
返回
pos
位置的字符,
const string
类对象调用
begin
+
end
begin
获取一个字符的迭代器
+
end
获取最后一个字符下一个位
置的迭代器
rbegin
+
rend
begin
获取一个字符的迭代器
+
end
获取最后一个字符下一个位
置的迭代器
范围
for
C++11
支持更简洁的范围
for
的新遍历方式
代码接口的实现
#include<iostream>
using namespace std;
int main()
{
string s1("hello");
for (int i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";//使用重载的[]来访问s1
}
cout << endl;
string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it << " ";
++it;//使用迭代器进行遍历
}
cout << endl;
// C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
auto rit = s1.rbegin();//c从末尾到前面进行遍历
while (rit != s1.rend())
{
cout << *rit << " ";
++rit;
}
cout << endl;
return 0;
}
运行结果:

4.
string
类对象的修改操作
函数名称
功能说明
push_back
在字符串后尾插字符
c
append
在字符串后追加一个字符串
operator+=
(
重点)
在字符串后追加字符串
str
c_str
(
重点
)
返回
C
格式字符串
find
+
npos
(
重点)
从字符串
pos
位置开始往后找字符
c
,返回该字符在字符串中的
位置
rfind
从字符串
pos
位置开始往前找字符
c
,返回该字符在字符串中的
位置
substr
在
str
中从
pos
位置开始,截取
n
个字符,然后将其返回
注意:
1.
在
string
尾部追加字符时,
s.push_back(c) / s.append(1, c) / s += 'c'
三种的实现方式差不多,
一般情况下string
类的
+=
操作用的比较多,
+=
操作不仅可以连接单个字符,还可以连接字符串。
2.
对
string
操作时,如果能够大概预估到放多少字符,可以先通过
reserve
把空间预留好
代码接口的实现
void Teststring5()
{
string str;
str.push_back(' '); // 在str后插入空格
str.append("hello"); // 在str后追加一个字符"hello"
str += 'b'; // 在str后追加一个字符'b'
str += "it"; // 在str后追加一个字符串"it"
cout << str << endl;
cout << str.c_str() << endl; // 以C语言的方式打印字符串
// 获取file的后缀
string file("string.cpp");
size_t pos = file.rfind('.');
string suffix(file.substr(pos, file.size() - pos));
cout << suffix << endl;
// npos是string里面的一个静态成员变量
// static const size_t npos = -1;
// 取出url中的域名
string url("http://www.cplusplus.com/reference/string/string/find/");
cout << url << endl;
size_t start = url.find("://");
if (start == string::npos)
{
cout << "invalid url" << endl;
return;
}
start += 3;
size_t finish = url.find('/', start);
string address = url.substr(start, finish - start);
cout << address << endl;
// 删除url的协议前缀
pos = url.find("://");
url.erase(0, pos + 3);
cout << url << endl;
}