3.1 命名空间using声明
命名空间中的名称使用:
- 使用
using
引入
// 全部引入
using namespace::std;
// 部分引入
using std::cin;
using std::cout;
...
- 显示调用
int main()
{
...
std::cout<<...;
...
}
头文件不应包含using
声明,避免产生冲突
3.2 标准库类型string
#include <string>
using std::string;
直接初始化和拷贝初始化
string s1 = "hello"; // 拷贝初始化
string s2("hello"); // 直接初始化
string s3(10, 'c') // 直接初始化,s3='cccccccccc'
string s4 = string(10, 'c') // 拷贝初始化,出现利用临时变量拷贝
// 等价于
string temp(10, 'c');
string s4 = temp;
string
对象自动忽略开头的空白(空格符、换行符、制表符),遇到空白停止。
getline
遇到换行符停止,读取换行符但不保存
字符串字面值和string
对象相加时,必须确保每个加法运算符(+)的两侧运算对象至少有一个是string
string s = "hello"+","+s1; // 错误
string s = "hello"+s1+","; // 正确
string
字符操作
函数 | 操作 |
---|---|
isalnum | 字母或数字 |
isalpha | 子母 |
iscntrl | 控制字符 |
isdigit | 数字 |
isgraph | 不是空格但可以打印出来 |
islower | 小写字母 |
isprint | 可打印字符 |
ispunct | 标点符号(非控制字符、数字、子母) |
isspace | 空白(空格、制表符、回车、换行符等) |
isupper | 大写字母 |
isxdigit | 十六进制数字 |
tolower | 大写转小写 |
toupper | 小写转大写 |
基于范围的for
循环
使用范围for循环处理多维数组,除了最内层的循环其他循环控制变量都应该是引用类型。
for(declartion:expression)
statement
逐字符输出
string srt("some string");
for(auto c:str)
cout<<c<<endl;
统计string
对象中标点符号个数
string s("hello world!!!");
decltype(s.size()) punct_cnt = 0;
for(auto c:s)
if(ispunct(c))
++punct_cnt;
cout<<punct_cnt<<endl;
改变字符串中字符
strig s("hello world!!!");
for(auto &c:s) // & 改变字符
c = toupper(c);
cout << s << endl;
3.3 vector
对象的集合,所有对象的类型都相同。集合中的每个对象都有一个与之对应的索引,索引用于访问对象。亦称做容器。
vector类模板并非类型
除引用外,大多数内置类型和类都可以为vector对象的元素,包括vector。
注意
早期版本C++中元素是vector的向量模板定义稍有不同
// C++11 之前
vector<vector<int> >
// C++11
vector<vector<int>>
定义和初始化
语句 | 初始化方式 |
---|---|
vector v1 | v1空vector,潜在元素是T类型,执行默认初始化 |
vector v2(v1) | v2中包含有v1的所有元素的副本 |
vector v2=v1 | 等价于v2(v1) |
vector v3(n, val) | v3包含n个重复的元素,每个元素都是val |
vector v4(n) | v4包含n个重复执行了值初始化的对象 |
vector v5{a,b,c…} | v5包含了初始值个数的元素,每个元素被赋予乡相应的初始值 |
vector v5={a,b,c…} | 等价于v5{a,b,c…} |
值初始化
初始化时,可以只提供vector对象容纳的元素数量,此时库会创建一个值初始化的元素初值,并将其赋给容器中所有元素。这个初始值由vector对象中元素的内置类型决定。
如果vector元素是内置类型,比如int,则元素初始值自动设为0;如果是类类型,如string,则元素由类默认初始化。
vector<int> ivec(10) // 10个初始化为0的int
vector<int> svec(10) // 10个初始化为空的string
添加元素
直接初始化三种情形:
- 数量少
- 副本
- 类型、值一致
当数量较大或其他情况时,更适合向vector中添加元素而不是直接初始化
不能用下标形式添加元素,只能对已存在的元素执行下标操作
vector<int> v1;
for (int i = 0; i !=100; ++i) {
v1.push_back(i);
}
3.4 迭代器
end迭代器(尾迭代器)指向尾元素的下一个位置,不存在的元素。容器为空,begin和end相同。
如果对象是常量,只能使用const_iterator迭代器。
迭代器运算符
运算符 | 含义 |
---|---|
*iter | 返回迭代器iter所指元素的引用 |
iter->mem | 获取iter指向元素的mem成员,等价于(*iter).获取iter指向元素的mem成员 |
++iter | 指向容器中的下一个元素 |
–iter | 指向容器中的上一个元素 |
iter1 ==/!= iter2 | 迭代器是否相等 |
对尾迭代器(end)解引用、递增(++)是非法的,因为end没有指向的存在的元素
迭代器失效
- 不能在for循环中想vector对象添加元素
- 可能改变vector对象容量的操作,如push_back,使其迭代器失效
迭代器运算
经典算法:二分搜索。
auto beg = text.begin(), end = text.end();
auto mid = text.begin() + (end-beg)/2;
while(mid != end && *mid != sought){
if(sought < *mid)
end = mid;
else
beg = mid + 1;
mid = beg + (end - beg)/2
}
3.5 数组
定义和初始化
定义数组必须指定类型,不允许使用auto关键字,不存在引用的数组。
数组维度必须是常量表达式
unsigned cnt = 42;
int arr[cnt]; // 错误
constexpr unsigned sz = 42;
int arr[sz]; // 正确
数组的指针和数组的引用
int (*parray)[10] = &arr;
int (&arrref)[10] = arr;
由内向外解释声明含义,()中表明parray是一个指针,指向大小为[10]的数组,且数组中元素是int;同理arrref是一个引用,引用对象是一个大小为[10]的数组,且元素类型是int。
int * (&arry)[10] = ptrs;
arry
是一个大小为10的数组的引用,并且元素的类型是int指针(int *),即arry是一个含有10个int型指针的数组的引用。
指针和数组
很多对数组的操作实际是对指针的操作,数组名就是指向数组第一个元素的指针。
string nums[] = {"one", "two", "three"};
string *p = &nums[0];
// 等价
string *p = nums;
使用auto
关键字时,得到的变量的类型是指针而非数组
int ia[] = {0,1,2,3,4,5};
auto ia2(ia);
// 等价于
auto ia2(&ia[0]); // ia2: int *
使用decltype
关键字时,保持不变,返回类型是数组
decltype(ia) ia3 = {0,1,2,3,4,5}; // ia3是数组
ia3[2] = 6;
指针和迭代器
利用标准库函数begin
和end
,定义在iterator头文件中。
int ia[] = {1,2,3,4,5};
int *beg = begin(ia);
int *last = end(ia);
C风格字符串
头文件cstring
或者string.h
C风格字符串需要以空字符(’\0’)结尾,才能判断字符串的尾部,进行下一步操作。
建议任何出现字符串字面值的地方都可以用以空字符结束的字符数组来替代
string
对象初始化C风格字符串
const char *str = s.c_str();
如果后续的操作改变了s的值,则之前的返回的字符数组将失效,最好将其重新拷贝一份
使用数组初始化vector对象
int int_arr[] = {1,2,3,4};
vector<int> ivec(begin(int_arr), end(int_arr)); // 全部一样
vector<int> svec(int_arr+1, int_arr+3); // 从int_arr[1]~[3]一样
3.6 多维数组
初始化
int ia[3][4] = {
{0,1,2},
{4,5,6},
{7,8,9}
};
// 等价
int ia[3][4] = {1,2,3,4,5,6,7,8,9};
使用范围for循环处理多维数组,除了最内层的循环其他循环控制变量都应该是引用类型。