C++Primer读书笔记----第三章标准库类型

第三章 标准库类型

两种最重要的标准库类型是 string 和 vector。string 类型支持长度可变的字符串,vector 可用于保存一组指定类型的对象。

另一种标准库类型 bitset,提供了一种抽象方法来操作位的集合。与整型值上的内置位操作符相比,bitset 类类型提供了一种更方便的处理位的方式。

3.1 命名空间的using声明

using namespace::name

using std::cin;

每个名字都需要一个 using 声明,一个 using 声明一次只能作用于一个命名空间成员。

using std::cin;
using std::cout;
using std::endl;

 

3.2 标准string类型

string 类型支持长度可变的字符串,C++ 标准库将负责管理与存储字符相关的内存,以及提供各种有用的操作。

#include <string>
using std::string;

 

string 对象的定义和初始化

string s1;       默认构造函数 s1 为空串
string s2(s1);     将 s2 初始化为 s1 的一个副本
string s3("value");   将 s3 初始化为一个字符串字面值副本
string s4(n, 'c');    将 s4 初始化为字符 'c' 的 n 个副本

 

string对象的读写

string s;   // empty string
cin >> s;   // read whitespace-separated string into s
cout << s << endl; // write s to the output
return 0;

  cin<<s;

  •   读取并忽略开头所有的空白字符(如空格,换行符,制表符).
  •       读取字符直至再次遇到空白字符,读取终止。

读入未知数目的string 对象

  while (cin >> word)

  cout << word << endl;

 

使用getline 读取整行文本

while (getline(cin, line))
cout << line << endl;由于 getline 函数返回时丢弃换行符,换行符将不会存储在 string 对象中。

 

string对象的操作

s.empty()   //如果 s 为空串,则返回 true,否则返回 false。
s.size()   //返回 s 中字符的个数
s[n]   //返回 s 中位置为 n 的字符,位置从 0 开始计数
s1 + s2   //把 s1 和s2 连接成一个新字符串,返回新生成的字符串
s1 = s2   //把 s1 内容替换为 s2 的副本
v1 == v2  //比较 v1 与 v2 的内容,相等则返回 true,否则返回 false
!=, <, <=, >, and >=   //保持这些操作符惯有的含义

 

string::size_type 类型 

size() 成员函数似乎应该返回整形数值,无符号整数。但事实上,size 操作返回的是 string::size_type 类型的值。

 

string 关系操作符

string 对象比较操作是区分大小写的。在多数计算机上,大写的字母位于小写之前:任何一个大写之母都小于任意的小写字母。

== 操作符比较两个 string 对象,长度相当并且含有相同字符

 

string 对象的赋值

标准库类型尽量设计得和基本数据类型一样方便易用。因此,大多数库类型支持赋值操作。对 string 对象来说,可以把一个 string 对象赋值给另一个 string 对象;

  string st1, st2 = "The expense of spirit";
  st1 = st2; // replace st1 by a copy of st2

赋值操作需要做一些工作。它必须先把 st1 占用的相关内存释放掉,然后再分配给 st2 足够存放 st2 副本的内存空间,最后把 st2 中的所有字符复制到新分配的内存空间。

 

两个string 对象相加

string s3 = s1 + s2;        s1 += s2;

 

和字符串字面值的连接

string s4 = "hello" + ", "; // error: no string operand

string s6 = "hello" + ", " + s2; // error: can't add string literals

 

从string 对象获取字符

string 类型通过下标操作符([ ])来访问 string 对象中的单个字符。下标操作符需要取一个 size_type 类型的值,来标明要访问字符的位置。

  string str("some string");
  for (string::size_type ix = 0; ix != str.size(); ++ix)
    cout << str[ix] << endl;

在使用下标索引 string 对象时,必须保证索引值“在上下界范围内”。

 

string 对象中字符的处理

这些函数都在 cctype 头文件中定义。

 

isalnum(c)   如果 c 是字母或数字,则为 True。
isalpha(c)   如果 c 是字母,则为 true。
iscntrl(c)   如果 c 是控制字符,则为 true
isdigit(c)    如果 c 是数字,则为 true。
isgraph(c)   如果 c 不是空格,但可打印,则为 true。
islower(c)   如果 c 是小写字母,则为 true。
isprint(c)   如果 c 是可打印的字符,则为 true。
ispunct(c)   如果 c 是标点符号,则 true。
isspace(c)   如果 c 是空白字符,则为 true。
isupper(c)   如果 c 是大写字母,则 true。
isxdigit(c)   如果是 c 十六进制数,则为 true。
tolower(c)   如果 c 大写字母,返回其小写字母形式,否则直接返回 c。
toupper(c)   如果 c 是小写字母,则返回其大写字母形式,否则直接返回 c。

 

3.3. 标准库 vector 类型

vector 是同一种类型的对象的集合,每个对象都有一个对应的整数索引值。一个容器中的所有对象都必须是同一种类型的

  #include <vector>
  using std::vector;

vector 是一个类模板(class template)。必须说明 vector 保存何种对象的类型,通过将类型放在类型放在类模板名称后面的尖括号中来指定类型:

  vector<int> ivec; 
  vector<Sales_item> Sales_vec;

 

vector 对象的定义和初始化

vector<T> v1;   //vector 保存类型为 T 对象。默认构造函数 v1 为空。
vector<T> v2(v1);   //v2 是 v1 的一个副本。
vector<T> v3(n, i);   //v3 包含 n 个值为 i 的元素。
vector<T> v4(n);   //v4 含有值初始化的元素的 n 个副本。

 

创建确定个数的元素

若要创建非空的 vector 对象,必须给出初始化元素的值。虽然可以对给定元素个数的 vector 对象预先分配内存,但更有效的方法是先初始化一个空 vector 对象,然后再动态地增加元素。vector 对象(以及其他标准库容器对象)的重要属性就在于可以在运行时高效地添加元素。因为 vector 增长的效率高,在元素值已知的情况下,最好是动态地添加元素。

 

值初始化

如果没有指定元素的初始化式,那么标准库将自行提供一个元素初始值进行值初始化(value initializationd)。这个由库生成的初始值将用来初始化容器中的每个元素,具体值为何,取决于存储在 vector 中元素的数据类型。

vector 对象的操作

v.empty()   //如果 v 为空,则返回 true,否则返回 false。
v.size()   //返回 v 中元素的个数。
v.empty()   //如果 v 为空,则返回 true,否则返回 false。
v.push_back(t)   //在 v 的末尾增加一个值为 t 的元素。
v[n]   //返回 v 中位置为 n 的元素。
v1 = v2   //把 v1 的元素替换为 v2 中元素的副本。
v1 == v2    //如果 v1 与 v2 相等,则返回 true。
!=, <, <=,>, and >=     //保持这些操作符惯有的含义。

vector 对象的 size

empty 和 size 操作类似于 string 的相关操作。成员函数size 返回相应 vector 类定义的 size_type 的值。

  vector<int>::size_type

向 vector 添加元素

while (cin >> word) {
  text.push_back(word);// append word to text

vector 的下标操作

  for (vector<int>::size_type ix = 0; ix != ivec.size(); ++ix)
    ivec[ix] = 0;

下标操作不添加元素

vector<int> ivec; // empty vector
for (vector<int>::size_type ix = 0; ix != 10; ++ix)
  ivec[ix] = ix; // disaster: ivec has no elements

这个循环的正确写法应该是:
  for (vector<int>::size_type ix = 0; ix != 10; ++ix)
    ivec.push_back(ix); // ok: adds new element with value ix

关键概念:安全的泛型编程

C++ 程序员习惯于优先选用 != 而不是 < 来编写循环判断条件。调用 size 成员函数而不保存它返回的值,在这个例子中同样不是必需的,但这反映了一种良好的编程习惯。在 C++ 中,有些数据结构(如vector)可以动态增长。

3.4. 迭代器简介

每种容器类型都定义了自己的迭代器类型,如 vector:
  vector<int>::iterator iter;

 

begin 和 end 操作

每种容器都定义了一对命名为 begin 和 end 的函数,用于返回迭代器。如果容器中有元素的话,由 begin 返回的迭代器指向第一个元素:

  vector<int>::iterator iter = ivec.begin();

由 end 操作返回的迭代器指向 vector 的“末端元素的下一个”。他指向一个不存在的元素。

 

vector 迭代器的自增和解引用运算

  *iter = 0;  解引用操作符返回迭代器当前所指向的元素。

另一对可执行于迭代器的操作就是比较:用 == 或 != 操作符来比较两个迭代器,如果两个迭代器对象指向同一个元素,则它们相等,否则就不相等。

 

迭代器的算术操作

iter + n      iter - n

可以对迭代器对象加上或减去一个整形值。这样做将产生一个新的迭代器,其位置在 iter 所指元素之前(加)或之后(减) n 个元素的位置。

iter1 - iter2  

该表达式用来计算两个迭代器对象的距离,该距离是名为 difference_type 的 signed 类型 size_type 的值

可以用迭代器算术操作来移动迭代器直接指向某个元素,例如,下面语句直接定位于 vector 中间元素:
  vector<int>::iterator mid = vi.begin() + vi.size() / 2;

任何改变 vector 长度的操作都会使已存在的迭代器失效。例如,在调用 push_back 之后,就不能再信赖指向 vector 的迭代器的值了。

 

3.5标准库bitset

有些程序要处理二进制位的有序集,每个位可能包含 0(关)1(开)值。位是用来保存一组项或条件的 yes/no 信息(有时也称标志)的简洁方法。标准库提供的 bitset 类简化了位集的处理。要使用 bitset 类就必须包含相关的头文件。

#include <bitset>
using std::bitset;

 

bitset 对象的定义和初始化

bitset 类是一种类模板;而与 vector 不一样的是 bitset 类型对象的区别仅在其长度而不在其类型。在定义 bitset 时,要明确 bitset 含有多少位,须在尖括号内给出它的长度值:

bitset<n> b;  //b 有 n 位,每位都 0
bitset<n> b(u);   //b 是 unsigned long 型 u 的一个副本
bitset<n> b(s);   //b 是 string 对象 s 中含有的位串的副本
bitset<n> b(s, pos, n);  //b 是 s 中从位置 pos 开始的&nbps;n 个位的副本。

      bitset<32> bitvec; // 32 bits, all zero

位集合的位置编号从 0 开始,因此,bitvec 的位序是从 0 到 31。以 0 位开始的位串是低阶位(low-order),以 31 位结束的位串是高阶位(high-order)。

当用 unsigned long 值作为 bitset 对象的初始值时,该值将转化为二进制的位模式。而 bitset 对象中的位集作为这种位模式的副本。如果 bitset 类型长度大于 unsigned long 值的二进制位数,则其余的高阶位将置为 0;如果 bitset 类型长度小于 unsigned long 值的二进制位数,则只使用 unsigned 值中的低阶位,超过 bistset 类型长度的高阶位将被丢弃。

 

用string 对象初始化 bitset 对象

当用 string 对象初始化 bitset 对象时,string 对象直接表示为位模式。从 string 对象读入位集的顺序是从右向左(from right to left):
    string strval("1100");
    bitset<32> bitvec4(strval);

string 对象和 bitsets 对象之间是反向转化的:string 对象的最右边字符(即下标最大的那个字符)用来初始化 bitset 对象的低阶位(即下标为 0 的位)。当用 tring 对象初始化 bitset 对象时,记住这一差别很重要。

bitset 对象上的操作

b.any()   //b 中是否存在置为 1 的二进制位?
b.none()   //b 中不存在置为 1 的二进制位吗?
b.count()   //b 中置为 1 的二进制位的个数
b.size()  //b 中二进制位的个数
b[pos]   //访问 b 中在 pos 处二进制位
b.test(pos)   //b 中在 pos 处的二进制位置为 1 么?
b.set()   //把 b 中所有二进制位都置为 1
b.set(pos)   //把 b 中在 pos 处的二进制位置为 1

b.reset()   //把 b 中所有二进制位都置为 0
b.reset(pos)   //把 b 中在 pos 处的二进制位置为 0
b.flip()   //把 b 中所有二进制位逐位取反
b.flip(pos)   //把 b 中在 pos 处的二进制位取反
b.to_ulong()   //用 b 中同样的二进制位返回一个 unsigned long 值
os << b   //把 b 中的位集输出到 os 流测试

访问 bitset 对象中的位

for (int index = 0; index != 32; index += 2)
  bitvec[index] = 1;

for (int index = 0; index != 32; index += 2)
  bitvec.set(index);

获取 bitset 对象的值

仅当 bitset 类型的长度小于或等于 unsigned long 的长度时,才可以使用 to_ulong 操作:

unsigned long ulong = bitvec3.to_ulong();
cout << "ulong = " << ulong << endl;

输出二进制位

bitset<32> bitvec2(0xffff); // bits 0 ... 15 are set to 1; 16 ...31 are 0
cout << "bitvec2: " << bitvec2 << endl;

输出结果为: bitvec2: 00000000000000001111111111111111

posted @ 2012-12-09 12:15  Sam.Sun  阅读(177)  评论(0编辑  收藏  举报