【问题标题】:sizeof-operator reverse behaviorsizeof-operator 反向行为
【发布时间】:2019-07-18 05:41:11
【问题描述】:

我们知道,当我们使用数组时,它保存第一个元素的地址,而 &array 存储整个数组地址,当我在 printf 中使用它时它是正确的,但在 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;
            }

\我不明白为什么请解释

【问题讨论】:

  • 因为 “我们知道 [...]” 的事情并不准确。您必须重新阅读 arr&arr 到底是什么
  • OT:在循环中打印相同的内容似乎很奇怪。您是否打算在printf 语句中使用i
  • sizeof(arr)/sizeof(&arr) 是错误的,没有意义。它像正确的东西,所以很容易混淆
  • 您为sizeof 使用了错误的格式说明符,因此行为未定义。 sizeof 表达式的类型为 size_t,而不是 int。您的编译器应该对此发出警告。您应该认为您打印的所有地址都不正确。
  • @alk 哦,看起来有一个单独的gcc 警告选项:-Wformat-signedness。启用后,它将给出您想要的已签名与未签名警告。但请注意,-Wall 不会启用此警告。

标签: c sizeof


【解决方案1】:

我想这里你需要知道的是,&array 仍然是一个指针,只是类型不同而已。

对于像int arr[]={4,3,2,1,0}这样的数组

  • 大多数情况下,arr&arr[0] 相同,即int *,但使用sizeof 运算符,它的行为会有所不同(请参阅下面的注释)。当传递给 sizeof 运算符时,它会为您提供整个数组的大小,即在本例中为 sizeof(int [4])
  • &arrint (*)[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 运算符或 一元 & 运算符,或者是用于初始化数组的字符串文字,该表达式具有 type ''array of type'' 被转换为一个类型为 ''pointer to type'' 的表达式,它指向 到数组对象的初始元素并且不是左值。 [...]

也就是说,

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

【讨论】:

  • printf("%zu %zu",sizeof(arr),sizeof(&arr)); === 输出为“zu zu”
  • @ManpreetSidhu 哪个环境/编译器?
  • 元素数 = zu
【解决方案2】:

首先,如果你想打印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 个字节。

【讨论】:

  • 很好的解释,但我的困惑并没有消失 #include int main(void) { int c[5]; printf(" %d %d %d %d\n",c,c+1,&c,&c+1);\\当我们在 "c" 中添加 1 时,它会增加 4 个字节,而当 "&c+1"它添加 20 字节女巫是真的 printf(" %u %u ",sizeof(c),sizeof(&c));\\但是当我们打印第一个元素大小(使用“c”)时它给出 20 字节,当打印 (使用 "&c") 整个数组大小,它给出 4 字节 \\我不明白为什么返回 0; }
猜你喜欢
  • 2023-03-25
  • 2011-01-13
  • 1970-01-01
  • 1970-01-01
  • 2019-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多