编程语言中的很多设计都可以与现实生活结合起来。在声明一个基本变量的时候,我们可以比作一个点,那么线又是什么呢,是数组(一维),面是什么呢,是二维数组,三维空间是什么呢,是三维数组,当然了,在数字图像处理领域,还有四维数组,这表示一批3通道的图片。
数组有一个很重要的特征,那就是所有的元素是同类型的,且有序排列。其实学习数组的关键点在于数组中元素的存取,可以是索引,更深层次的还可以是地址。
以上是我对数组的一些鄙陋之见。数组分为静态数组和动态数组,鉴于篇幅,先谈谈静态数组。
1、静态数组和动态数组的区别
所谓静态,这个涉及到程序的编译和运行的区别,静态数组对应的是在程序编译阶段就确定了数组的长度(即内存),动态数组则是在程序运行阶段才确定数组的长度,即编译时不实际给它分配内存。
2、静态数组
- 另类的静态数组声明
相信学习过数组的机油们都清楚下面的语句:
int array1[5] = {1, 2, 3, 4, 5};
是的,嗖一贼。然而还有这样的:
int array2[5] = {1, 2, 3, 4};
这就看上去有点奇特了,再看一个:
int array3[] = {1, 2, 3, 4, 5};
依旧奇特。是的,如果声明时给定了数组的长短,是可以不(全)赋值的,编译时系统会自动赋初值为0
,如果没有给定长度,那么,给多少个初值它的长度就是多少,反而如果不赋初值便是错的,因为编译器不知道你要给多长。这个在二维数组里面基本原则也是如此,只是因为维度约束问题会显得不同,但本质上是一样的。
- 究竟是不是索引?
这个问题很简单,我们看到声明时,比如array[5]
,这个5
其实并不是索引,而是数组的长度。如果在声明之后出现呢,比如array[4]
,这个4
就是这个数组的索引了。
- 通过索引存取元素
上面说的索引的问题,其实就是用来存取数组元素用的,比如要修改数组array的第3
个元素,那么就是array[2] = //...
,是的,索引值是从零开始的,很多编程语言都是这样,当然也有例外的,比如matlab
。
- 数组名
谈到数组名,就不得不说说指针,这是一个比较复杂的东西,数组有些特征跟指针是似而非,这往往给数组的理解带来困难。以下我们以结论的形式说一说数组名和指针的区别。
1)、数组名不是指针
我们知道,指针变量本身是占有内存空间的,当声明指针时,计算机会给其分配8个字节的地址空间。指针变量的地址和其所指的地址并不是同一个地址。
#include <iostream>
using namespace std;
int main()
{
int a[3] = {3, 5, 6};
int *p = a;
cout << a << endl;
cout << &a << endl;
cout << p << endl;
cout << &p << endl;
return 0;
}
运行结果:
我们知道,数组名就是数组的首元素地址,可以看出,数组名和其地址是同一个,也就是说计算机并未给数组变量分配空间。而对于指针,计算机分配了内存空间给指针变量用来存储所指内容的地址。
2)、数组名包含的不只是数组首元素地址信息
其实有的资料上说,当把数组作为函数参数的时候,还要指明数组的长度,然而,实验表明,这是值得质疑的。
#include <iostream>
using namespace std;
int main()
{
int a[] = {1, 2, 3, 4, 5};
cout << a << endl;
cout << sizeof(a) << endl;
cout << sizeof(a+1) << endl;
cout << sizeof(a+2) << endl;
return 0;
}
运行结果:
可以看到,当把数组名当做参数的时候,不仅提供了数组的元素首地址信息,还可以通过内置函数sizeof()
返回数组长度信息,这说明数组组名同时包含了数组元素首地址信息和数组长度信息,而有了这两点等价于提供了该数组的全部信息。值得注意的是,由上面的程序及结果可以看出,对于数组名a
而言,a
和a + n
有本质的区别,总的来说,数组名不是单纯的地址,而数组名加上偏移量为什么占位8个字节(跟数组类型无关),笔者水平有限,还希望各位大牛指点。