所以,我一直都知道在 C/C++ 中传递的数组“对象”只包含数组中第一个对象的地址。
指向数组“对象”的指针和它包含的值如何相同?
有人可以向我指出更多信息,也许是关于装配中的所有工作方式。
简短回答:指向数组的指针被定义为与指向数组第一个元素的指针具有相同的值。这就是 C 和 C++ 中的数组的工作方式。
学究式的回答:
C 和 C++ 具有右值和左值表达式。左值是&
可以应用运算符的东西。它们也有隐式转换。一个对象在被使用之前可能会被转换成另一种类型。(例如,如果您调用sqrt( 9 )
then9
将转换为double
因为sqrt( int )
未定义。)
数组类型的左值隐式转换为指针。隐式转换更改array
为&array[0]
. 这也可以static_cast< int * >( array )
在 C++ 中显式写为 , 。
这样做是可以的。铸造到void*
是另一回事。void*
有点难看。并且用括号铸造 as(void*)array
也很丑陋。所以请避免(void*) a
在实际代码中使用。
您正在混合两种不相关(实际上是相互排斥)的东西,这会造成更多混乱。
首先,您正确地说明“在 C/C++中传递的数组对象只包含数组中第一个对象的地址”。这里的关键词是“传递”。实际上,数组不能作为数组对象传递。数组不可复制。每当您在函数参数列表中使用数组样式声明时,它实际上被解释为指针声明,即它是您“传递”的指针,而不是数组。但是,在这种情况下,您的平等不成立
void foo(int a[]) {
assert((void *) &a == (void *) a); // FAIL!!!
}
上面的断言肯定会失败——等式不成立。因此,在这个问题的上下文中,您必须忘记您“传递”的数组(至少对于上面示例中使用的语法)。您的相等性不适用于已被指针对象替换的数组。
其次,实际的数组对象不是指针。并且没有必要将术语对象放入引号中。数组是成熟的对象,尽管具有一些特殊的属性。所讨论的相等性确实适用于尚未失去其“数组性”的实际数组,即尚未被指针对象替换的数组对象。例如
int a[10];
assert((void *) &a == (void *) a); // Never fails
这意味着整个数组的地址在数字上与其第一个元素的地址相同。这里没有什么不寻常的。事实上,在 C/C++ 中,结构类型可以观察到相同的(本质上)相等性
struct S { int x; } a;
assert((void *) &a == (void *) &a.x); // Never fails
即整个结构对象的地址与其第一个字段的地址相同。
指向数组“对象”的指针和它包含的值如何相同?
数组是存储多个元素的连续内存块。
显然,数组中的第一个元素位于某个地址。
第一个元素和实际数组的开头之间没有数据。
因此,第一个元素与数组具有相同的地址。
请阅读以下主题
http://www.cplusplus.com/forum/beginner/29595/
它基本上解释了(&a != a)
由于类型差异(因为&a
返回指向数组和a
第一个元素的指针),即使它们都指向相同的地址。
由于您将它们都转换为(void*)
仅比较地址值并发现它们相等,这意味着((void*) a == (void*)&a)
正如您所说。这是有道理的,因为数组的地址必须与第一个元素相同。
让我们看看这两个声明:
int a[4];
int * b;
两者a
和b
都具有与 and 兼容的类型int *
,例如,可以作为参数传递给期望的函数int *
:
void f(int * p);
f(a); // OK
f(b); // OK
在 的情况下a
,编译器为 4 个 int 值分配空间。当您使用 namea
时,例如在调用 时f(a)
,编译器只是替换它分配第一个 int 值的地址,因为它知道。
在 的情况下b
,编译器为一个指针分配空间。当您使用 nameb
时,例如在调用 时f(b)
,编译器会生成用于从分配的存储中检索指针值的代码。
说到,那是和&
之间的区别变得明显的时候。始终表示编译器为您的变量分配的存储地址:是这四个 int 值的地址(因此与 just 一致),而是指针值的地址。它们也有不同的类型。a
b
&
&a
a
&b
&a
与 不完全相同a
,尽管它们比较相等。它们有不同的类型:&a
指针和a
数组。您可以注意到不同之处,例如,如果您将sizeof
运算符应用于这些表达式:sizeof(a)
将评估为四个 int 值sizeof(&a)
的大小,而是指针的大小。
好的,所以我认为发生的事情是,当您创建一个数组时,您在某处为该数组分配了空间,并在其他地方创建了指向其第一个对象的指针,而您在代码中传递的是指针。
这实际上是当您在 C++ 中使用 new 或在 C/C++ 中使用 malloc 创建数组时发生的行为。像这样,
int * a = new a[SIZE];
assert((void*)&a==(void*)a); // Always fails
我了解到,对于以 的样式声明的数组int a[SIZE];
,当您尝试将数组传递给函数时,会创建一个指向第一个元素的指针(这称为数组指针衰减)。有趣的是,事实上,正如 AndreyT 所写,
void foo(int a[]) {
assert((void *) &a == (void *) a); // Always fails
}
这表明只有当您尝试传递数组时,才会为int a[SIZE];
.