对于学习过编程语言的人来说,相信绝大多数人都会有这样的疑问:我们平时计数,通常是从一开始计数的,为什么在编程语言中,数组的下标是从0开始计算的呢?
这是因为,C语言中,下标的含意是:
当前元素到第一个元素的偏移量
。第一个元素的下标自然就是0,第二个元素的下标为1,第n个元素的下标为n-1。
这样处理能带来什么好处呢?
我们知道,C语言的数组是存储在一片连续的内存空间中的。C编译器就可以直接通过第一个元素的地址,即数组地址,和相应元素的下标[即距首元素的偏移量]来得到它的地址。如:
char arr[] = "hello world!";
假设arr[0]的地址为10000,编译器可以通过10000 + 2来获取a[2]的地址。从编译器的角度来讲,数组下标[索引]从0开始更为高效。
很多同学可能在学习
数组
时会有这个疑问,
下标
为什么
不从
1
开始
呢?从
1
开始
不是
更符合大家的日常习惯吗?生活中我们通常说第
1
个,而
不是
第
0
个。的确,有些计算机
语言
如早期的Pascal
语言
,
数组
元素的
下标
是从
1
开始
的。难道是C
语言
故意要与众不同?要弄清楚这个问题,得先看一下计算机底层是怎样处理
数组
元素的。我们先编写了一个小程序,然后在visual
studio中对其进行了反汇编。源程序和反汇编后的部分
大家学习c
语言
刚接触
数组
时候,书上说第一个
数组
元素要从
下标
0
开始
数起,不能从
1
开始
数,比如
int a[4]={
1
,2,3,4};
那么a[
0
]=
1
;
为什么
不从
1
数起呢
即a{
1
}=
1
呢?不更符合大家的生活习惯吗?
在C
语言
中,所有定义的变量最终都是加载到内存中进行相关的操作的,包括
数组
;
数组
在内存中占据的空间是连续的,而且
数组
的每个元素都是相同的数据类型。这就决定了我们在访问
数组
时必须能够找到这一连续内存空间的首地址,而这个首地址自然就落到了
数组
名的肩上。此时,**这个首地址就是第一个元素的地址;这样一来,当需要访问其他数据元素时都需要和这个首地址进行关联,
数组
的
下标
实际上表示的意义是:
数组
中元素位置与首地址的偏移量。**因此在C
语言
中
数组
的第一个元素
下标
即为
0
。
另一种理解方式可以和自然数做类比:最小的自然数是
0
而
我们先创建一个整型
数组
:
int[] array = new int[5];
数组
中每一个元素都有他的地址值,并且是连续的,假设第一个元素的地址为
1
0
0
0
0
,且他存放的是int类型数据,我们知道他在java中是占用4个字节的,所以他的下一个元素的地址为
1
0
0
0
4,再下一个就是
1
0
0
0
8,以此类推。
下图显示了
数组
在内存中的地址分配:
那我们直接根据索引寻找元素是如何实现的呢?这涉及到寻址算法公式:
array[i] = base_address + i * d
一、
数组
下标
从
0
开始
的原因
在回答这个问题之前我们首先要明确一点那就是对于
数组
元素的访问在操作系统层其实就是对特定内存偏移量的数据的访问,换而言之即如果想要访问一个
数组
的某一个元素的值那么首先就要计算它的地址偏移量 ,其大概的公式为:
a[k]_adress = base_address + k*type_size ;
,倘若
数组
下标
是从
1
开始
那么地址计算公式即会转变为:
a[k]_adress = base_address + (k-
1
)*type_size ;
这对于CPU来说多了一次减法操作,对于
windows C/C++ 使控制台窗口全屏
CodeSharkSJ:
windows C/C++ 使控制台窗口全屏
ZJ_fifififi: