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

Why isn't the size of an array parameter the same as within main?

提问人:Chris_45 提问时间:12/29/2009 最后编辑:LundinChris_45 更新时间:11/7/2018 访问量:76013

问:

为什么作为参数发送的数组的大小与 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));
}
C 数组函数 大小

评论


答:

110赞 13 revs, 3 users 89%Prasoon Saurav #1

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

所以

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*) 的值

评论

2赞 Prasoon Saurav 12/29/2009
在 C++ 中,您可以通过引用函数来传递数组,但在 C 中不能这样做。
14赞 Aric TenEyck 12/29/2009
您需要将数组的大小作为单独的参数传递。那么数组的大小将是 sizeof(*p_someArray) * length
15赞 Alok Singhal 12/29/2009
次要 nit:运算符返回一个类型的对象,因此您应该使用 (C99) 打印它,或者如果您在调用中使用上述内容,则将其强制转换为。sizeofsize_t%zuint%dprintf
4赞 Prasoon Saurav 12/29/2009
阿洛克的说法是正确的。在 printf(..) 中使用不正确的格式说明符是 UB。
2赞 AnT stands with Russia 12/31/2009
@Chris_45:C 没有引用,但在 C 中,您可以通过指向整个数组的指针传递数组,如: 。在函数内部,您可以使用取消引用运算符访问数组: 。这将与在 C++ 中使用引用具有相同的效果。void PrintSize(int (*p_someArray)[10])*sizeof(*p_someArray)
-3赞 plinth 12/29/2009 #2

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

评论

4赞 Jens 5/15/2011
对不起,这个答案具有误导性。数组既不是“松散大小”,也不是“指向内存的指针”。数组的大小非常精确,数组名称代表指向其第一个元素的指针的位置由 C 标准精确指定。
5赞 Khaled Alshaya 12/29/2009 #3

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

 // 10 is superfluous here! You can pass an array of different size!
void PrintSize(int p_someArray[10]);
3赞 user195488 12/29/2009 #4

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

评论

2赞 David R Tribble 12/30/2009
通常,您应该始终将数组的大小(元素数)与数组一起传递给函数,除非您有其他方法来确定其大小(例如,字符串数组末尾的空字符终止符)。char[]
0赞 alk 12/31/2017
请问什么是“未知数组”?
0赞 Pavel Radzivilovsky 12/29/2009 #5

该行为是设计使然。

函数参数声明中的相同语法与局部变量定义中的语法完全不同。

原因在其他答案中有所描述。

3赞 MR. 12/29/2009 #6

不能将数组传递给函数。

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

#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));
}
16赞 Pete Kirkham 12/30/2009 #7

正如其他人所说,当用作函数参数时,数组会衰减为指向其第一个元素的指针。还值得注意的是,sizeof 不计算表达式,并且在与表达式一起使用时不需要括号,因此您的参数实际上根本没有被使用,因此您不妨用类型而不是值来编写 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] ) );
}
18赞 user240312 12/30/2009 #8

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

13赞 S.C. Madsen 12/30/2009 #9

因此,您需要将数组的长度作为第二个参数传递。当你在编写代码时,你既声明了一个恒定大小的数组,然后又将该数组传递给一个函数,那么让数组长度常量在代码中出现几个位置是一件很痛苦的事情......

K&R 来救援:

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

所以现在你可以做,例如:

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

评论

0赞 weefwefwqg3 1/31/2017
如果数组的大小在编码时不可用,而仅在运行时可用,该怎么办?有没有其他方法可以在不硬编码其大小的情况下计算数组的大小?
0赞 S.C. Madsen 2/8/2017
显示的方法仅在数组的声明“在视图中”时才有效。对于所有其他情况,您必须手动传递数组长度。
5赞 Alexandre C. 6/23/2010 #10

在 c++ 中,你可以通过引用传递一个数组来达到这个目的:

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

评论

1赞 alk 12/31/2017
这对 C 问题有什么帮助?
6赞 Walter 10/5/2014 #11

你发现的行为实际上是 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 ratio 返回 2。

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

这并不意味着不可能将数组传递给函数。您可以通过将数组嵌入到结构中来绕过这个疣(这基本上是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 */
}
0赞 dagrawal 12/18/2014 #12

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

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

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

评论

0赞 alk 12/31/2017
在 C 语言中,没有“引用调用”。
0赞 alk 12/31/2017
"当您打印数组的大小时,它将打印第一个元素的大小。不,它打印指针的大小。
-1赞 RichardGeerify 6/11/2016 #13

在 'C' 编程语言中,'sizeof()' 是运算符,他以字节为单位返回对象的大小。'sizeof()' 运算符的参数必须是左值类型(integer,float number,struct,array)。因此,如果你想知道一个数组的大小(以字节为单位),你可以做得非常简单。只需使用'sizeof()'运算符,并为其参数使用数组名称。例如:

#include <stdio.h>

main(){

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

}

在 32 位系统上的输出将是: n 的大小为:40.因为 32 系统上的无整数是 4 字节。在 64x 上,它是 8 字节。在本例中,我们在一个数组中声明了 10 个整数。所以结果是 '10 * sizeof(int)'。

一些提示:

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

sizeof(name_of_the_array) / sizeof(array_type)

产品代码: #include

主(){

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

}

评论

3赞 MicroVirus 6/11/2016
欢迎来到 StackOverflow,感谢您写下答案。不幸的是,这并没有解决这个问题,特别是关于局部变量和函数参数之间的区别,即使两者看起来都是 类型 。sizeof(n)sizeof(arg)int[10]