【问题标题】:Does the address of the array equal to that of its first element in C++?数组的地址是否等于它在 C++ 中的第一个元素的地址?
【发布时间】:2015-11-11 09:11:42
【问题描述】:

这可以在 C 中得到保证,因为 WG14/N1570 中有以下句子:

6.2.5/20 ... 数组类型描述了一个连续分配的非空对象集,具有特定的成员对象类型,称为元素类型。

但是在WG21/N4527中,即在C++中,对应的句子变成了

8.3.4/1 ...数组类型的对象包含一个连续分配的非空集合,由 N 个 T 类型的子对象组成。

而“描述”一词改为“包含”,不能保证数组的地址等于其第一个元素的地址。这种改变是有意的还是无意的?如果是故意的,数组的地址是否等于它在 C++ 中的第一个元素的地址?如果是,C++标准中的哪一段可以保证这一点?

【问题讨论】:

    标签: c++ arrays language-lawyer memory-address


    【解决方案1】:

    我认为它没有在任何地方明确说明,但我相信它来自5.3.3 Sizeof

    n 元素数组的大小是元素大小的 n 倍

    唯一可以存储在数组起始地址的是数组的第一个元素。

    【讨论】:

    • 为什么它可以是最后一个元素?如果我以反向索引顺序放置子对象,它会改变数组的大小?
    • @LanguageLawyer 我不明白这个问题。第一个元素是索引为零的元素。
    • @molbdnilo 第一个元素是索引为零的元素 是的。为什么一定要存放在数组的起始地址?
    【解决方案2】:

    在 C++ 中,它通过 4.2/1 数组到指针的转换 [conv.array] 来保证,(我用粗体表示)

    “N T 数组”或“未知边界数组”类型的左值或右值 of T”可以转换为“pointer to T”类型的纯右值。 结果 是指向数组第一个元素的指针。

    这意味着如果你想在 C++ 中获取一个数组的地址,你会得到一个指向数组第一个元素的指针。即

    int a[10];
    int* p1 = a;     // take the address of array
    int* p2 = &a[0]; // take the address of the first element of the array
    

    标准保证p1p2 将指向同一个地址。

    【讨论】:

    • 但这并没有说明数组的地址。它只是说一个数组(既不是它的地址也不是指向这个数组的指针)可以转换为指向它的第一个元素的指针。即使它说指向数组的指针可以转换为指向其第一个元素的指针,它也没有说转换保持指针中存储的值相同。
    • @Shenke 我已经添加了一些解释,作为我对引用标准的理解。
    • 在您的示例中,数组的地址只是&a。所以我要问的是(void *)(&a) == (void *)a是不是真的。
    • @Shenke 抱歉目前在标准中找不到相关内容。仅供参考:stackoverflow.com/questions/8412694/address-of-array
    • 没关系。不管怎么说,还是要谢谢你。 @molbdnilo 可能会给出正确答案。
    【解决方案3】:

    这取决于你所说的“数组地址”。

    如果你问一个数组,当转换为一个指针时,是否给出等于它的第一个元素的地址的结果,那么答案是肯定的。例如;

    #include <iostream>
    
    void func(int *x, int *y)
    {
         std::cout << "x and y are ";
         if (p != q) std::cout << "NOT ";
         std::cout << " equal\n";
    }
    
    int main()
    {
        int x[2];
    
        func(x, &x[0]);
    }
    

    这将始终报告两个指针相等。宋元瑶解释了原因。

    但是,x 实际上并不是一个指向数组的指针(在这段代码中也没有转换为一个)。如果将main()func()的调用改为

      func(&x, &x[0]);
    

    那么该语句甚至不会编译。原因是&amp;x(数组x的地址)不是指向int的指针——它是指向两个int的数组的指针,并且不能隐式转换为指向int.

    但是,值将是相同的,可以通过运行此代码来演示。

    #include <iostream>
    
    void func2(void *x, void *y)
    {
         std::cout << "x and y are ";
         if (p != q) std::cout << "NOT ";
         std::cout << " equal\n";
    }
    
    int main()
    {
        int x[2];
    
        func2(&x, &x[0]);     // both pointers implicitly converted to void * when calling func2()
    }
    

    【讨论】:

    • 是的,我想问的是,为什么两个指针中存储的两个值在最后的代码中是一样的。我想在 C++ 标准中找到证据。
    • 我当前的机器上没有 C++ 标准的副本,所以无法查找。但是,我确实记得有句话大意是&amp;x 产生一个与x 内存中的起点相对应的地址(即,“start”表示作为@ 表示的一部分的字节的最小地址987654334@).
    • 是的,我知道这些话。但问题是为什么数组的起点是它的第一个元素?也许在它的第一个元素之前还有其他东西(可能是填充,我不知道,或者只是因为标准允许它而无意义的东西)。
    • 数组的对齐方式由其元素的对齐方式决定。其结果之一是在数组元素之前或之间没有填充。仅填充(可能)对具有不同大小(和对齐方式)成员的结构或类起作用。
    猜你喜欢
    • 2020-05-23
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 2017-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    相关资源
    最近更新 更多