在栈上声明的数组的值(指针)是如何存储在内存中的?

问题描述 投票:0回答:2

最近我意识到,如果我们在堆栈上创建一个数组,那么以下值将等于它:变量本身在堆栈上的地址,这个变量的值(即同一个指针),以及作为该数组的第一个元素的地址。事实证明,当我们创建类型为

T
且大小为
N
的数组时,堆栈上会出现
sizeof(T)*N
字节的区域。对于下面的代码,所有三个地址都是相同的:

#include <bits/stdc++.h>

using namespace std;

int main() {

    int automaticArray[5] {1, 2, 3, 4, 5};

    cout << "Variable value = " << automaticArray << ", variable adress = " << &automaticArray << ", first element addres = " << &automaticArray[0] << endl;
}

如果对动态内存区域中的数组执行相同的操作,则不会正确。变量本身的地址(将位于堆栈上的地址)将与其余两个值不同。这是合乎逻辑的,因为我们在堆栈上只存储指针,并为其分配了 8 个字节。数组本身位于堆上的某个位置。那些。对于下面的示例,地址不会相同:

#include <bits/stdc++.h>

using namespace std;

int main() {

    int* dynamicArray = new int[5] {0};

    cout << "Variable value = " << dynamicArray << ", variable adress = " << &dynamicArray << ", first element addres = " << &dynamicArray[0] << endl;
}

所以,问题是:当在堆栈上创建数组时,我们(考虑整数的示例)在前八个字节中如何可能同时包含指向数组的指针(即指向该变量本身的指针)和数组的前 2 个元素?

我的猜测是变量的值(数组第一个元素的地址)没有存储在任何地方。我通过GodBolt检查了这一点,但我不擅长组装,而且我不能100%确定我的猜测是正确的。 enter image description here

c++ arrays memory stack
2个回答
0
投票

在 C++ 中使用 std::array 和 std::vector。如果没有必要的话,不要纠结于指向数组的指针。如果你需要一个指针,你可以在 std::array 和 std::vector 上使用

.data()
方法

#include <array>
#include <vector>

// you cannot return "C" style (stack) arrays
// but you can return std::array
std::array<int,4> make_array()
{
    std::array<int,4> values{1,2,3,4};
    return values;
}

int main()
{
    std::array<int,4> array1 = make_array(); // Allocated on the stack

    std::array<int,4> array2{2,3,4,5}; // Also allocated on the stack    

    std::vector<int> vector{1,2,3,4}; // Allocatd (for you) on the heap;

    // when vector goes out of scope memory is deallocated for you
}

0
投票

区别在于

dynamicArray
是指针,而
automaticArray
是数组。

更简单的情况是

dynamicArray
new int[5] {0};
分配一个数组并返回指向其第一个元素的指针。记忆里有你

 ----------------             
 | dynamicArray |   ------
 ----------------        |
                         |
                         v
                        -------------
                        | 0 1 2 3 4 |
                        -------------    

也就是说,你有一个指向

int
的指针存储在某处。它的值是新分配的数组的第一个元素的地址。因此
&dynamicArray[0] == dynamicArray
。然而,该指针的地址是其他一些远程地址,因为
&dynamicArray
存储在其他地方。

automaticArray
事情就不同了。记忆里只有你

                        -------------
                        | 0 1 2 3 4 |
                        -------------    

就是这样。您缺少的是数组到指针的衰减。在这一行

cout << automaticArray << &automaticArray << &automaticArray[0] << endl;

所有三个地址都是相同的,因为

automaticArray
在传递给
std::ostream::operator<<
时会衰减为指针。这是因为没有重载会引用 5 个整数的数组。你可以自己写一个。为了便于说明,请考虑以下内容:

#include <iostream>


std::ostream& operator<<(std::ostream& out, int (&arr)[5]) {
    for (int i=0;i<5;++i) out << arr[i] << " ";
    return out;
}


int main() {

    int automaticArray[5] {1, 2, 3, 4, 5};
    std::cout << automaticArray;
}

哪个输出:

1 2 3 4 5 

您实际上不会编写这样的代码,但这只是为了证明

automaticArray
不是指针。它是一个数组。它可能会衰减为指向数组第一个元素的指针。这就是您的代码中发生的情况,因为没有
<<
重载需要引用数组。但是,如果您通过引用传递数组,则不会发生指向指针衰减。在上面的示例中,
automaticArray
是一个数组,
arr
是对该数组的引用。不涉及指针。

© www.soinside.com 2019 - 2024. All rights reserved.