【问题标题】:Multidimensional arrays memory storage overview多维数组内存存储概述
【发布时间】:2016-07-27 05:12:53
【问题描述】:

最近开始学习c++中的指针和引用(不只是平时的使用,各种方式,近期不想遇到问题)。

从我的角度来看,一维静态分配数组类似于 int* const 指针。我的问题是,当我使用指针动态分配时,指针本身具有除第一个元素之外的其他内存地址,而在一维数组中并非如此。这是一个例子

int a[5];
cout<<&a<<" "<<&a[0]<<"\n";
int* t=new int[10];
cout<<&t<<" "<<&t[0]<<"\n";

输出是:

0x6afed0 0x6afed0
0x6afecc 0xcb0e40

我想不出一维数组是如何存储的,在 1 个 4 字节的块中,您可以存储一个值或一个地址。 我还尝试了2D阵列,还有更多的交叉点。

q = new int*[10];
for (i=0;i<10;i++)
    q[i] = new int[i+1];
cout<<&q<<" "<<&q[0]<<" "<<&q[0][0]<<"\n";
int b[10][10];
cout<<&b<<" "<<&b[0]<<" "<<&b[0][0]<<"\n";

输出:

0x6afee4 0xe40e40 0xe41240
0x6afd54 0x6afd54 0x6afd54

如果有人能启发我并解释这些数组是如何存储的,我将不胜感激。

编辑:更具体地说,我知道如何存储由指针使用 new 关键字动态创建的数组是合乎逻辑的。但是 &a 和 &a[0] 如何具有相同的值,如果 a 应该存储 a[0] 的地址。那块内存(&a)存储什么然后呢? a[0] 的值或 a[0] 的地址]。希望我在我的问题是什么。

【问题讨论】:

  • 查看矿井的答案:stackoverflow.com/questions/23581342/… span>
  • 感谢您的回答。但是正如 arnobpl 所说,您会感到困惑,因为您可以像指针一样在数组名称上使用 *,因此您认为它们是相同的(它们不是)。
  • 我明白他们不一样,我没有说别的。也许我的答案并不完全清楚。 span>
  • 对不起,当我说“你”时,我指的是一般人,而不是你:P

标签: c++ pointers multidimensional-array


【解决方案1】:

数组是包含 N 个对象的连续块的对象,其中 N 是某个恒定大小。数组的地址是数组的开头,所以第一个对象的地址和数组的地址是一回事。

指向数组的指针是唯一的对象。因为它是自己的对象,所以它有自己的地址,与它所拥有的地址不同。所以int* t=new int[10];&amp;tt的地址,&amp;t[0]是new分配的数组的第一个元素的地址。

【讨论】:

  • 所以实际上静态声明的数组不是指针?(即使您可以执行 *(a+i) 或 p=a 其中 p 是指针)。我认为 *x 告诉编译器“给我存储在 x 包含的地址中的内容”,所以如果 &a=&a[0],*a 应该给出错误的答案。所以我应该把它们分别当作两个不同的东西来对待?
  • @BaltatuAndreiMircea 数组不是指针。它们是两种完全不同的东西。不幸的是,在许多情况下,数组可能会衰减为指针,因此很容易混淆它们。 *a*(a + 0) 相同,与a[0] 相同。好玩吧?
【解决方案2】:

数组是语言的一等实体,所以当你声明一个数组变量时

int a[10];

编译器知道数组的维度。分配动态存储空间时

int* p = new int[10];

只有你和分配器知道这个空间有多大。

在数组版本中,a数组。它有一个地址,但该地址在编译期间由编译器保存。在分配范式中,p 是数据的地址,直到运行时才知道。

使人们感到困惑的是,总的来说,两者似乎可以互换:您可以同时使用指针和数组数学运算,在需要指针的地方使用其中任何一个:

void f(int*);

int a1 = a[1];
f(a);
int p1 = p[1];
f(p);

这是设计使然,它被称为array-pointer-equivalence,强调我的:

C 中围绕数组和指针的许多混淆可以追溯到对这句话的误解。说数组和指针是“等价的”意味着它们既不是相同的,也不是可以互换的。这意味着数组和指针算法被定义为可以方便地使用指针来访问数组或模拟数组。换句话说,正如 Wayne Throop 所说,它是 ''指针算术和数组索引 [that] 在 C 中是等价的,指针和数组是不同的。''

具体来说,等价的基石是这个关键定义:

对出现在表达式中的 T 数组类型对象的引用衰减(除了三个例外)成指向其第一个元素的指针;结果指针的类型是指向T的指针。

【讨论】:

  • 非常详尽的回答,非常感谢。所以因为静态声明数组的地址和大小在编译时是已知的(在大多数情况下,因为使用新的编译器,你可以用 x 一个 int 变量做 int a[x]),当衰减到一个指针并丢失一个维度,它仍然强制该指针具有与其他维度的正确边界。与指针或指向指针的指针一样,它不能设置任何东西,因为事情会在运行时发生变化。我明白了,再次感谢!
【解决方案3】:

t 是在堆栈上声明的指针,它保存堆上数组的地址。 &amp;t 获得t 的地址,也就是t 在堆栈上的位置。如果要访问数组的第一个成员,可以使用*tt[0]。当您使用方括号表示法时,C++ 会根据 t 的类型自动取消引用并执行指针运算。

但是,&amp;t[0] 本质上为您提供了t[0] 的地址,这就是它与&amp;t 不同的原因,因为&amp;t 位于堆栈上,而&amp;t[0] 位于堆上。因此,如果您想要t[0] 的地址,您可以使用该符号,否则如果您只想要这些值,请坚持使用t[0]

【讨论】:

  • 谢谢,会添加进去
【解决方案4】:

&amp;t 获取指针t 的地址,而不是第一个元素的地址。第一个元素的地址就是t(因为t是一个int*,指向内存块)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 1970-01-01
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 2019-07-27
    相关资源
    最近更新 更多