数组声明:
int arr [ ]={34, 65, 23, 75, 76, 33};
四种表示法:(考虑 i=0)
arr[i]
和
*(arr+i)
和
*(i+arr)
和
i[arr]
让我们看一下数组在内存中的布局:
低地址高地址 | | 五 五 +----+----+----+----+----+----+ |34 |65 |23 |75 |76 |33 | +----+----+----+----+----+----+ ^ ^ ^ ^ | | | ...等 | | | | | 到达[2] | | | 到达[1] | arr[0]
第一个元素是arr[0]
,第二个arr[1]
很清楚,这是每个人都学到的。不太清楚的是,编译器实际上将诸如arr[i]
之类的表达式转换为*(arr + i)
。
*(arr + i)
所做的是首先获取指向第一个元素的指针,然后执行指针算术以获取指向索引i
处所需元素的指针,然后取消引用指针以获取其值。
由于加法的交换性质,表达式*(arr + i)
等于*(i + arr)
由于上述翻译等于i[arr]
。
arr[i]
和*(arr + i)
的等价性也是数组衰减到指向其第一个元素的指针背后的原因。
指向数组第一个元素的指针将是&arr[0]
。现在我们知道arr[0]
应该等于*(arr + 0)
这意味着&arr[0]
必须等于&*(arr + 0)
。向任何内容添加零都是无操作,因此导致表达式&*(arr)
。也可以删除只有一个项且没有运算符的括号,留下&*arr
.最后,地址和取消引用运算符彼此对立并相互抵消,给我们留下简单的arr
。所以&arr[0]
等于arr
.
数组中的每个元素在内存中都有一个位置。数组中的位置是连续的。C 中的数组是指针,始终指向集合(数组的第一个元素)内存上的第一个方向。
arr[i]=> 获取数组中 "i-position" 的值。arr[i] = *(arr + i)
*(arr+i)=> 通过添加内存中指向arr
和i value
的位置来获取内存中的值。
*(i+arr)=> 与*(arr+i)
相同。总和是可交换的。
i[arr]=> 与*(i+arr)
相同。这是另一种表现方式。
它们是相同的,因为 C 语言规范是这样说的。读取 n1570
符号a[i]
是*(a+i)
的语法糖。
第一个是数学语法(更接近人脑教育的符号),而第二个直接对应于一个汇编指令。
另一方面*(a+i)=*(i+a)=i[a]
因为指针的算术是可交换的。
由于数组下标运算符[]
的定义方式,这些是相同的。
从C标准第6.5.2.1节:
2后缀表达式后跟方括号中的表达式
[]
是数组对象的元素的下标指定。这 下标运算符的定义[]
是E1[E2]
是 与(*((E1)+(E2)))
相同。由于转换规则 应用于二进制+
运算符(如果E1
是数组对象) (等效地,指向数组对象的初始元素的指针)E2
是一个整数,E1[E2]
表示 的E2
个元素E1
(从零开始计数)。
示例中arr[i]
的表达式的格式为E1[E2]
。 因为标准规定这与*(E1+E2)
相同,这意味着arr[i]
与*(arr + i)
相同。
由于加法的交换性质,*(arr + i)
与*(i + arr)
相同。 将上面的等价规则应用于此表达式会得到i[arr]
。
简而言之,这 4 个表达式是等价的,因为标准如何定义数组下标以及加法的交换属性。
它之所以有效,是因为 C 中的数组变量(即示例中的 arr)只是指向内存位置数组开头的指针。 指针是数字,表示特定内存位置的地址。 当您在指针前面放置和"*"时,它表示"给我该内存位置中的数据"。
因此,如果 arr 是指向数组开头的指针,则 *(arr) 或 *(arr + 0) 是- 数组第0 个索引中的数据,*(arr + 1) 是第一个索引中的数据,依此类推。
- 看起来像A[B]的表达式本质上被翻译成类似*(A+B)的东西。 因此,arr[0] = *(arr + 0) 和arr[i] = *(arr+i),依此类推。
- 由于A+B = B+A,因此两者是可以互换的。 意思*(arr+i) = *(i+arr)。 因为 arr[i] = *(arr+i) 和 *(
- arr+i) = *(i+arr),所以 arr[i]= i[arr]应该是有意义的。