using声明
- 使用using声明:例如
using std::cin
表示使用命名空间std
中的名字cin
。 - 头文件中不应包含
using
声明。这是因为每个使用该头文件的内容会拷贝到所有它的文件中去,可能会产生始料未及的名字冲突。
string类型
-
标准库类型
string
表示可变长的字符序列。 -
使用string类型必须先包含string头文件,再使用命名空间。例如
#include <string> using std::string;
-
string对象:注意,不同于字符串字面值。
string对象和字符串字面值有什么区别
1.C字符串是const char * 类型,而string是标准库类型, 2.当在操作文件时,这种区别就很明显了,打开文件时的文本名一定是const char*类型的,而如果用的是string类型时就会出错 4.c的字符串头文件是#include<string.h>或者#include<cstring> 5.stl的string头文件是#include<string> 而且在命名空间std中。 6.string是STL模板里面使用vector来编写的,char*是以'\0'结尾 但是string不是的 7.string里隐含了个char *指针,这个指针指向真正存放字符串字面值的内存地址。 8.std::string类型只是basic_string<>的一个char特化。也就是说,string相当于一个容器,里面维护了很多的char。
定义和初始化string对象
初始化string
对象的方式:
方式 | |
---|---|
string s1 |
默认初始化,s1 是个空字符串 |
string s2(s1) |
s2 是s1 的副本 |
string s2 = s1 |
等价于s2(s1) ,s2 是s1 的副本 |
string s3("value") |
s3 是字面值“value”的副本,除了字面值最后的那个空字符外 |
string s3 = "value" |
等价于s3("value") ,s3 是字面值"value"的副本 |
string s4(n, 'c') |
把s4 初始化为由连续n 个字符c 组成的串 |
- 拷贝初始化(copy initialization):使用等号
(=)
初始化一个变量,编译器把等号右侧的初始值拷贝到新创建的对象中去。 - 直接初始化(direct initialization):与上面相反,不使用等号。
string对象上的操作
string的操作 | |
---|---|
os << s |
将s 写到输出流os 当中,返回os |
is >> s |
从is 中读取字符串赋给s ,字符串以空白分割,返回is |
getline(is, s) |
从is 中读取一行赋给s ,返回is |
s.empty() |
s 为空返回true ,否则返回false |
s.size() |
返回s 中字符的个数 |
s[n] |
返回s 中第n 个字符的引用,位置n 从0计起 |
s1+s2 |
返回s1 和s2 连接后的结果 |
s1=s2 |
用s2 的副本代替s1 中原来的字符 |
s1==s2 |
如果s1 和s2 中所含的字符完全一样,则它们相等;string 对象的相等性判断对字母的大小写敏感 |
s1!=s2 |
同上 |
< , <= , > , >= |
利用字符在字典中的顺序进行比较,且对字母的大小写敏感: |
读写string对象
-
在执行读操作(
>>运算符
)时:string对象会自动忽略掉开头的空白(包括空格符、换行符和制表符),并从第一个真正的字符开始读起,直到遇到下一处空白为止。 -
getline
:读取一整行,包括空白符和换行符,然后把所读的内容存入到那个string对象中去(不存换行符)。 -
end
操作符结束当前行并刷新显示缓冲区 -
再说一遍,字符串字面值和string是不同的类型。
请说明string类的输入运算符和getline函数分别是如何处理空白字符的。
1.类似 is >> s 的读取:string对象会忽略开头的空白并从第一个真正的字符开始,直到遇见下一空白为止。
2.类似 getline(is, s) 的读取:string对象会从输入流中读取字符,直到遇见换行符为止。
处理string对象中的字符
处理每个字符
-
范围for(range for)语句:
for (auto c: str)
,或者for (auto &c: str)
使用引用直接改变字符串中的字符。 (C++11) -
下标运算符
[ ]
接受的输入参数是string::size_type类型(无符号类型)的值 -
string对象的下标必须大于等于0而小于s.size()
-
某个索引是带符合类型的值将会自动转换成string::size_type类型表达的无符号类型
-
在使用下标运算符时可以总是设下标的类型为string::size_type类型,可以确保下标不会小于0,此时,代码只需保证下标小于size( )的值就可以了
下面的程序有何作用?它合法吗?如果不合法?为什么?
string s; cout << s[0] << endl;
不合法。使用下标访问空string是非法的行为,会引发不可预知的结果。
下面的范围for语句合法吗?如果合法,c的类型是什么?
const string s = "Keep out!";
for(auto &c : s){ /* ... */ }
要根据for循环中的代码来看是否合法,c是string 对象中字符的引用,s是常量。因此如果for循环中的代码重新给c赋值就会非法,如果不改变c的值,那么合法。
vector类型
-
vector表示对象的集合,是一个容器,也是一个类模板;
-
使用string类型必须先包含vector头文件,再使用命名空间。例如
#include <vector> using std::vector;
-
容器:容纳着其他对象。
-
模板本身不是类或函数,编译器生成类或函数编写的一份说明,这个过程称为实例化(instantiation) 。例如,vector
是一个模板,
vector< int >是一个类
,该类必须由vector生成并包含vector中元素的类型 -
通过将类型放在类模板名称后面的尖括号中来指定类型,如
vector<int> ivec
-
因为引用不是对象,所以不存在包含引用的vector
定义和初始化vector对象
初始化vector
对象的方法
方法 | |
---|---|
vector<T> v1 |
v1 是一个空vector ,它潜在的元素是T 类型的,执行默认初始化 |
vector<T> v2(v1) |
v2 中包含有v1 所有元素的副本 |
vector<T> v2 = v1 |
等价于v2(v1) ,v2 中包含v1 所有元素的副本 |
vector<T> v3(n, val) |
v3 包含了n个重复的元素,每个元素的值都是val |
vector<T> v4(n) |
v4 包含了n个重复地执行了值初始化的对象,例如:vector< int > v4(10); //v4有10个元素,每个元素的值都是0 |
vector<T> v5{a, b, c...} |
v5 包含了初始值个数的元素,每个元素被赋予相应的初始值,例如:vector< int > v5{10}; //v5有1个元素,该元素的值是10 |
vector<T> v5={a, b, c...} |
等价于v5{a, b, c...} |
-
vector可以作为对象附加,前提是对象类型必须相同
-
列表初始化:只能把初始值都放在花括号里进行列表初始化,而不能放在圆括号里,例如:
vector<string> v{"a", "an", "the"};
(C++11) -
如果用的是圆括号,可以说是提供值用来构造vector对象
-
如果用的是花括号,可以表述成我们想礼拜初始化该vector对象
-
另一方面,如果初始化时使用了花括号的形式但是提供的值又不能用来列表初始化,就要考虑编译器是否要用这样的值来初始化vector对象,例如
vector<string> v6("hi"); //错误,不能使用字符串字面值来构造vector对象
vector<string> v7{
10}; //v7有十个默认初始化的元素
vector<string> v8{
10,"hi"}; //v8有十个值为"hi"的元素
向vector对象中添加元素
v.push_back(e)
在尾部增加元素。- 范围for语句体内不应改变其所遍历序列的大小
其他vector操作
vector
支持的操作
操作 | |
---|---|
v.emtpy() |
如果v 不含有任何元素,返回真;否则返回假 |
v.size() |
返回v 中元素的个数 |
v.push_back(t) |
向v 的尾端添加一个值为t 的元素 |
v[n] |
返回v 中第n 个位置上元素的引用 |
v1 = v2 |
用v2 中的元素拷贝替换v1 中的元素 |
v1 = {a,b,c...} |
用列表中元素的拷贝替换v1 中的元素 |
v1 == v2 |
v1 和v2 相等当且仅当它们的元素数量相同且对应位置的元素值都相同 |
v1 != v2 |
同上 |
< ,<= ,> , >= |
以字典顺序进行比较 |
- 要使用size_type,首先要指定它是由哪种类型定义的,vector对象的类型总是包含着元素的类型,例如:
vector<int> ::size_type;
vector
对象(以及string
对象)的下标运算符,只能对确知已存在的元素执行下标操作,不能用于添加元素。
下面的程序合法吗?如果不合法,你准备如何修改?
vector<int> ivec;
ivec[0] = 42;
不合法。应改为:
ivec.push_back(42);
如果想定义一个含有10个元素的vector对象,所有元素的值都是42,请例举三种不同的实现方法,哪种方式更好呢?
1.vector<int> ivec1(10, 42);
2.vector<int> ivec2{
42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
3.vector<int> ivec3;
for (int i = 0; i < 10; i++)
ivec3.push_back(42);
第一种方式最好。