*A 和 A[0] 之间的大小差异

问题描述

void Size(int A[],int size){
    printf("Size of A = %d\nSize of A[0] = %d\n\n",sizeof(A),sizeof(A[0]));
}

这样做时,我得到了意想不到的答案:

Size of A = 8
Size of A[0] = 4

据我所知,当我们将数组传递给函数时,我们使用“通过引用传递”并通过检查 sizeof(A) 我们应该得到数组类型的大小。请问你能帮我解决这个问题吗?

解决方法

因为您不能将数组作为参数传递给函数(它们会衰减为指针),所以编译器会默默地将数组参数的声明更改为指针。所以参数 int A[] 实际上不是一个数组——它实际上是一个指针。所以你正在打印一个指针的大小。

,

当您将数组作为函数的参数传递时,它会衰减为指向该数组第一个元素的指针,int A[] 变为 int *A,实际上您可以在函数声明,一样。

sizeof A 是该指针的字节大小,就像使用 sizeof(int*) 一样,而 sizeof A[0] 是数组第一个元素的字节大小,这是一个int,就好像您使用了 sizeof(int)

注意通过引用传递不是该语言的特性,也许您正在考虑C++,您正在做的是通过值传递指针(传递存储在指针中的内存地址),通常被pass by pointer引用。

,

在 C 中,通过引用传递意味着通过指向对象的指针间接传递对象。因此,取消引用指针,您将可以直接访问该对象。

当数组指示符传递给函数时,它会隐式转换为指向其第一个元素的指针。来自 C 标准(6.3.2.1 左值、数组和函数指示符)

3 除非是 sizeof 运算符或一元 & 的操作数 运算符,或者是用于初始化数组的字符串文字, 类型为“类型数组”的表达式被转换为 类型为“指向类型的指针”的表达式,指向首字母 数组对象的元素并且不是左值。如果数组对象 有寄存器存储类,行为未定义。

另一方面,具有数组类型的参数被编译器调整为指向数组元素类型的指针。来自 C 标准(6.7.6.3 函数声明符(包括原型))

7 将参数声明为“类型数组”应进行调整 到“类型的限定指针”,其中类型限定符(如果有) 是在数组类型派生的 [ 和 ] 中指定的那些。 如果关键字 static 也出现在数组的 [ 和 ] 中 类型派生,然后对于每次调用该函数, 相应的实参应提供访问第一个 具有至少与指定的元素一样多的数组元素 大小表达式。

所以这个函数声明

void Size(int A[],int size);

相当于

void Size(int *A,int size);

因此,数组的所有元素实际上都是通过指向数组第一个元素的指针通过引用传递的。使用指针算法,您可以直接访问数组的任何元素。

注意带有 sizeof 运算符的表达式的类型是 size_t。因此,您必须在调用 %zu 时使用转换说明符 %d 而不是 printf

printf("Size of A = %zu\nSize of A[0] = %zu\n\n",sizeof(A),sizeof(A[0]));

在此调用中,sizeof( A ) 产生指针 A 的大小,这是由于传递的数组隐式转换为指向其第一个元素的指针,并且由于编译器将函数参数调整为指向数组元素类型的指针.

,

这个警告(没有 -Wall)应该使结果不那么意外

 warning: 'sizeof' on array function parameter 'A' will return size of 'int *' [-Wsizeof-array-argument]

通过引用传递意味着您不传递数组本身,而只传递对它的引用,即地址又名指针。该指针只知道它指向的是什么 (int),所以 sizeof *A 就像 sizeof A[0]

即使是 VLA

void Size(int size,int A[size]) 

sizeof 给出同样的警告。

但是为什么在这种情况下数组参数的 decay 会有例外,因为 size 变量包含所有信息?