数组指针如何存储其大小?

#include "stdio.h" #define COUNT(a) (sizeof(a) / sizeof(*(a))) void test(int b[]) { printf("2, count:%d\n", COUNT(b)); } int main(void) { int a[] = { 1,2,3 }; printf("1, count:%d\n", COUNT(a)); test(a); return 0; } 

结果很明显:

 1, count:3 2, count:1 

我的问题:

  1. 声明“a”时存储的长度(计数/大小)信息在哪里?
  2. 当“a”传递给test()函数时,为什么长度(计数/大小)信息会丢失?

在C语言中没有“数组指针”这样的东西。

尺寸不存储在任何地方。 a不是指针, aint[3]类型的对象,这是编译器在编译时熟悉的事实。 因此,当您要求编译器在编译时计算sizeof(a) / sizeof(*a) ,编译器知道答案是3

当你将a传递给函数时,你有意要求编译器将数组类型转换为指针类型(因为你将函数参数声明为指针)。 对于指针, sizeof表达式会产生完全不同的结果。

  1. 声明“a”时存储的长度(计数/大小)信息在哪里?

它不存储在任何地方。 sizeof运算符(在COUNT()宏中使用)返回整个数组的大小,当它被赋予一个真正的数组作为操作数时(就像在第一个printf()

  1. 当“a”传递给test()函数时,为什么长度(计数/大小)信息会丢失?

不幸的是,在C中,函数的数组参数是虚构的。 数组不会传递给函数; 该参数被视为指针,并且在函数调用中传递的数组参数被“衰减”为一个简单的指针。 sizeof运算符返回指针的大小,该指针与用作参数的数组的大小无关。

作为旁注,在C ++中,您可以将函数参数作为对数组的引用 ,在这种情况下,完整的数组类型可供函数使用(即,参数不会衰减为指针, sizeof将返回完整数组的大小)。 但是,在这种情况下,参数必须与数组类型完全匹配(包括元素数),这使得该技术最常用于模板。

例如,以下C ++程序将执行您期望的操作:

 #include "stdio.h" #define COUNT(a) (sizeof(a) / sizeof(*(a))) template  void test(int (&b)[T]) { printf("2, count:%d\n", COUNT(b)); } int main(int argc, char *argv[]) { int a[] = { 1,2,3 }; printf("1, count:%d\n", COUNT(a)); test(a); return 0; } 
  1. 无处。
  2. 因为它没有存储在第一位。

当您在main()引用数组时,实际的数组声明定义是可见的,因此sizeof(a)以字节为单位给出数组的大小。

当你在函数中引用数组时,参数实际上是’ void test(int *b) ,并且指针的大小除以它指向的东西的大小恰好在32位平台上为1,而在具有LP64架构的64位平台上(或者实际上,在像Windows-64这样的LLP64平台上)它将是2,因为指针是8字节而int是4字节。

没有通用的方法来确定传递给函数的数组的大小; 你必须明确和手动传递它。


来自评论:

我还有两个问题:

  1. 你是什​​么意思“……实际的声明是可见的……”? 编译器(或OS)可以通过sizeof(a)函数获取长度信息吗?
  2. 为什么指针&(a [0])不包含长度信息作为指针“a”?
  1. 我认为你在学习C或其他更现代的语言之前学过Java。 归根结底,它归结为“因为这就是C的定义方式”。 操作系统没有涉及; 这是纯编译器问题。

    • sizeof()是一个运算符,而不是一个函数。 除非您正在处理VLA(可变长度数组),否则它将在编译时进行求值并且是一个常量值。

    main() ,数组定义(当我说’声明’时我错过了),当sizeof()运算符应用于实际数组的名称 – 而不是函数的数组参数 – 然后返回的大小是数组的大小(以字节为单位)。

  2. 因为这是C而不是Algol,Pascal,Java,C#,……

    C不存储数组的大小 – 句点。 这是生活中的事实。 并且,当数组传递给函数时,大小信息不会传递给函数; 数组’衰减’到指向数组的第0个元素的指针 – 并且只传递该指针。

 1. Where is the length(count/size) info stored when "a" is declared? 

它没有存储。 编译器知道它是什么,因此知道它的大小。 因此编译器可以用实际大小替换sizeof()

 2. Why is the length(count/size) info lost when "a" is passed to the test() function? 

在这种情况下,b被声明为指针(即使它可能指向a)。 给定指针,编译器不知道指向的数据的大小。

  1. 声明“a”时存储的长度(计数/大小)信息在哪里?

无处。 这个问题没有意义BTW。

  1. 当“a”传递给test()函数时,为什么长度(计数/大小)信息会丢失?

传递给函数时,数组衰减为指针(指向第一个元素)。 所以答案是’无处’并且类似于前一个问题,这个问题再没有任何意义。

数组指针不存储大小。 但是, []类型实际上不是指针。 这是一种不同的类型。 当你说int a[] = {1,2,3}; 你定义了3个元素的数组,并且由于它是这样定义的,sizeof(a)给出了整个数组的大小。

然而,当你将参数声明为int a []时,它与int * a几乎相同,而sizeof(a)将是指针的大小(巧合地,它可能与int的大小相同,但并非总是如此) 。

在C中,没有办法将大小存储在指针类型中,因此如果需要大小,则必须将其作为附加参数传递或使用struct