BlockLune's Blog

Home Tags About

二维数组到底是啥啊...

published at 2022-11-16
c & c++ array pointer

一维数组还是比较容易理解的,但是二维数组,我始终没弄清楚这玩意儿是按照什么规则从二维的样子转成一维然后存起来的,也因此常常犯下下标写反了的错误。我觉得是时候详细地理一理这玩意儿到底是个啥了…

怎么转成了一维?

要知道二维数组到底是怎么转成了一维存在内存里,或者说,我到底是应该从前往后(前面的一个数字先不动,先让后边的数字动)读这个数组,还是从后往前(后面的一个数字先不动,先让前面的数字动)读这个数组,其实方法很简单 —— 我们只要把数组里每个元素的地址输出来就行了。比如下边这串代码:

#include <iostream>

using namespace std;

int main()
{
    int a[2][3] = {0};
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cout << "&a[" << i << "]"
                 << "[" << j << "] = " << &a[i][j] << " " << endl;
        }
    }
    return 0;
}

可能的输出如下:

&a[0][0] = 0x61fe00
&a[0][1] = 0x61fe04
&a[0][2] = 0x61fe08
&a[1][0] = 0x61fe0c
&a[1][1] = 0x61fe10
&a[1][2] = 0x61fe14

可以看到,正确的读法应该是:从前往后,前面的保持不动,从最后一个开始变化。

也就是说,对于 a[2][3] 这样一个数组,应该这么理解:a[2][3] 前面的 [2] 表示这是一个包含两个元素的数组,后面的 [3] 表示前面所说的两个元素每一个都是包含三个元素的数组。

赋初值的一些问题

知道了上边的东西,所以我们知道,我们可以写一个类似 int a[][3] = {0,0,0,0,0,0}; 的玩意儿,却不能写一个 int a[2][] = {0,0,0,0,0,0} 的玩意儿 —— 相当于第二个方括号里边是告诉了编译器后边这一串数字按几个为一组,由于 {} 中元素个数不足是会往后边自动补零的,所以少了这个每组几个的参数,编译器就不知道你这到底有多少个元素了。

用指向数组的指针(数组指针)来实现一个其中一维可以动态调整的二维数组?

类似上边的赋初值时候的问题,这个动态的二维数组的内层,也就是按几个为一组的那一层,必须是已经确定的,例如,我们依然创建一个 2*3 的二维数组,其中前面的 2 是在运行时确定的:

#include <iostream>

using namespace std;

int main()
{
    int n = 2;
    int(*p)[3] = new int[n][3];
    int now = 1;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < 3; j++)
        {
            p[i][j] = now;
            now++;
        }
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < 3; j++)
            cout << p[i][j] << " ";
        cout << endl;
    }
    return 0;
}

输出结果如下:

1 2 3
4 5 6

能不能用 int** p 来创建一个两个维度都能变化的二维数组?

不知道啊就是说…