C-不转换为其类型的指针时,数组名称是什么?

时间:2019-04-06 02:54:40

标签: c arrays pointers type-conversion

所以有一段时间我对数组名称和指针感到困惑。

我们声明int a[10]; 在路上的某个地方还有a&a

因此我了解了语法的工作原理。 a是阵列名称。当它不用作sizeof &等的操作数时,它将被转换或“衰减”,因此它返回一个指向整数的指针,该指针保存着数组第一个元素的地址。 / p>

如果将数组名用作sizeof&的操作数,则其类型为int (*)[10]。所以我想类型是不同的,因为不会发生“衰减”。

但我仍然不了解&a的工作方式。我的理解是,它为我提供了whatever it was before the "decay" happened的地址。因此,在指针发生“衰减”之前,它是什么?编译器如何与“原始”一起计算&a

相比之下,如果我们声明int *p; 然后在代码中的某个位置添加了&pp ...

在这种情况下,指向整数p的指针具有一个单独的指针单元格及其地址,并且该地址处的值将是我们为其分配的任何地址(或该地址预分配处的垃圾值)

a在声明为int a[10]时未在内存中分配单独的指针单元。我听说它在寄存器%ebp上有偏移量。那么,编译器在评估&a时会发生什么?指向整数的指针的“衰减”未发生,首先没有单独的“指针”。那么,编译器将a标识为什么?当看到一元&一元运算符正在使用数组名称作为操作数时,它将做什么?

3 个答案:

答案 0 :(得分:3)

给出:

int a[10];

对象a的类型为int[10]。在大多数(但不是全部)上下文中,表达式 a“衰减”到指针表达式。表达式产生类型为int*的值,等效于&a[0]

  

但我仍然不了解&a的工作方式。我的理解是,它为我提供了“衰变”发生之前的地址。.因此,在指针发生“衰变”之前,它是什么以及编译器如何工作?评估&a的“原始”?

那不是很正确。在&a中,衰减根本不会发生。 a的类型为“ 10 int的数组”(int[10]),因此&a的类型为“ 10 int的数组的指针”({{ 1}})。

这没什么特别的。对于类型为int(*)[10]的任何名称foo,表达式some_type的类型为“指向&foo的指针”。 (令人困惑的是,这是数组名称​​不会表现异常的罕见情况之一。)

最好将单词“数组”和“指针”视为形容词而不是名词。因此,我们可以拥有一个数组对象,一个数组表达式,一个数组类型等等,但是“数组”是模棱两可的。

此:

some_type

定义一个名为int a[10]; 的数组对象(并分配a个字节来保存它)。没有创建指针对象。您可以通过获取对象或其任何元素的地址来创建指针 value 。这与任何其他类型的对象没有什么不同。定义类型为4 * sizeof (int)的对象不会创建类型为some_type的对象,但是您可以通过计算对象的地址来创建类型为some_type*的值。

答案 1 :(得分:1)

  

然后,编译器将as标识为什么,并且在编译时会做什么   看到一元&运算符正在使用数组名称作为操作数?

编译器将a标识为10个元素的整数数组,当看到&运算符时,它将返回该数组的地址。

就像它将int i = 3;视为整数,并将&i视为该整数的地址一样。

答案 2 :(得分:0)

关于获取数组的地址:数组本身就是一个对象,因此它既有大小又有地址(尽管获取地址很少有用)。

将数组转换为指向其第一个元素的指针是强制类型的一种形式。仅当替代方法是编译错误时才会发生。

例如,您无法将数组与指针进行比较,因此将数组(隐式)强制(强制)到int*(至其第一个元素),然后比较指针类型。在C语言中,您可以比较任何指针类型。 C不在乎(尽管它可能会发出警告)。

正如您所说,这实际上是将int*int(*)[10]进行类型比较。由于数组直接保存其数据,因此这些地址必须具有相同的地址(无论键入如何)。因此,数组的地址将始终是其第一个元素的地址。

但是,获取数组的大小并不是错误,因此sizeof(a)可以获取整个数组的大小,因为无需强制即可使其合法。因此,这与sizeof(int[10])相同。

您所说的其他情况sizeof(&a)确实是sizeof(int(*)[10])