vja*_*n27 14 c c++ compiler-construction language-design
我只是想知道为什么在将数组传递给函数时允许省略多维数组的最左边索引?为什么不是一个以上的索引?编译器如何在省略一个索引的情况下找出大小?
hug*_*omg 15
其他答案描述了C标准如何处理数组到指针转换以及它如何影响函数声明,但我觉得它们没有进入原因,所以我在这里......
在C中,数组代表内存中紧密排列的元素.
A -> _ _ _ _ _ _ ...
i: 0 1 2 3 4 5 ...
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,每个数组元素都是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
Run Code Online (Sandbox Code Playgroud)
要找到A[i][j]我们需要跳过i行(3*i)然后跳过j个元素 - >(3*i + j)的偏移量.请注意这里也不需要第一个维度的大小.
现在应该很清楚,使用数组时不需要最左边的大小,只有在创建它时才需要它.
既然没有必要给出最左边索引的维度,那么为什么不完全放弃呢?毕竟,这是Pascal编程语言(C当代)所做的.
好吧,大多数在数组上运行的函数对于所有可能的数组长度都是一样的,所以指定大小只会损害你重用它们的能力.
例如,为什么呢
int sum(int arr[10]){
int s = 0, i;
for(i=0; i<10; i++){
s += arr[i];
}
return s;
}
Run Code Online (Sandbox Code Playgroud)
当你可以这样做时:
int sum(int arr[], int n){
int s = 0, i;
for(i=0; i<n; i++){
s += arr[i];
}
return s;
}
Run Code Online (Sandbox Code Playgroud)
至于省略多个维度,这在使用普通多维数组时是不可能的(因为你需要知道维度以了解第一行何时结束而第二行何时开始).但是,如果您愿意为临时空间花费一些(少量)额外内存,则完全可以使用指针指针:http://www.eskimo.com/~scs/cclass/int/sx9b.html
在一份声明中
实际上,你不能完全忽略最右边或最左边的尺寸.
但是,如果您有初始化程序,则只能为您推断最左侧.
在函数参数列表中
当您通过值将数组传递给函数时,实际上是将指针传递给该数组的第一个元素.是的,它看起来就像你传递一个数组一样,但是,不,你不是.
考虑:
void f(int ar[3])
void f(int ar[])
Run Code Online (Sandbox Code Playgroud)
两者都是等效的语法混淆:
void f(int* ar)
Run Code Online (Sandbox Code Playgroud)
没有数组的痕迹,更不用说三个元素之一了.
现在:
void f(int ar[][3])
Run Code Online (Sandbox Code Playgroud)
对于等效语法,这是令人困惑的语法:
void f(int (*ar)[3])
Run Code Online (Sandbox Code Playgroud)
where int (*)[3]指向数组第一个元素的指针的类型(指向int[3]).
总之,不要过分关注类似于数组的语法[]; 它并不能代表真正发生的事情.