第三章-数组

string

  • string使用加法运算符必须确保运算符两侧的运算对象至少有一个string

迭代器

  • 使用iterator和const_iterator表示迭代器的类型
vector<int>::iterator it; //it能读写vector<int>的元素
vector<int>::const_iterator it2; //it2只能读不能写
  • begin和end返回的具体类型由对象是否是常量决定
vector<int> v;
const vector<int> cv;
auto it1 = v.begin(); //it1是iterator
auto it2 = cv.begin(); //it2是const_iterator
  • 如果对象只需读无需写最好使用常量iterator。为了得到const_iterator类型的返回值,可以使用cbegin和cend
vector<int> v;
auto it3 = v.cbegin(); //it3是const_iterator

数组

  • 数组的维度必须是常量表达式(第二章constexpr和常量表达式)
  • 字符数组除了用列表初始化的形式初始化,还有一种自己独特的方式——用字符串字面值初始化。但是C++对字符串字面值(用双引号括起来的零或多个字符)会在字面值后添加空字符\0,所以用这个初始化长度要加1
char c1[] = {'C', '+', '+'}; //列表初始化没有空字符
char c2[] = {'C', '+', '+', '\0'}; //自己显式的加了个空字符
char c3[] = "C++"; //字符串字面值初始化,实际有四个元素
const char c4[6] = "Daniel"; //错误!没有空间放空字符了
  • 理解复杂的数组声明
int *ptrs[10]; //ptrs含有10个整型指针的数组
int &refs[10] = ... //错误,不存在引用的数组
int (*parray)[10] = &arr; //parray指向一个含有10个整数的数组
int (&arrref)[10] = arr; //arrref引用一个含有10个整数的数组
int *(&arry)[10] = ptrs; //arr是数组的引用,该数组含10个指针
  • 在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针
int ia[] = {1, 2, 3};
auto ia2(ia); //ia2是一个整型指针,指向ia第一个元素
ia2 = 42; //错误,ia2是指针
//当使用decltype时不会发生上述转换
decltype(ia) ia3 = {0, 1, 2};
ia3 = p; //错误
ia3[2] = 3; //正确
  • 标准库函数begin和end
int ia = {0, 1, 2};
int *beg = begin(ia);
int *last = end(ia); //指向ia尾元素下一个位置的指针
  • 两个指针相减是它们之间的距离
auto n = end(arr) - begin(arr); //n是arr中的元素
  • 只要指针指向数组中的元素,就可以执行下标运算
int *p = &ia[1];
int j = p[1]; //注意p[1]是*(p+1),是ia[2]
int k = p[-1]; //p[-1]表示ia[0]
//内置下标运算符可以处理负值
  • 一维数组和指针
int a[3] = {1, 2, 3};
int *c = a; //a是一个指针常量,是数组第一个元素的地址
int *c = &a[0]; //&a[0]返回指向数组第一个元素的指针,也就是数组名本身,所以和上一句完全一样

c += 2; //现在c指向3
cout << c[-1] << endl; //c使用偏移量-1后指向前一个数,即2

int (*p)[3]; //定义一个指向长度为3的数组的指针
p = &a;
/*
a是一个数组变量的变量名,对a取地址返回指向数组a的指针
然后把这个指针赋给只能指向数组的指针p。
不能是p = a,因为a表示指向首个元素的地址
而p必须指向3个元素的数组
*/
cout << p << endl; //p指向数组a,输出p的地址
cout << *p << endl; //p指向数组a,所以*p是数组a本身
//因为a和&a一般都用首元素地址表示,所以上面两个输出一致
cout << **p << endl; //相当于*a,对首元素地址解引用
cout << **(p + 1) << endl;
//因为p是指向3个数的数组的指针,所以p + 1也是往前移动3个数后的地址
//这里一共只有3个数,再移动3个数后指向a[3],是一个未定义的数
//还有公式p[i] = *(p + i)
  • 二维数组和指针
int aa[3][10];
/*
一维数组的数组名表示第一个元素的地址,二维元素也是一样
但是二维数组的每个元素都是数组,所以要用指向数组的指针
来指向二维数组的每个元素
*/
aa + 1; //指向a的下一行
*(aa + 1); 
/*
在一维数组中对数组名解引用会得到数组元素的值
二维数组里也一样,只不过得到的是第二维数组的指针
*(aa + 1)就得到aa下一行的子数组
*/
*(aa + 1) + 5; //*(aa + 1)是指向第二行的指针,在第二维的层面上右移5个单位
*(*(aa + 1) + 5); //访问上面移动结束后的那个元素,即a[1][5]

int (*p)[10] = aa; //aa表示第一个子数组的地址,现在由p指向它
int *pi = aa[0];
int *pi = &aa[0][0];
//就像一维数组中int *c = a和int *c = &a[0]一样
//pi这两种声明都创建了指向aa第一个子数组的指针
  • 使用范围for语句处理多维数组,外层循环的控制变量必须声明成引用类型。如果不加引用,会被系统转为对该数组内首元素的指针
  • 要使用范围for语句,除了最内层循环,其他所有循环的控制变量都应该是引用
int ia[3][4] = {
	{0, 1, 2, 3},
	{4, 5, 6, 7},
	{8, 9, 10, 11}
};
for (auto &row : ia) //这里row的类型是int (&row)[4],系统自动转为对存储4个数的数组的引用
//如果不加&符号,row将是int*,这样内层的循环就不合法了
{
	for (int col : row)
		cout << col << " ";
	cout << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值