为什么数组参数的大小与main中的大小不同?


104

为什么作为参数发送的数组大小与main中的大小不同?

#include <stdio.h>

void PrintSize(int p_someArray[10]);

int main () {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* As expected, 40 */
    PrintSize(myArray);/* Prints 4, not 40 */
}

void PrintSize(int p_someArray[10]){
    printf("%d\n", sizeof(p_someArray));
}

Answers:


103

将数组类型传递给函数时,它会隐式转换为指针类型。

所以,

void PrintSize(int p_someArray[10]) {
    printf("%zu\n", sizeof(p_someArray));
}

void PrintSize(int *p_someArray) {
    printf("%zu\n", sizeof(p_someArray));
}

是等效的。所以你得到的是sizeof(int*)


1
在C ++中,你可以通过参考功能传递数组但不能做,在C.
Prasoon Saurav

13
您需要将数组的大小作为单独的参数传递。然后,数组的大小将为sizeof(* p_someArray)* length
Aric TenEyck 09年

13
次要nit:sizeof运算符返回类型为的对象size_t,因此您应该使用%zu(C99)打印该对象,或者int如果%dprintf调用中使用上述对象,则将其强制转换为。
Alok Singhal

4
阿洛克的说法是正确的。在printf(..)中使用不正确的格式说明符是UB。
Prasoon Saurav

1
@ Chris_45:C没有引用,但是在C中,您可以像下面这样通过指针将数组传递给整个数组void PrintSize(int (*p_someArray)[10])。在函数内部,您可以使用解引用运算符访问数组*sizeof(*p_someArray)。这将与在C ++中使用引用具有相同的效果。
AnT

18

这是一个指针,这就是为什么将数组的大小作为第二个参数传递给函数的常见实现的原因


16

正如其他人所述,数组在用作函数参数时会衰减到指向其第一个元素的指针。还值得注意的是,sizeof不会与表达式一起使用,并且在与表达式一起使用时不需要括号,因此您的参数实际上根本没有被使用,因此您最好将typeof而不是值写成sizeof。

#include <stdio.h>

void PrintSize1 ( int someArray[][10] );
void PrintSize2 ( int someArray[10] );

int main ()
{
    int myArray[10];
    printf ( "%d\n", sizeof myArray ); /* as expected 40 */
    printf ( "%d\n", sizeof ( int[10] ) ); /* requires parens */
    PrintSize1 ( 0 ); /* prints 40, does not evaluate 0[0] */
    PrintSize2 ( 0 ); /* prints 40, someArray unused */
}

void PrintSize1 ( int someArray[][10] )
{
    printf ( "%d\n", sizeof someArray[0] );
}

void PrintSize2 ( int someArray[10] )
{
    printf ( "%d\n", sizeof ( int[10] ) );
}

12

因此,您需要将数组的长度作为第二个参数传递。在编写代码时,您都声明了一个常量大小的数组,然后将该数组传递给函数,让数组长度常量在代码中显示几个位置是很痛苦的。

K&R进行救援:

#define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0])) 

所以现在您可以执行例如:

int a[10];
...
myfunction(a, N_ELEMENTS(a));

如果数组的大小在编码时不可用,而仅在运行时可用,该怎么办?还有其他方法可以在不对数组大小进行硬编码的情况下计算数组的大小吗?
weefwefwqg3

仅当数组的声明为“ in view”时,所示方法才有效。对于所有其他情况,您必须手动传递数组长度。
马德森SC

5

因为数组在作为参数传递时会衰减为指针。尽管您可以通过引用在C ++中传递“数组”并克服此问题,但是C是这样工作的。请注意,您可以将不同大小的数组传递给此函数:

 // 10 is superfluous here! You can pass an array of different size!
void PrintSize(int p_someArray[10]);

5

您发现的行为实际上是C语言的一大弊端。每当您声明带有数组参数的函数时,编译器都会忽略您,并将参数更改为指针。因此,这些声明的行为都类似于第一个声明:

void func(int *a)
void func(int a[])
void func(int a
typedef int array_plz[5];
void func(array_plz a)

在所有四种情况下,a都是指向int的指针。如果将数组传递给func,它将立即衰减为指向其第一个元素的指针。(在64位系统上,64位指针的大小是32位int的两倍,因此sizeof比率返回2。)

此规则的唯一目的是保持与不支持将聚合值作为函数参数传递的历史编译器的向后兼容性。

这并不意味着不可能将数组传递给函数。您可以通过将数组嵌入到struct中来解决这个问题(这基本上是C ++ 11的std :: array的目的):

struct array_rly {
int a[5];
};
void func(struct array_rly a)
{
printf("%zd\n", sizeof(a.a)/sizeof(a.a[0]));  /* prints 5 */
}

或通过将指针传递给数组:

void func(const int (*a)[5])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints 5 */
}

如果数组大小不是编译时常量,则可以对C99可变长度数组使用指针数组技术:

void func(int n, const int (*a)[n])
{
printf("%zd\n", sizeof(*a)/sizeof((*a)[0]));  /* prints n */
}

4

在c ++中,您可以为此目的通过引用传递数组:

void foo(int (&array)[10])
{
    std::cout << sizeof(array) << "\n";
}

1
这对C问题有什么帮助?
ALK

3

在C语言中,没有任何方法可以确定未知数组的大小,因此需要传递数量以及指向第一个元素的指针。


2
通常,除非有其他确定其大小的方法(例如,char[]字符串数组末尾的空字符终止符),否则应始终将数组的大小(元素数)与数组一起传递给函数。
David R Tribble,

请问什么是“ 未知数组 ”?
ALK

3

您不能将数组传递给函数。

如果您真的想打印大小,可以将指针传递给数组,但是它根本不是通用的,因为您还需要为函数定义数组大小。

#include <stdio.h>

void PrintSize(int (*p_anArray)[10]);

int main(void) {
    int myArray[10];
    printf("%d\n", sizeof(myArray)); /* as expected 40 */
    PrintSize(&myArray);/* prints 40 */
}

void PrintSize(int (*p_anArray)[10]){
    printf("%d\n", (int) sizeof(*p_anArray));
}


0

在C语言中,当将数组作为参数传递给函数时,它将自动转换为指针,从一个函数传递给另一个函数的数组称为按引用调用。这就是被调用函数仅接收指向函数第一个元素的指针的原因,这就是原因

fun(int a [])与fun(int * a)类似;

因此,当您打印数组的大小时,它将打印第一个元素的大小。


在C中,没有“ 通过引用调用 ”。
alk

当您打印数组的大小时,它将打印第一个元素的大小。 ”不,它将打印指针的大小。
ALK

-1

在'C'编程中,lan​​guange'sizeof()'是运算符,他以字节为单位返回对象的大小。'sizeof()'运算符的参数必须为左值类型(整数,浮点数,结构,数组因此,如果您想知道数组的大小(以字节为单位),则可以非常简单地进行操作,只需使用'sizeof()'运算符,并为其参数使用数组名称即可,例如:

#include <stdio.h>

main(){

 int n[10];
 printf("Size of n is: %d \n", sizeof(n)); 

}

在32位系统上的输出为:n的大小为:40.因为32系统上的ineteger为4字节,在64x上为8字节,因此在一个数组中声明了10个整数,因此结果为'10 * sizeof( int)”。

一些技巧:

如果我们有一个这样声明的数组'int n [] = {1,2,3,... 155 ..};'。因此,我们想知道此数组中存储了多少个元素。使用以下算法:

sizeof(数组名称)/ sizeof(数组类型)

代码:#include

主要(){

int n[] = { 1, 2, 3, 44, 6, 7 };
printf("Number of elements: %d \n", sizeof(n) / sizeof(int));
return 0;

}


2
欢迎使用StackOverflow,感谢您提出答案。不幸的是,这没有解决问题,特别是关于sizeof(n)局部变量和sizeof(arg)函数自变量之间的区别,即使它们看起来都是type int[10]
MicroVirus 2013年

-3

数组的大小只是松散的。在大多数情况下,数组是指向内存的指针。声明中的大小仅告诉编译器要为数组分配多少内存-它与类型无关,因此sizeof()没什么可做的。


3
抱歉,此答案有误导性。数组都不是“松散大小”的,也不是“指向内存的指针”。数组的大小非常精确,而数组名代表指向其第一个元素的指针的位置由C标准精确指定。
詹斯(Jens)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.