最近,我意识到如果我在堆栈上创建一个数组,那么以下值将等于它:
- 变量本身在堆栈上的地址
- 该变量的值(即相同的指针)
- 数组第一个元素的地址
结果是,当我创建一个类型为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;
}
型
当在堆栈上创建一个数组时(考虑一个int的例子),前8个字节将同时包含一个指向数组的指针(即指向这个变量本身的指针),以及数组的前2个元素,这是怎么可能的呢?
我的猜测是变量的值(数组第一个元素的地址)没有存储在任何地方。
我通过GodBolt检查了这个,但我不擅长组装,我不能100%确定我的猜测是正确的。
的数据
3条答案
按热度按时间w9apscun1#
当在堆栈上创建一个数组时,我们(考虑一个int的例子)在前8个字节中同时包含一个指向数组的指针(即指向这个变量本身的指针)和数组的前2个元素,这是怎么可能的呢?
这是不可能的。您误解了您的输出。在大多数情况下,当数组类型的子表达式出现在表达式中时,它会自动转换为指向第一个数组元素的指针。这是左值转换通常规则的特殊例外,其结果是
字符串
实际上,并不打印数组的内容。它100%等效于
型
这种行为在C++诞生时从C继承而来,并且从那时起一直保持不变。
我的猜测是变量的值(数组第一个元素的地址)没有存储在任何地方。
注意,数组和指针根本不是一回事。数组的地址确实没有以任何可访问的形式存储在内存中。但是数组的值是由其元素的值组成的集合,它肯定存储在内存中。
tzxcd3kk2#
在C++中使用std::array和std::vector。如果没有必要,不要挂在指向数组的指针上。如果需要指针,可以在std::array和std::vector上使用
.data()
方法字符串
qxgroojn3#
不同之处在于
dynamicArray
是指针,而automaticArray
是数组。更简单的情况是
dynamicArray
。new int[5] {0};
分配一个数组并返回指向其第一个元素的指针。字符串
也就是说,你有一个指向
int
的指针。它的值是新分配的数组的第一个元素的地址。因此&dynamicArray[0] == dynamicArray
。然而,该指针的地址是其他远程地址,因为指针与实际数组分开存储。当
automaticArray
的时候事情就不一样了。在内存中你只有型
就是这样。你缺少的是数组到指针的衰减。在这一行中,
型
所有三个地址都是相同的,因为
automaticArray
在传递给std::ostream::operator<<
时会衰减为指针。这是因为没有重载会引用5个整数的数组。你可以自己写一个。为了说明,考虑一下:型
Which outputs:
你不会真的写这样的代码,但这只是为了证明
automaticArray
不是指针。它是一个数组。它可能会衰减为指向数组第一个元素的指针。这就是在你的代码中发生的事情,因为没有<<
重载接受数组的引用。但是如果你通过引用传递数组,那么就没有-指针衰减发生。在上面的例子中,automaticArray
是一个数组,arr
是对该数组的引用。不涉及指针。