C++ 为什么是c/c++;允许在函数调用中省略多维数组最左边的索引?
我只是想知道,在将多维数组传递给函数时,为什么允许省略多维数组最左边的索引?为什么不止一个索引?编译器如何找出省略了一个索引的大小?在声明中 实际上,不能完全忽略最右边或最左边的维度 然而,只有当您有一个初始化器时,才能为您推导出最左边的值 在函数参数列表中 当按值将数组传递给函数时,实际上是在传递指向该数组第一个元素的指针。是的,从语法上看,你传递的是一个数组,但不是 考虑:C++ 为什么是c/c++;允许在函数调用中省略多维数组最左边的索引?,c++,c,compiler-construction,language-design,C++,C,Compiler Construction,Language Design,我只是想知道,在将多维数组传递给函数时,为什么允许省略多维数组最左边的索引?为什么不止一个索引?编译器如何找出省略了一个索引的大小?在声明中 实际上,不能完全忽略最右边或最左边的维度 然而,只有当您有一个初始化器时,才能为您推导出最左边的值 在函数参数列表中 当按值将数组传递给函数时,实际上是在传递指向该数组第一个元素的指针。是的,从语法上看,你传递的是一个数组,但不是 考虑: void f(int ar[3]) void f(int ar[]) 这两种语言的语法都比较混乱: void f(
void f(int ar[3])
void f(int ar[])
这两种语言的语法都比较混乱:
void f(int* ar)
void f(int (*ar)[3])
没有数组的痕迹,更不用说三个元素中的一个了
现在:
这是一种令人困惑的等效语法:
void f(int* ar)
void f(int (*ar)[3])
其中int(*)[3]
是指向数组第一个元素的指针类型(指向int[3]
)
总之,不要太注意类似数组的语法,它看起来像
[]
;它并不真正代表真正发生的事情。除非它是sizeof
或一元&
运算符的操作数,或者是用于在声明中初始化数组的字符串文字,否则类型为“N-element array ofT
”的表达式将隐式转换为“指向T
的指针,并将计算为数组中第一个元素的地址
这些和你的问题有什么关系
假设以下代码行:
int arr[10] = {0,1,2,3,4,5,6,7,8,9};
foo(arr);
我们将数组表达式arr
作为参数传递给foo
。由于arr
不是sizeof
或&
的操作数,其类型被隐式地从“int的10元素数组”转换为“指向int的指针”。因此,我们将指针值传递给foo
,而不是数组
事实证明,在函数参数声明中,ta[]
和ta[N]
是ta*a
的同义词;这三个函数都将a
声明为指向T
的指针,而不是T
的数组
我们可以将foo
的原型定义编写为
void foo(int *a) // <- foo receives a pointer to int, not an array
表达式arr
的类型为“10元素数组/20元素数组/int”。根据上述规则,它将隐式转换为“指向int
的20个元素数组的指针”。因此,foo
的原型定义可以写成
void foo(int (*a)[20]) // <-- foo receives a pointer to an array, not an array of arrays
void foo(int(*a)[20])/其他答案描述了C标准如何处理数组到指针的转换,以及这如何影响函数声明,但我觉得他们没有讨论为什么,所以我来看看
在C语言中,数组代表内存中紧密压缩的元素
A -> _ _ _ _ _ _ ...
i: 0 1 2 3 4 5 ...
在上面的示例中,每个数组元素的宽度为1。为了找到第i个元素,我们必须找到第i个地址。(请注意,最左边的尺寸(大小)在这里并不重要)
现在考虑多维数组:
B -> [_ _ _][_ _ _][_ _ _][_ _ _]...
i: 0 0 0 1 1 1 2 2 2 3 3 3
j: 0 1 2 0 1 2 0 1 2 0 1 2
^first row ^third row
要找到A[i][j]
的偏移量,我们需要跳过i行(3*i),然后跳过j元素->(3*i+j)。请注意,这里也不需要第一个维度的大小
现在应该很清楚,使用数组时不需要最左边的大小,只有在创建数组时才需要
既然不需要给出最左边索引的维度,那么出于完整性考虑,为什么不给出它呢?毕竟,这是在Pascal编程语言(a C)中完成的
大多数在数组上运行的函数在所有可能的数组长度上都是一样的,因此指定大小只会影响重用它们的能力
比如,你为什么要这样做
int sum(int arr[10]){
int s = 0, i;
for(i=0; i<10; i++){
s += arr[i];
}
return s;
}
int和(int arr[10]){
int s=0,i;
对于(i=0;i你能提供一些代码作为例子吗?“‘数组’作为多维数组的声明必须对所有维度都有边界,除了第一个”第一个不能的证据在哪里?……啊。我隐约记得,如果它只有一个维度,而你将其留空,它会被视为一个指针。void foo(int bar[][3] );
?@Philip:Pfft,关于他传递给函数的部分是对问题的编辑。我会补充我的答案。@Tomalak:没有注意到OP的编辑。我当然不是想暗示你什么,我只是好奇。@Mark:你在想什么时候函数有一个参数int ar[]
;但是,这与声明无关。:)您的绘图帮助很大。非常感谢
B -> [_ _ _][_ _ _][_ _ _][_ _ _]...
i: 0 0 0 1 1 1 2 2 2 3 3 3
j: 0 1 2 0 1 2 0 1 2 0 1 2
^first row ^third row
int sum(int arr[10]){
int s = 0, i;
for(i=0; i<10; i++){
s += arr[i];
}
return s;
}
int sum(int arr[], int n){
int s = 0, i;
for(i=0; i<n; i++){
s += arr[i];
}
return s;
}