最近我意识到,如果我们在堆栈上创建一个数组,那么以下值将等于它:变量本身在堆栈上的地址,这个变量的值(即同一个指针),以及作为该数组的第一个元素的地址。事实证明,当我们创建类型为
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%确定我的猜测是正确的。
在 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
}
区别在于
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
是对该数组的引用。不涉及指针。