【问题标题】:Size difference between *A and A[0] [duplicate]*A 和 A[0] 之间的大小差异 [重复]
【发布时间】:2021-10-07 01:00:11
【问题描述】:
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) 我们应该得到数组类型的大小。请问您能帮我解决这个问题吗?

【问题讨论】:

  • C 中没有pass by reference。C 中唯一的类型是按值传递。 C 和 C++ 是非常不同的语言
  • A 是一个数组(即内存地址),在 64 位机器上是 8 个字节。 A[0] 是一个整数,所以是 32 位/4 字节。当您执行sizeof(array) 时,编译器实际上无法为您提供您所期望的标准响应,因为它没有大小(int[] vs int[size]`)
  • @Tibrogargan A 是一个指针,而不是一个数组。
  • @Tibrogargan 你错了,int[]int* 和函数参数是一回事。即使int A[10] 也是一个指针。查看此问题的答案。
  • 您正在比较 AA[0] 的大小,这通常可能不同,而不是像主题声称的那样,*AA[0] 的大小应该是相同的。此外,您需要使用%zu 打印sizeof 值。使用 %d 会调用未定义的行为。

标签: arrays c pointers implicit-conversion sizeof


【解决方案1】:

这个警告(没有 -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 给出同样的警告。

但是在这种情况下,当size变量保存了所有信息时,为什么数组参数的decay会有一个例外呢?

【讨论】:

    【解决方案2】:

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

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

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

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

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

    所以这个函数声明

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

    等价于

    void Size(int *A, int size);
    

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

    注意带有sizeof 运算符的表达式的类型是size_t。所以你必须在printf的调用中使用转换说明符%zu而不是%d

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

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

    【讨论】:

      【解决方案3】:

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

      sizeof A 是该指针的字节大小,就像您使用 sizeof(int*),而 sizeof A[0] 是数组的第一个元素的大小,即 int,它是如果你使用sizeof(int)

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2019-11-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-15
          • 2012-03-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多