数组是C/C++以及各种编程语言中最常用的一种数据结构,了解数组的性质并且学会使用数组是对于程序员最基本的要求。今天给大家介绍一下数组,介绍主要分为静态数组与动态数组两部分。
注:这里讲到的静态数组不是使用static 关键字修饰的数组,而是普通的数组,为了与后面的动态数组分离开,才说明它是静态数组。
数组是一种复合的类型,因此在定义数组时必须显式指定数组的类型,不能使用auto关键字,静态数组的声明形如a[d]; a是数组的名字,d是数组的维度。维度说明了数组中元素的个数,因此d必须大于0。
在进行编译时,d必须是已知的,即编译器在编译时d已经是可以确定的值,因此数组的维度必须是一个常量表达式。
补充:常量表达式是指不会改变且在编译过程就能得到计算结果的表达式,显然字面值属于常量表达式。
int S = 10;
int arr[S]; //错误,S不是常量表达式
int *prr[10]; //正确,10是常量表达式
const int M = 10;
int A[M] = { 10 }; //正确,M是常量表达式
string C = "fishing_pan";
const int N = C.length();
char B[N]; //错误,N不是常量表达式,因为N在运行时候才被初始化
在上面的数组中可以看到,数组的维度必须是常量表达式。
在定义的时候可以对静态数组进行列表初始化,而进行列表初始化时,可以不声明数组的维度,如果没有声明数组的维度,那么编译器会根据初始值推测数组的大小。如果声明了维度,那么数组的初始值的数量不能超过维度,如下面的例子所示。
int arr1[4] = {0, 1, 2 }; //数组大小为4,值分别是0,1,2,0,未列出的值进行默认初始化;
char arr2[] = {'P', 'A', 'N' }; //未声明大小,大小为3
double arr3[4] ={0,1,2,3,4} //错误,初始值过多
在字符数组的定义中,可以使用字符串字面值进行定义,这个时候要注意了,字符串默认在结尾处还有一个空字符,空字符需要占用一个位置。
从下面的例子可以看出,初始化字符数组时,可以不标明大小,这样不会出错。
char arr4[3] ="pan"; //错误,"pan"是const char[4]类型,不能用于初始化char arr4[3]
char arr5[] ="pan"; //正确,arr5大小为4;
不能将数组内容拷贝给其他数组进行初始化,也不能用数组为其他数组赋值。
数组元素可以用下标进行访问,也可以实现指针进行访问,需要注意的是,数组的第一个元素的编号是0,而不是1;一个100大小的数组,索引编号是0-99。
char arr5[] = "pan";
char c=arr[2]; //c=’n’;
在C++中,数组与指针的关系非常紧密。指针一般使用取地址符来指向某一对象。同样也可以用于指向一个数组,不同的是,指针不会指向整个数组,而是指向数组中的某个位置;例如
int arr1[4] = { 0, 1, 2 };
int *p = &arr1[1]; //指向arr1的第二个数;
直接将数组的名字传给指针时,默认指向数组的第一个值。
int arr1[4] = { 0, 1, 2 };
int *p = arr1; //等价于p=&arr1[],指向arr1的第1个数;
当遍历数值的值时,可以使用指针进行迭代,只需移动指针即可;
int arr1[4] = { 0, 1, 2 };
int *p = &arr1[1];
++p; //此时p指向arr1[2];
使用指针遍历虽然简单,但是容易出现超出范围的内存错误。因此可以使用迭代器;
int *beg = begin(arr1); //指向数组首元素
int *ends = end(arr1); //指向数组末尾元素的下一位
while(beg!=ends) //进行遍历。
{
cout<< *beg<
在有些时候,为了使用方便或者观察方便,会定义多维数组,比如读取一张图像,可以用一张二维数组存储图像中对应坐标的灰度值。
多维数组其实就是元素是数组的数组,拿一个二维数组为例,第一个维度表示的是数组的大小,也就说是数组本身有多少个元素。第二个维度表示其元素的大小。
inttwodArr1[4][5]; //定义一个本身大小为4,元素大小为5的数组,共可存储20个整型数据
对于二维数组来说,我们常常把第一个维度称为行,第二个维度称为列,上式定义了一个4行5列的数组。
除了一维数组中提到的注意事项外,多维数组进行初始化时,也有一个需要注意的问题。
为了方便理解,可以使用花括号将每一行括起来。
int twodArr2[4][5] = { { 0, 1, 2, 3, 4 }, {5, 6, 7, 8, 9 }, { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 } };
也可以不适用花括号,由编译器自己判断;
int twodArr3[2][5]= { 0, 1, 2, 3, 4, 5, 6 }; //等价于int twodArr2[2][5] = { {0, 1, 2, 3, 4},{ 5, 6 ,0,0,0}};
注意:定义多维数组时,如果不对它进行初始化,必须标明每个维度的大小;如果进行了显式的初始化,可以不标明最高维度的大小,(也就是第一个维度,当第一个维度不标明大小,则不需进行初始化);
inttwodarr4[][][5] = { 0, 1, 2, 3, 4, 5, 6 }; //错误,需标明第二个维度的大小
inttwodarr5[][5] = { 0, 1, 2, 3, 4, 5, 6 }; //正确;
inttwodarr5[][5]; //错误,必须声明每一个维度的大小
int twodarr[3][4];
int(*p3)[5]= twodArr2; //指向twodArr2的第一行
p3= &twodArr2[1]; //指向twodArr2的第二行
cout << *(*p3) << endl; //输出为5,第二行第一个数字
可以看出,我们使用指针对数组进行迭代,当然,也可以使用迭代器;
for (auto p = begin(twodArr2); p !=end(twodArr2); p++)
{
for(auto q = begin(*p); q != end(*p); q++)
{
cout<< *q << " ";
}
cout<< endl;
}
未完.......
相关文章 细说C++中的数组之动态数组