我知道有很多类似的问题,但是我找不到答案。
在下面的代码中将二维[3] [4]数组传递给函数时,对于最后一个printf()我们要递增3的情况,编译器如何知道将指针递增多远x 4个内存位置,如果函数参数中缺少数字3? 我的意思是,为什么仅arr [] [4]足够,而不是[3] [4]?谢谢
#include <stdio.h>
#include <stdlib.h>
int Fun(int arr[][4])
{
printf("%p\n", arr); // address of first element
printf("%p\n", arr[0] + 1); // address increments by 4, pointing to next "inner array"
printf("%p\n", arr + 1); // how does it know to increment address by 3 x 4 here? The complete array size
}
int main()
{
int arr[3][4] =
{
1,2,3,4,
5,6,7,8,
9,10,11,12
};
printf("%p\n", arr);
printf("%p\n", arr[0] + 1);
printf("%p\n", arr + 1);
printf("Passing to function\n");
Fun(arr);
return 0;
}
答案 0 :(得分:1)
首先,Fun
的定义应为:
int Fun(int arr[][4])
int Fun(int* arr[][4]);
而不是您拥有的东西。
接下来,当评估Fun(arr)
时,arr
会自动从3个4个int
数组的数组转换为4个int
数组的指针。同样,在Fun
的声明中,int arr[][4]
被自动调整为指向4个int
数组的指针。因此,如果正确声明Fun
,则参数类型和参数类型将匹配。
您也可以将Fun
声明为:
int Fun(int (*arr)[4])
与上面相同,这是由于将对上述声明进行自动调整。请注意,此处的星号通过括号与arr
分组。这使它成为指向int
数组的指针,而不是指向int
的指针数组。
现在,关于要打印的内容,在main
中:
printf("%p\n", arr);
在此语句中,arr
将自动转换为指向其第一个元素的指针,因此它将变为指向4 int
的数组的指针。然后打印该指针的值。注意:从技术上讲,在打印指针时,应像const void *
一样将它们转换为void *
或printf("%p\n", (const void *) arr);
。但是,忽略这种情况目前不会造成问题。
printf("%p\n", arr[0] + 1);
在此语句中,arr[0]
是arr
的第一个元素。该第一个元素是4 int
的数组,它会自动转换为指向其第一个元素的指针。因此arr[0]
成为第一个int
的指针。然后加1将指针前进到下一个int
。根据您的C实现,结果可能是地址arr
后四个字节。 (它的字节数可以不同,但是今天最常见的是四个。)
printf("%p\n", arr + 1);
在此语句中,arr
被转换为指向其第一个元素的指针,该元素为4个int
的数组。加1会指向下一个元素的指针,该元素是下一个4 int
的数组。因此,这很可能会将地址增加16个字节。
然后,在Fun
中:
printf("%p\n", arr); // address of first element
这里arr
是指向4 int
数组的指针。打印其值,其地址与printf
中相应的main
相同。
printf("%p\n", arr[0] + 1); // address increments by 4, pointing to next "inner array"
此处arr[0]
是arr
指向的对象,它是4个int
的数组。由于它是一个数组,因此它将自动转换为指向其第一个元素int
的指针。因此,这指向第一个int
。然后向下一个int
加1前进,这又产生了与printf
中相应的main
相同的地址。
printf("%p\n", arr + 1); // how does it know to increment address by 3 x 4 here? The complete array size
在这种情况下,arr
是指向4 int
的数组的指针,加1会将其前进到下一个4 int
的数组,因此结果可能是16个字节超出了arr
的值,这又产生了与printf
中相应的main
相同的地址。
如果您在printf
和Fun
中为main
语句看到了不同的值,则可能是由于int*
的声明不正确,以及int *
在您的C实现中为8个字节,而int
为4个字节。该错误会使某些增量加倍。您应该看不到增量的三个的倍数。
关于第一维,Fun
不需要知道第一维,因为它永远不会以第一维为单位前进任何指针。它仅接收指向4个int
数组的指针,并且不需要知道那里有3个此类数组。
答案 1 :(得分:1)
详细的answer by Eric Postpischil清楚地显示了OP代码中的所有问题。
我想指出,将指针传递给正确的类型会使编译器执行正确的指针算术:
#include <stdio.h>
#include <stdlib.h>
void Fun(int (*arr)[3][4])
{
printf("Address of the first element: %p\n", (void *)*arr);
printf("Address of the second row: %p\n", (void *)(*arr + 1));
printf("Address after the last element: %p\n", (void *)(arr + 1));
}
void Fun_vla(size_t rows, size_t cols, int (*arr)[rows][cols])
{
printf("Address of the first element: %p\n", (void *)*arr);
printf("Address of the second row: %p\n", (void *)(*arr + 1));
printf("Address after the last element: %p\n", (void *)(arr + 1));
}
int main()
{
int arr[3][4] =
{
{1,2,3,4},
{5,6,7,8},
{9,10,11,12}
};
Fun(&arr);
puts("");
Fun_vla(3, 4, &arr);
return 0;
}