二维数组如何存储在内存中?

时间:2016-07-05 13:25:30

标签: c++ arrays c++11 pointers multidimensional-array

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a[101][101];
    a[2][0]=10;
    cout<<a+2<<endl;
    cout<<*(a+2)<<endl;
    cout<<*(*(a+2));
    return 0;
}

为什么a + 2和*(a + 2)的值相同?提前谢谢!

5 个答案:

答案 0 :(得分:5)

a是一个2D数组,表示一个数组数组。但是当在适当的上下文中使用时,它衰减指向数组的指针。所以:

  • a+2中,a衰减到指向大小为101的int数组的指针。当你传递给ostream时,你得到这个数组的第一个元素的地址,即{{ 1}}
  • 根据定义<{1}}中的
  • &(a[2][0]):它是一个大小为101的数组,从*(a+2)开始。它衰减到指向int的指针,当你将它传递给ostream时,你得到它的第一个元素的地址,它仍然是a[2]
  • 根据定义,
  • a[2][0] <{em> &(a[2][0])。当你将它传递给ostream时,你得到它的int值,这里是10。

但要注意:**(a+2)a[2][0]都是指向同一地址的指针(a + 2a[2]相同),但它们是指向不同类型的指针:指向大小为101的int数组,后者为int。

答案 1 :(得分:1)

二维数组是一个数组数组,因此它在内存中存储如下:

char v[2][3] = {{1,3,5},{5,10,2}};

Content: | 1 | 3 | 5 | 5 | 10 | 2
Address:   v  v+1 v+2 v+3 v+4 v+5

要访问v [x] [y],编译器会将其重写为:*(v + y * M + x)(其中M是指定的第二个维度)

例如,要访问v [1] [1],编译器会将其重写为*(v + 1*3 + 1) =&gt; *(v + 4)

请注意, 与指针指针(char **)相同。 指向指针的指针不是数组:它包含存储单元的地址,并包含另一个地址。

要使用指向指针的指针访问二维数组的成员,请执行以下操作:

char **p;
/* Initialize it */
char c = p[3][5];
  1. 转到p;
  2. 内容指定的地址
  3. 将偏移量添加到该地址(在我们的示例中为3);
  4. 转到该地址并获取其内容(我们的新地址)。
  5. 将第二个偏移添加到该新地址(在我们的示例中为5)。
  6. 获取该地址的内容。
  7. 通过传统的二维数组访问成员时,这些步骤是:

    char p[10][10];
    char c = p[3][5];
    
    1. 获取p的地址并将第一个偏移量(3)加上一行(10)的维数。
    2. 将第二个偏移量(5)添加到结果中。
    3. 获取该地址的内容。

答案 2 :(得分:1)

如果您有这样的数组

T a[N];

然后将数组的名称隐式转换为指向其第一个元素的指针,但极少数例外(例如在sizeof运算符中使用数组名称)。

因此,例如,在表达式( a + 2 )中,a转换为T *类型&a[0]

相对于您的示例wuth数组

int a[101][101];
表达式中的

a + 2

a转换为int ( * )[101]类型的右值并指向数组的第一个“行”。 a + 2指向数组的第三个“行”。行的类型为int[101]

表达式*(a+2)为第三行提供了类型int[101]的数组。并且依次在表达式中使用的该数组将转换为指向其第一个int *类型元素的指针。

它与第三行占用的内存区域的起始地址相同。

只有表达式( a + 2 )的类型为int ( * )[101],而表达式*( a + 2 )的类型为int *。但是两者都产生相同的值 - 数组a的第三行占用的内存区域的起始地址。

答案 3 :(得分:0)

数组的第一个元素与数组本身位于同一位置 - 没有&#34;空格&#34;在数组中。

cout << a + 2中,a被隐式转换为指向其第一个元素&a[0]的指针,而a + 2a&#39的位置;第三个元素&a[2]

cout << *(a + 2)中,数组*(a + 2) - 即a[2] - 将转换为指向其第一个元素&a[2][0]的指针。

由于a的第三个元素的位置和a的第三个元素的第一个元素的位置相同,因此输出相同。

答案 4 :(得分:0)

我将尝试解释编译器如何映射内存:

让我们考虑一个更实际的多维数组示例:

int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

您可以执行命令

x/10w a

在GDB中查看内存:

0x7fffffffe750: 1   2   3   4
0x7fffffffe760: 5   6   7   8
0x7fffffffe770: 9   0

每个元素都存储在 int 类型中( 32位/ 4字节)。 所以矩阵的第一个元素已存储在:

1) a[0][0] -> 0x7fffffffe750
2) a[0][1] -> 0x7fffffffe754
3) a[0][2] -> 0x7fffffffe758
4) a[1][0] -> 0x7fffffffe75c
5) a[1][1] -> 0x7fffffffe760
6) a[1][2] -> 0x7fffffffe764
7) a[2][0] -> 0x7fffffffe768
        ...

命令:

std::cout << a + 2 << '\n'

它会打印地址 0x7fffffffe768 因为 指针aritmetic: a 的类型为 int ** ,因此它是指向指针的指针。 a + 2是a [0](第一行)+ 2.结果是指针 到第三排。

*(a + 2)推断第三行,即{7,8,9}

第三行是int数组,这是一个指向int的指针。

然后运营商&lt;&lt;将打印该指针的值。