c++ 2D动态阵列中的行和列的指定

hgncfbus  于 2023-08-09  发布在  其他
关注(0)|答案(2)|浏览(105)

下面的清单创建了一个二维动态数组。

#include <iostream>

#define COLS 3
#define ROWS 3

int ** create2d()
{
    int index = 1;
    int** arr = new int*[COLS];
    for (size_t i = 0; i < COLS ; i++)
    {
        arr[i] = new int[ROWS];
        for (size_t j = 0; j < ROWS ; j++)
        {
            arr[i][j] = index++;
            printf("%d (%d) [%d][%d]\t", arr[i][j], &arr[i][j], i,j);
        }
      printf("\n");
    }
  
    return arr;
}

int main()
{
    int** arr = create2d();
    for (int i = 0; i < COLS; i++) 
    {
        delete[] arr[i];
    }
    delete[] arr;
    return 0;
}

字符串

输出

./main
1 (34979536) [0][0] 2 (34979540) [0][1] 3 (34979544) [0][2]
4 (34980608) [1][0] 5 (34980612) [1][1] 6 (34980616) [1][2]
7 (34980640) [2][0] 8 (34980644) [2][1] 9 (34980648) [2][2]


从输出中,我们看到元素的增量和数组元素的地址匹配。
COLSROWS名称是否正确?
如果是这样,这是否意味着在arr[p][q]中,左手索引(p)总是可以被认为是列,而右侧索引(q)总是可以被认为是行?

0s7z1bwu

0s7z1bwu1#

在C和C中,为什么我们说数组是按行为主的顺序存储的?
在数学中,二维矩阵中下标的传统顺序是先放行下标,后放列下标。对于给定的矩阵A,在第m行和第n列中的元素被表示为A(m,n)。正是这种约定迫使我们得出结论,C和C
中的二维数组是以行为主的顺序存储的。
当然,在C和C++中,并没有实际的二维数组。最接近的类比是array of arrays。这就是我们所说的“二维数组”的含义。
在下面的声明中,A就是这样一个数组。它的类型是array of arrays of int

enum : std::size_t { M = 3, N = 2 };
int A[M][N];

字符串
更准确地说,它的类型是“M个元素的数组,其中每个元素都是int类型的N个元素的数组”。这是一个口。
下面是几个类型别名:

enum : std::size_t { M = 3, N = 2 };
using array_of_N_ints 
    = int[N];
using array_of_M_arrays_of_N_ints 
    = array_of_N_ints[M];
using M_by_N_matrix 
    = array_of_M_arrays_of_N_ints;
M_by_N_matrix A;


M_by_N_matrix类型与int[M][N]类型相同。你可以在一个程序中使用std::is_same_v来测试。
使用括号运算符[]引用M_by_N_matrix的元素两次,例如A[m][n]。运算符[]的规则要求从左到右的绑定顺序,因此这等价于(A[m])[n]。意思是“数组A[m]的第n个元素,其中A[m]是数组A的第m个元素”。
现在,我们可以看到下标m与行关联的原因:我们希望C和C中的A[m][n]与数学中的A(m,n)具有相同的含义。第一个下标是行下标。这只是个惯例,仅此而已
好吧,那我们怎么才能达到行大序呢?
答案就在于数组的定义。数组的元素必须储存在连续的位置(可能会加上填补以满足对齐需求)。首先存储元素0,然后是元素1,依此类推。
在上面的示例中,数组A的元素是数组。因为M = 3,所以有三个。它们被连续存储:
A[0] A[1] A[2]
但是我们在上面已经决定了第一个下标是行下标。A[0]是一个包含N个整数的数组,它对应于我们的数学矩阵中的第0行。类似地,A[1]是第1行,A[2]是第2行。根据定义,这是行主顺序。
行0行1行2
所以,你有它:在C和C
中,“二维数组”都是以行为主的顺序存储的。
顺便说一下,下面的程序返回0。

#include <cstddef>
#include <type_traits>
int main()
{
    enum : std::size_t { M = 3, N = 2 };
    using array_of_N_ints 
        = int[N];
    using array_of_M_arrays_of_N_ints 
        = array_of_N_ints[M];
    using M_by_N_matrix 
        = array_of_M_arrays_of_N_ints;
    M_by_N_matrix A;
    return std::is_same_v<M_by_N_matrix, int[M][N]> ? 0 : 1;
}

vdgimpew

vdgimpew2#

每次输出'\n'都是结束一行。因此,内部循环打印一行的元素。要做到这一点,列索引的范围必须在0和我称之为n_cols之间。保持行索引不变,而改变列索引。因此,您称为ROWS的东西实际上是n_cols。
外部循环的每次迭代打印一行。您打印多少行?我将其称为n_rows,但您将其标记为COLS。
所以我会说,不,你对ROWS和COLS的命名是不正确的。
如果将COLS更改为2,但将ROWS保持为3,则输出将包含两行,而不是两列。
你建议你的j索引是一个行索引,但是你第二次打印它,* 这里打印列索引是正常的。* 基本上,你已经转置了名字,足以说服自己矩阵是以列优先的顺序存储的。

相关问题