二、 标准库类型
:: 操作符,该操作符是作用域操作符,它的含义是右操作数的名字可以在左操作数的作用域中找到。
using namespace::name;每个名字都需要一个using声明。
1. string类型
string 类型的输入操作符:
• 读取并忽略开头所有的空白字符(如空格,换行符,制表符)。
• 读取字符直至再次遇到空白字符,读取终止。
string.empty()
string.size()
string[n]
string1+string2
string::size_type类型保存string的长度。
当进行 string 对象和字符串字面值混合连接操作时,+ 操作符的左右操作数必须至少有一个是 string 类型的。
string 对象的下标从 0 开始。如果 s 是一个 string 对象且 s 不空,则 s[0] 就是字符串的第一个字符。
头文件cctype提供了一系列字符操作函数。
getline(输入流,string对象)
2. vector类型
#include <vector>
using std::vector;
vector 不是一种数据类型,而只是一个类模板。
虽然可以对给定元素个数的 vector 对象预先分配内存,但更有效的方法是先初始化一个空 vector 对象,然后再动态地增加元素。
构造函数:vector<T> v1;vector<T> v2(v1);vector<T> v3(n,i);vector<T> v4(n);
vector.empty()
vector.size() ------- vector<int>::size_type
vector.push_back(t):末尾新增元素
vector[n]
必须是已存在的元素才能用下标操作符进行索引。通过下标操作进行赋值时,不会添加任何元素。
内联(inline)函数:编译器遇到内联函数时就会直接扩展相应代码,而不是进行实际的函数调用。
3. 迭代器
vector<int>::iterator iter;
vector.begin()
vector.end():只是起一个哨兵(sentinel)的作用,表示我们已处理完 vector 中所有元素。
迭代器类型可使用解引用操作符(*)来访问迭代器所指向的元素。解引用操作符返回迭代器当前所指向的元素。迭代器使用自增操作符向前移动迭代器指向容器中下一个元素。
另一对可执行于迭代器的操作就是比较:用 == 或 != 操作符来比较两个迭代器,如果两个迭代器对象指向同一个元素,则它们相等,否则就不相等。
vector<int> iv(10);
for(vector<int>::iterator it=iv.begin();it!=iv.end();++it)//如果为空,程序是安全的
*it=2;
const_iterator:只读迭代器
iterator+/-n
iterator1-iterator2:该表达式用来计算两个迭代器对象的距离,该距离是名为 difference_type 的 signed 类型 size_type 的值
4. bitset
#include <bitset>
using std::bitset;
bitset<n> b; b 有 n 位,每位都 0
bitset<n> b(u); b 是 unsigned long 型 u 的一个副本
bitset<n> b(s); b 是 string 对象 s 中含有的位串的副本。string 对象和 bitsets 对象之间是反向转化的:string 对象的最右边字符(即下标最大的那个字符)用来初始化 bitset 对象的低阶位(即下标为 0 的位)。
bitset<n> b(s, pos[, n]); b 是 s 中从位置 pos 开始的n个位的副本。
b.any() |
b 中是否存在置为 1 的二进制位? |
b.none() |
b 中不存在置为 1 的二进制位吗? |
b.count() |
b 中置为 1 的二进制位的个数,返回类型为size_t类型,声明在cstddef头文件中 |
b.size() |
b 中二进制位的个数,返回类型为size_t类型 |
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 流 |
三、 数组与指针
1. 数组的长度是固定的。数组一经创建,就不允许添加新的元素。数组定义中的类型名可以是内置数据类型或类类型;除引用之外,数组元素的类型还可以是任意的复合类型。
2. 如果没有显式提供元素初值,则数组元素会像普通变量一样初始化
• 在函数体外定义的内置数组,其元素均初始化为 0。
• 在函数体内定义的内置数组,其元素无初始化。
• 不管数组在哪里定义,如果其元素为类类型,则自动调用该类的默认构造函数进行初始化;如果该类没有默认构造函数,则必须为该数组的元素提供显式初始化。
3. 字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值进行初始化。然而,要注意这两种初始化形式并不完全相同,字符串字面值包含一个额外的空字符用于结束字符串。
4. 一个数组不能用另外一个数组初始化,也不能将一个数组赋值给另一个数组。
5. 数组下标的正确类型则是 size_t。
6.
string s("hello world"); string *sp = &s; // sp holds the address of s
*sp 中的 * 操作符表明 sp 是一个指针变量,&s 中的&符号是取地址操作符,当此操作符用于一个对象上时,返回的是该对象的存储地址。取地址操作符只能用于左值,因为只有当变量用作左值时,才能取其地址。同样地,由于用于 vector 类型、string 类型或内置数组的下标操作和解引用操作生成左值,因此可对这两种操作的结果做取地址操作,这样即可获取某一特定对象的存储地址。
7. 每个指针都有一个与之关联的数据类型,该数据类型决定了指针所指向的对象的类型
8. 一个有效的指针必然是以下三种状态之一:保存一个特定对象的地址;指向某个对象后面的另一对象;或者是0 值。若指针保存0 值,表明它不指向任何对象。未初始化的指针是无效的,直到给该指针赋值后,才可使用它。
9. 对指针进行初始化或赋值只能使用以下四种类型的值:
1. 0值常量表达式,或者预处理器变量NULL(在头文件cstdlib中申明,其值为0,编译时会自动替换为数值0)。
2. 类型匹配的对象的地址。
3. 另一对象末的下一地址。
4. 同类型的另一个有效指针。
10. void*,它可以保存任何类型对象的地址,表明该指针与一地址值相关,但不清楚存储在此地址上的对象的类型。void* 指针只支持几种有限的操作:与另一个指针进行比较;向函数传递void*指针或从函数返回 void* 指针;给另一个 void* 指针赋值。不允许使用void*指针操纵它所指向的对象。
11. 对指针进行解引用可访问它所指的对象,*操作符(解引用操作符)将获取指针所指的对象。虽然使用引用(reference)和指针都可间接访问另一个值,但它们之间有两个重要区别。第一个区别在于引用总是指向某个对象:定义引用时没有初始化是错误的。第二个重要区别则是赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象(这就是为什么引用必须在定义时初始化的原因)。
int ival = 1024, ival2 = 2048; int *pi = &ival, *pi2 = &ival2; pi = pi2; // pi now points to ival2 int &ri = ival, &ri2 = ival2; ri = ri2; // assigns ival2 to ival
12. 指针本身也是可用指针指向的内存对象。指针占用内存空间存放其值,因此指针的存储地址可存放在指针中。C++ 使用 ** 操作符指派一个指针指向另一指针(获取值时需要进行两次解引用)。
13.
int ia[] = {0,2,4,6,8}; int *ip = ia; // ip points to ia[0]
如果希望使指针指向数组中的另一个元素,则可使用下标操作符给某个元素定位,然后用取地址操作符 & 获取该元素的存储地址:ip = &ia[4]。
ip = ia; // ok: ip points to ia[0] int *ip2 = ip + 4; // ok: ip2 points to ia[4], the last element in ia
通常,在指针上加上(或减去)一个整型数值 n 等效于获得一个新指针,该新指针指向指针原来指向的元素之后(或之前)的第 n 个元素。指针的算术操作只有在原指针和计算出来的新指针都指向同一个数组的元素,或指向该数组存储空间的下一单元时才是合法的。如果指针指向一对象,我们还可以在指针上加1从而获取指向相邻的下一个对象的指针。
ptrdiff_t n = ip2 - ip; // ok: distance between the pointers
结果是 4,这两个指针所指向的元素间隔为 4 个对象。两个指针减法操作的结果是标准库类型ptrdiff_t 的数据。与 size_t 类型一样,ptrdiff_t 也是一种与机器相关的类型,在 cstddef 头文件中定义。size_t 是
unsigned 类型,而 ptrdiff_t 则是 signed 整型。允许在指针上加减 0,使指针保持不变。更有趣的是,如果一指针具有 0 值(空指针),则在该指针上加 0 仍然是合法的,结果得到另一个值为 0 的指针。也可以对两个空指针做减法操作,得到的结果仍是 0。
int ia[]={1,2,3,4,5}; int *ip1=ia; cout<<ip1<<endl;//ia[0]的内存地址 cout<<&ip1<<endl;//指针ip1的内存地址 cout<<*ip1<<endl;//ia[0]的内容
14. 在表达式中使用数组名时,实际上使用的是指向数组第一个元素的指针。
15. p 指向数组 arr 的第一个元素,在指针 p 上加数组长度即可计算出数组 arr 的超出末端指针。C++ 允许计算数组或对象的超出末端的地址,但不允许对此地址进行解引用操作。而计算数组超出末端位置之后或数组首地址之前的地址都是不合法的。
int int_array={1,2,3,4,5}; for(int *pBegin=int_array,*pEnd=int_array+5;pBegin!=pEnd;++pBegin) cout<<*pBegin<<endl;
16. C++语言强制要求指向const对象的指针也必须具有const特性:
const double *cptr; // cptr may point to a double that is const
const 限定了cptr 指针所指向的对象类型,而并非 cptr 本身。也就是说,cptr 本身并不是const。在定义时不需要对它进行初始化,如果需要的话,允许给 cptr 重新赋值,使其指向另一个 const 对象。但不能通过 cptr 修改其所指对象的值。不能使用 void* 指针保存 const 对象的地址,而必须使用 const void* 类型的指针保存 const 对象的地址。允许把非 const 对象的地址赋给指向 const 对象的指针。
17. const 指针:
int errNumb = 0; int *const curErr = &errNumb;
与其他 const 量一样,const 指针的值不能修改,这就意味着不能使 curErr 指向其他对象。与任何 const 量一样,const 指针也必须在定义时初始化。
const double pi = 3.14159; const double *const pi_ptr = π
18.
typedef string *pstring; const pstring cstr;//该定义等价于:string *const cstr;