为什么 c/c++允许在函数调用中省略多维数组的最左边索引吗?
我只是想知道为什么在将数组传递给函数时允许省略多维数组的最左边的索引?为什么不超过一个索引呢?编译器如何找出省略一个索引的大小?
I was just wondering why it is allowed to omit the leftmost index of a multidimensional array when passing the array to a function ? Why not more than one indexes? And how does the compiler find out the size with one index omitted ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
其他答案描述了 C 标准如何处理数组到指针的转换以及这如何影响函数声明,但我觉得他们没有详细说明为什么,所以我在这里......
在 C 中,数组代表内存中紧密排列的元素。
在上面的示例中,每个数组元素的宽度为 1
_
。为了找到第 i 个元素,我们必须转到第 i 个地址。 (请注意,最左边的维度(大小)在这里并不重要)现在考虑一个多维数组:
要找到
A[i][j]
的偏移量,我们需要跳过 i 行 (3 *i) 然后遍历 j 个元素 -> (3*i+j)。请注意,这里也不需要第一维的大小。现在应该很清楚了,使用数组时不需要最左边的大小,仅在创建数组时才需要。
既然不需要给出最左边索引的维度,那么为了完整性为什么不给出它呢?毕竟,这是 Pascal 编程语言(C 的当代语言)所做的事情。
好吧,大多数对数组进行操作的函数对于所有可能的数组长度都是相同的,因此指定大小只会损害您重用它们的能力。
例如,为什么
当您可以这样做时:
至于省略多个维度,在使用普通多维数组时这是不可能的(因为您需要知道维度才能知道第一行何时结束而第二行何时开始) 。但是,如果您愿意花费一些(少量)额外内存作为暂存空间,则完全可以使用指向指针的指针: http://www.eskimo.com/~scs/cclass/int/sx9b.html
Other answers described how the C standard handles array to pointer conversion and how this affects the function declaration, but I feel they didn't go into the why, so here I go...
In C, arrays stand for tightly packed elements in memory.
In the above example, each of the array elements is 1
_
wide. To find the i-th element, we thus have to go to the i-th address. (Note that the leftmost dimension (the size) doesn't matter here)Now consider a multidimensional array:
To find the offset of
A[i][j]
we need to jump over i rows (3*i) and then over j elements -> (3*i + j). Note how the size of the first dimension is also not needed here.It should be clear by now then, that the leftmost size isn't needed when using the array, it is only needed when you create it.
Since there is no need to give the dimension of the leftmost index, then why not give it anyway, for completeness sake? After all, this is what is done in the Pascal programming language (a C contemporary).
Well, most functions that operate on arrays work the same for all possible array lengths, so specifying the size would only hurt your ability to reuse them.
for example, why do
When you can do this instead:
As for omitting more then one dimension, this isn't possible when using normal multidimensional arrays (because you need to know the dimension to know when the first row ends and the second starts). However, if you are willing to spend some (little) extra memory for scratch space, it is perfectly possible to use pointers to pointers instead: http://www.eskimo.com/~scs/cclass/int/sx9b.html
在声明中
实际上,您不能完全省略最右边或最左边的尺寸。
但是,如果您有初始化器,则可以为您推导出最左边的唯一。
在函数参数列表中
当您按值将数组传递到函数时,您实际上是在传递指向该数组的第一个元素的指针。是的,从语法上看,您正在传递一个数组,但是,不,您不是。
考虑一下:
两者的语法都令人困惑:
没有数组的痕迹,更不用说特定的三个元素之一了。
现在:
这对于等价物来说是令人困惑的语法:
其中
int (*)[3]
是指向数组第一个元素的指针的类型(指向int[3]
int[3]代码>)。总之,不要过多关注类似于
[]
的类似数组的语法;它并不能真正代表真正发生的事情。In a declaration
Actually, you can't leave out the rightmost or the leftmost dimension entirely.
However, the leftmost only can be deduced for you if you have an initialiser.
In a function argument list
When you pass an array into a function by value, you're actually passing a pointer to the first element of that array. Yes, it looks from the syntax like you're passing an array but, no, you're not.
Consider:
Both are confusing syntax for the equivalent:
No trace of an array, let alone one of specifically three elements.
Now:
This is confusing syntax for the equivalent:
where
int (*)[3]
is the type of a pointer to the first element of your array (pointer toint[3]
).In conclusion, don't pay too much attention to the array-like syntax that looks like
[]
; it's not really representative of what's truly happening.除非它是
sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化数组的字符串文字,否则类型为“N”的表达式 为数组中第一个元素的地址。-
T
的元素数组”将其类型隐式转换为“指向T
的指针”,并将计算结果 与您的问题有关?假设以下几行 code:
我们将数组表达式
arr
作为参数传递给foo
,因为arr
不是sizeof
的操作数。 > 或&
,其类型从“int
的 10 元素数组”隐式转换为“指向int
的指针”。正在将指针值传递给foo
,不是数组 事实证明,在函数参数声明中,
T a[]
和T a[N]
是 的同义词。T *a
; 所有三个都将a
声明为指向T
的指针,而不是T 的数组
。我们可以将
foo
的原型定义写为或
两者含义相同;两者都将
a
声明为指向int
的指针。现在让我们看看多维数组。假设以下代码:
表达式
arr
的类型为“10-element array of 20-element array ofint
”。根据上述规则,它将隐式转换为“指向int
的 20 元素数组的指针”。因此,foo
的原型定义可以写为或
再次声明,
a
都声明为指针,而不是数组。这就是为什么您可以在函数参数声明中删除最左边(并且仅最左边)的数组索引。
Except when it is the operand of the
sizeof
or unary&
operators, or is a string literal being used to initialize an array in a declaration, an expression of type "N-element array ofT
" will have its type implicitly converted to "pointer toT
and will evaluate to the address of the first element in the array.What does any of that have to do with your question?
Assume the following lines of code:
We pass the array expression
arr
as an argument tofoo
. Sincearr
is not an operand of eithersizeof
or&
, its type is implicitly converted from "10-element array ofint
" to "pointer toint
". Thus, we are passing a pointer value tofoo
, not an array.It turns out that in a function parameter declaration,
T a[]
andT a[N]
are synonyms forT *a
; all three declarea
as a pointer toT
, not an array ofT
.We can write the prototype definition for
foo
asor
Both mean the same thing; both declare
a
as a pointer toint
.Now let's look at multidimensional arrays. Assume the following code:
The expression
arr
has type "10-element array of 20-element array ofint
". By the rule described above, it will implicitly be converted to "pointer to 20-element array ofint
". Thus, the prototype definition forfoo
can be written asor
Again, both declare
a
as a pointer, not an array.This is why you can drop the leftmost (and only the leftmost) array index in a function parameter declaration.