【问题标题】:Whats the value of &y[0] == &x.a?&y[0] == &x.a 的值是多少?
【发布时间】:2019-08-01 12:10:53
【问题描述】:

从家庭作业中得到这段代码。我应该弄清楚&y[0] == &x.a 的价值是多少。顺便说一句,很抱歉没有正确格式化,我尽力了。

所以我的方法是; y[0] = 1&y[0]表示1的地址,也就是数组中的0

x.a 最让我困惑。这是否意味着结构 x 的元素 a?所以x.a == 1?它的地址也是0?所以布尔值会显示为true(1),因为0 == 0。但是解决方案说它是错误的,但是为什么呢?

struct my_struct {
    int a;
    double b;
    int c; 
};
my_struct x = { 1, 2, 3 }; 
int y[] = { 1, 2, 3 };

我期待输出1,但显然是0,但为什么呢?

【问题讨论】:

  • a 未初始化。这可能是解决方案返回 false 的原因。 a的值基本上是随机的。
  • xy 是两个不同的对象,你为什么希望它们存储在同一个地址?是不是 & 让你感到困惑?
  • 您在此处比较地址,因此比较两个不同的变量将始终返回 false
  • 为什么你会期望两个不同变量的地址相同? struct x 和数组 y 都在堆栈上分配,因此将各自获得自己的堆栈内存。
  • 除非它们都是联合体的成员,否则my_struct 的实例不会与int 数组的任何元素共同占用任何内存。所以&y[0] == &x.a 应该比较假(即 0)。您对两者使用相同的初始化程序 {1, 2, 3} 的事实无关紧要 - 编译器使用该数据初始化 xy,但这不会影响 x(或其成员)或y(或其元素)在内存中。

标签: c++ arrays struct


【解决方案1】:

&y[0]表示1的地址,在数组中为0

差不多,但不完全。 address-of 运算符提供给您的地址是绝对值,而不是相对于“容器”的地址。所以&y[0]实际上与y相同,&x.a实际上&x相同。

y 是一个可以转换为指向第一个元素的指针的值。这必须并且将与 &x 不同(在数字上),后者占用不同的内存部分。

| x.a | <- &x points here
| x.b |
| x.c |
| y[0]| <- y points here
| y[1]|
[ y[2]| 

以上所有内容都忽略了这些指针可能具有不同类型的事实。在检查代码的正确性时,这对编译器很重要,但最终会被丢弃,因为所有地址实际上都变成了数值。

【讨论】:

  • &amp;y[0] 比较等于 y,因为为了进行比较,y 将被转换为与 &amp;y[0] 等效的指针。
  • @Walter 是的,很难在没有技术错误的情况下回答这类问题。这是过于简单化和过于复杂的解释之间的界限。我已将x 更改为&amp;x,希望这足以清除该部分。 技术上 y 也不会明确指向任何东西,直到我们强制它衰减到一个指针...
  • 这里有什么不清楚的地方:可以用==比较两种不同的指针类型吗?
  • @Walter &amp;y[0]&amp;x.a 都有 int* 类型。
  • @BartekBanachewicz 确实。
【解决方案2】:

这个表达式

&y[0] == &x.a

比较两个不同对象的地址(指针)。第一个属于数组y(即y[0]是数组的第一个元素),而第二个属于my_struct类型的对象(a是对象x的数据成员)。

对象占用不同程度的内存。

所以表达式产生假,即不同对象的地址不相等。

我可以举一个例子,当比较两个不同的指针(即不同类型的指针)得出真值时。

考虑以下示例

struct my_struct {
    int a;
    double b;
    int c; 
};
my_struct x = { 1, 2, 3 }; 

然后( void * )&amp;x == ( void * )&amp;x.a 计算为1

注意:强制转换是必需的,因为操作数具有不同的类型,并且没有从一种类型到另一种类型的隐式转换。

再举一个例子

#include <iostream>
#include <iomanip>

int main()
{
    int y[] = { 1, 2, 3 };

    std::cout << std::boolalpha 
              << ( ( ( void * )&y == ( void * )y ) && ( ( void * )&y == ( void * )&y[0] ) && ( y == &y[0] ) ) 
              <<'\n';
}

程序输出是

true

所有三个表达式&amp;yy&amp;y[0] 具有相同的值(地址)。 (在表达式中使用的数组很少有例外会被转换为指向其第一个元素的指针。)

【讨论】:

    【解决方案3】:

    两个单独声明的变量的地址几乎永远不会相等 (==)。

    在这里,my_struct x = { 1, 2, 3 };int y[] = { 1, 2, 3 }; 分开声明。当它们被声明时,它们在内存中被赋予了自己的空间来占据,所以它们在内存中的两个不同的空间中。虽然struct my_struct x 和array int y[] 存储的值相同,但它们都存储在各自的内存空间中。

    如果您想查看实际的内存位置,可以使用简单的cout 打印语句来实现:

    cout << "&y[0]: " << &y[0] << endl;
    cout << "&x.a: " << &x.a << endl;
    

    【讨论】:

      【解决方案4】:

      &amp;y[0]&amp;x.a 是不同的地址。如果您想检查它们是否相同,您可以编写一个简单的程序。你会看到结果。

      struct my_struct {
          int a;
          double b;
          int c; 
      };
      
      int main()
      {
      
          my_struct x = { 1, 2, 3 }; 
          int y[] = { 1, 2, 3 };
          std::cout << "&y[0] = " << &y[0] << "\n&x.a = " << &x.a << "\n&y[0]==&x.a = " << (&y[0]==&x.a);
      }
      

      输出是:

      &y[0] = 0x72261501a440
      &x.a = 0x72261501a450
      &y[0]==&x.a = 0 
      

      所以我们可以看到 &y[0] 和 &x.a 的不同值。它们是不相同的。还有&amp;y[0]==&amp;x.a = 0,意思是false

      【讨论】:

        【解决方案5】:

        &amp; 将返回内存地址(取决于您的目标平台,通常是 16 到 64 位数字,代表物理内存地址,或由操作系统映射到物理内存的虚拟逻辑地址(在现代操作系统上,如 linux 或 MacOS ,用户进程默认看不到真实的物理地址))。

        所以这部分来源:

        my_struct x = { 1, 2, 3 }; 
        int y[] = { 1, 2, 3 };
        

        将内存中的结构和数组都实例化为全局变量,即它们将具有0x12345678等内存地址,并且它们不会重叠,如果my_struct的大小例如为20字节, x 地址是 0x1000,数组 y 将在内存中某处超出它(y 的地址也是第一个元素的地址,在 C/C++ 中,数组是零成本抽象,即数组开始的地方,第一个元素已经存储,其余元素在连续的内存地址之后)。

        因此,您的原始表达式&amp;y[0] == &amp;x.a 是将数组中特定元素的一个(绝对)地址与结构成员的(绝对)地址进行比较,并且因为它们是在不同的内存区域中实例化的,所以地址肯定会不同(如只要数组的索引在范围内)= false。您甚至不需要检查精确比较的地址的详细信息。

        但为了完整起见,y[0] 是数组y 的第一个元素,其地址与y 本身相同。如果有&amp;y[1],那是第二个数组元素的地址,类型为int,这意味着&amp;y[1]等于y+1和/或((void*)y) + sizeof(int) ...在CPU机器代码术语中,这意味着如果数组从内存地址 0x2000 开始,并且int 在您的目标平台上是 64 位,则第二个元素从地址 0x2008 开始(距数组开头 +8 个字节(64 位))。

        &amp;x.a同样是完整地址,成员a的实际值驻留在内存中,所以如果结构实例x从地址0x1000开始,则x.a的地址在这种情况下也是0x1000 (再次零成本抽象,它是简单的结构类型,如果它是类类的,具有虚函数,则成员 a 可能会在通常放在类开头的隐式虚拟表指针之后有点偏移/ struct instance ...但这是特定于实现/平台的,即取决于特定编译器如何实现虚拟函数/调用)。例如&amp;x.b 的地址将是 0x1008(我再次假设 64 位 int 类型,并且我假设在 my_struct 中没有应用额外的填充,不同的假设/条件 b 从开始的偏移量的结构可能与 +8 不同)。

        【讨论】:

          【解决方案6】:

          &amp; 为您提供对象的地址。

          &amp;y 为您提供数组y 的地址。

          &amp;y[0] 为您提供数组y 中第一个元素的地址,它等于&amp;y

          &amp;x 为您提供结构体x的地址

          &amp;x.a 为您提供结构 x 的第一个成员的地址,该地址等于 &amp;x

          由于xy 位于不同位置,因此地址不同。

          【讨论】:

          • 作者:“...等于&amp;x.a”你的意思是:“...等于&amp;x”。
          • 并且:“...等于&amp;y”不正确,它是:“...等于y”。
          • @PaulEvans 在值相等的意义上是正确的。从类型不相等的意义上说,这是不正确的。 “等于y”也不完全正确,因为y 是一个数组;不是指针,所以类型仍然不同。 y 在很多情况下都会衰减为指向第一个元素的指针,而这个衰减的指针正好等于 &amp;y[0]
          猜你喜欢
          • 2014-12-15
          • 2014-06-04
          • 1970-01-01
          • 2022-03-29
          • 2021-07-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-05
          相关资源
          最近更新 更多