【问题标题】:Create a contiguous dynamic matrix创建一个连续的动态矩阵
【发布时间】:2019-09-14 07:26:08
【问题描述】:

数组具有作为连续内存块的良好特性。当使用new 为数组分配内存时,它会返回一个指向连续 内存块的指针。但是,如果我使用new 分配一个矩阵,像这样:

#include <iostream> //std::cin

int main()
{
    int n, m;
    std::cin >> n >> m;
    int** mat = new int*[n];
    for (int i = 0; i < n; i++)
        mat[i] = new int[m];
    //use the matrix in some way
    for (int i = 0; i < n; i++)
        delete[] mat[i];
    delete[] mat;
    return 0;
}

这可行,但mat 不指向大小为n * m * sizeof(int) 的连续块。我怎样才能在 C++ 中做到这一点?我只是遵守最新标准(即 C++17),仅此而已。我想要一个不涉及 STL 容器或外部库的答案。

请不要回答有关 C 的问题,因为在 C99 和 C11 中使用可变长度数组很容易做到这一点:

#include <stdio.h> //scanf
#include <stdlib.h> //malloc, free

int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    //int mat[n][m]; VLA, but I want dynamic
    int (*mat)[m] = malloc(n * sizeof *mat);
    //use the matrix in some way;
    free(mat);
    return 0;
}

【问题讨论】:

  • 首先,不要自己进行动态分配,而是使用std::vector。至于你的问题,你可以创建一个 n * m 元素的向量,并使用算术来访问矩阵中的每个元素。
  • 我没有问要不要自己分配,我只是问怎么做。自己分配内存虽然很危险,但与使用像 std::vector 这样的 STL 容器相比,它可以随时重新分配自己。
  • @DarkAtom 向量不会随时重新分配。如果mn 是固定的,并且您创建了m*n 元素的向量,则没有理由进一步重新分配,除非您提出要求。
  • 如果你想用简单的指针来做这件事,无论是否聪明,出于好奇和学习经验,如果你这么说会有所帮助。因为除非您有其他极其特殊的要求(您需要告诉我们),否则所有“动态数组”问题的解决方案都将是“使用向量”。或者,根据实际问题和用例,“使用库 X”(从名称 mat 猜测可能是 OpenCV 或 Eigen 或类似名称)。
  • @Someprogrammerdude 好吧,我的错,我应该说这是一种学习体验,而不是真正的代码。下次我会这样做。对不起

标签: c++ c++17


【解决方案1】:

这是你正在做的,几乎完全一样,但没有不连续的记忆:

#include <iostream> //std::cin
#include <memory>

int main()
{
    int n, m;
    std::cin >> n >> m;
    auto matrix_data = std::make_unique<int[]>(n * m);
    auto mat = std::make_unique<int[]>(n);
    for(int i = 0; i < n; i++) { mat[i] = matrix_data.get() + i * m; }

    // Use the matrix in some way

    // No need to free anything - we're using smart pointers.

    // No need to return 0 from main - that's the default
}

注意事项:

  1. 这仍然是丑陋的代码...您最好创建一个适当的矩阵类,或者更好的是 - 使用其他人的实现。
  2. 最好遵循@Someprogrammerdude 的建议并使用算术而不是指针数组。

【讨论】:

  • 是的,我当然要为此实现一个类,但我要求实现。
  • 顺便说一下,有些编译器不会从 main 中自动返回 0。
  • @DarkAtom: 1. 不从 main 返回 0 的编译器是非标准投诉。 2. 我不会使用这个实现。但是对于 Someprogrammerdude 的方法,您将 必须operator[] 编写一个类。
  • @DarkAtom 他们must 自 C++11 如果你省略 return 语句(如果他们没有,他们有一个错误)。你用 C++17 标记了你的问题。
【解决方案2】:

我还是不知道你具体要求什么。要将矩阵元素存储在连续位置,只需将内存分配为一维动态数组即可。两个基本选项已经讨论过了,要么使用向量:

std::vector<int> mat(m * n);

或者,如果它的内存开销对您来说很重要,请使用唯一指针:

auto mat = std::make_unique<int[]>(m * n);

然后,要访问具有i 行索引和j 列索引的元素,只需使用:

a_i_j = mat[i * n + j];

假设m 是行数,n 是列数。此公式以所谓的 row-major 顺序存储元素。如果您需要 column-major 顺序,请切换到:

a_i_j = mat[j * m + i];

当然,整个方法最好封装在一个带有一些 getter 运算符 mat(i, j); 的类中。

【讨论】:

  • 这和int* mat = new int[m * n]一样,只是使用了智能指针。
  • @DarkAtom 是的。这就是你想要的,不是吗?
  • @DarkAtom 整个想法非常简单,即将所有矩阵行(或列)在内存中的一维数组中彼此相邻。
  • 如果这么简单我就不会问这个问题了。看看我的 C 示例。我正在分配一个 n * m 数组并将其分配给一个指针,其基础类型的大小实际上是m * sizeof(int)。所以这意味着我可以以 mat[i][j] 的形式访问它,而无需打扰 mat[i * n + m]。
  • @DarkAtom 所以,你唯一的问题是如何使用mat[i][j] 而不是mat(i,j) 访问元素?然后,答案是没有语言提供的选项来为具有连续存储的动态二维数组启用mat[i][j]。但是,您可以将 einpoklum 提供的解决方案与附加数组一起使用。然后,你可以以这个数组存储的价格写mat[i][j]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-13
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 2017-01-10
  • 2015-11-24
  • 1970-01-01
相关资源
最近更新 更多