运算符大小反转行为

时间:2019-07-18 05:41:11

标签: c sizeof

我们知道,当我们使用数组时,它保存第一个元素的地址,而&array是存储整个数组的地址,当我在printf中使用它时为true,但是在sizeof运算符中,这是相反的行为,为什么

我正在Windows 7上使用带有GCC的代码块

 int main(void)
  {
    int c[5];
      printf(" %d  %d  %d  %d\n",c,c+1,&c,&c+1);\\when we add 1 in "c" it add more 4 bytes and when "&c+1" it add 20 byte witch is true

       printf(" %u  %u ",sizeof(c),sizeof(&c));\\But when we print first element size (with "c") it give 20 byte and when print (With "&c") whole arry size it give 4 byte


         return 0;
            }

\我不明白为什么要解释

2 个答案:

答案 0 :(得分:6)

我认为您需要了解的是,&array仍然是一个指针,只是类型不同。

对于int arr[]={4,3,2,1,0}

这样的数组
  • 大多数情况下,arr&arr[0]相同,即int *,但是对于sizeof运算符,它的行为有所不同(请参见下面的注释)。当传递给sizeof运算符时,它将为您提供整个数组的大小,在这种情况下为sizeof(int [4])
  • &arr的类型为int (*)[4],它是一个指针。

因此,要获取数组中的元素数量,您应该执行类似的操作

printf ("Number of elements = %zu", sizeof(arr)/sizeof(arr[0]));
            / *(size of the entire array / size of one element in the array) */

引用C11,第6.3.2.1章(强调我的

  

除非它是sizeof运算符, _Alignof运算符或   一元&运算符,或者是用于初始化数组的字符串文字,该表达式具有   类型“类型数组” 转换为类型为“类型指针” 的表达式   数组对象的初始元素,不是左值。 [...]

说,

  • sizeof产生类型为size_t的结果,您应该使用%zu格式说明符来打印结果。
  • 要打印指向对象的指针,必须使用%p格式说明符并将相应的参数强制转换为void *

答案 1 :(得分:4)

首先,如果要打印sizeof的结果,则正确的格式为%zusizeof给您size_t,而不是int。要打印指针,请使用%p并将参数强制转换为(void *)

第二,要获得数组中元素的数量,为sizeof arr / sizeof arr[0](整个数组的大小除以单个元素的大小,也可以写为sizeof arr / sizeof *arr)。

也就是说,您要询问的内容确实与数组无关。例如,如果您这样做

char c;

然后sizeof &c将为4(在32位平台上),但是&c + 1将为您提供比&c高1字节而不是4字节的内存地址。

这是因为指针算术是以指向类型(而不是指针本身的类型)为单位进行的。也就是说,您需要比较ptr + 1sizeof *ptr(或&var + 1sizeof var)。

在您的代码中,四个表达式中的三个很简单:

  • sizeof &arr为4,因为&arr的类型为“指向5个整数的数组的指针”,并且您使用的是32位平台,因此指针为4个字节。
  • sizeof arr为20,因为arr的类型为“ 5个整数的数组”,而int的大小为4字节,因此该数组占用5 * 4 = 20字节。
  • &arr + 1为您提供一个arr后的内存地址。这就像问“ arr是否是数组的元素,下一个元素将从何处开始?”。由于arr的大小为20个字节,因此arr前一个的内存地址将增加20个字节。

剩下奇怪的了:

  • arr + 1会编译,因为arr会在此处衰减为指针。也就是说,由于数组不是sizeof&的操作数,因此它求值为指向第一个元素的指针,如&arr[0]。并且在&arr[0] + 1中,指向的类型为int,因此添加1意味着步进到内存中下一个int,相距4个字节。