今天读C++ primer发现其中讲数组的一章,有一些东西自己还不是很清楚,所以专门下一篇博客来总结一下数组里面的一些容易忘记的知识。
1. 首先看下面声明数组的几种方式有什么区别:
int *ptr[10];
int &refs[10] = /* */; error
int (*Parray)[10] = &array;
int (&arrRef)[10] = arr;
首先,第一个的意思是定义了一个指针数组,即ptr中存放了是个int*类型的指针值。
第二个是一种错误的写法,因为没有存放引用的数组,所以是错误的。
第三个虽然和第一个相比,就多了个括号,但含义差别还是很大的,它的意思是指Parray是一个指针类型,它指向的是一个存放有10个int类型数据的数组。
而第四个和第三个类似,不过这里arrRef是一个存放有10个int型数据的引用。
- 再来看一下二位数组的一些知识:
首先是二维数组的初始化,这里有两种方式,如下:
int ia[3][4] = {
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9 ,10 , 11}
};
int ia[3][4] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
然后看一下二维数组的遍历方式,首先是最常用的遍历方式:
constexpr size_t rowCnt = 3, colCnt = 4;
int ia[rowCnt][colCnt];
for(size_t i = 0; i != rowCnt; ++i)
{
for(size_t j = 0; j != colCnt; ++j)
{
ia[i][j] = i * colCnt + j;
}
}
下面我们用C++11中新添加的特性Range-For来遍历:
size_t cnt = 0;
for(auto &row : ia)
{
for(auto &col : row)
{
col = cnt;
++cnt;
}
}
注意,因为我们要修改数组ia里的值,所以在遍历的时候用的是引用的类型,当然如果不需要修改里面的值,只是对值进行输出的话,该怎么写呢?首先看一下下面这种写法:
for(auto row : ia)
{
for(auto col : row)
{
cout << col << endl;
}
}
以上写法看起来好像没问题,但其实是通不过编译的,这是因为数组和指针之间转换的问题。C++中在很多情况下,数组都会被看做成一个指针,如上面这种方式,row其实是ia中的一个行数组,所以row会被转换成一个int*类型的指针,导致了内层循环col : row出现错误。所以为了便面row被当作一个指针,我们需要用引用的方式,如下:
for(const auto &row : ia)
{
for(auto col : row)
{
cout << col << endl;
}
}
下面我们再来看一下用指针的方式如何来遍历二位数组:
for (auto p = ia; p != ia + 3; ++p)
{
for(auto q = *p; q != *p + 4; ++q)
{
cout << *q << ' ';
cout << endl;
}
}
上面这种方式的关键在于理解p和q的类型,首先p的类型是int (*p)[4]的,及p是一个指向存放4个int数据的数组的指针。而*p就是一个4大小的int型数组,所以q就是这个数组的指针。简单来说,p和q都是一个指针,但这两个指针确实不同的,p++每次指针前进的距离是sizeof(int) 4, 而q就是一个int*类型的,q++每次前进的距离是sizeof(int)。
利用begin和and函数,我们可以更简单地来遍历一个二维数组:
for (auto p = begin(ia); p != end(ia); ++p)
{
for(auto q = begin(*p); q != end(*p); ++q)
{
cout << *q << ' ';
cout << endl;
}
}
上面都用到了C++11中的auto关键字,当然也会可以明确指明类型的,如下:
using int_array = int[4];
typedef int int_array[4];
for(int_array *p = ia; q != ia + 3; ++p)
{
for(int *q = *p; q != *p + 4; ++q)
{
cout << * q << ' ';
cout << endl;
}
}