Как обрабатывать указатель, возвращаемый mallo c, как многомерный массив? - PullRequest
2 голосов
/ 05 марта 2020

Есть ли способ сообщить компилятору, что я выделил память размером N * M и хочу обработать этот указатель как массив N * M? Другими словами, есть ли способ написать что-то вроде этого? поэтому мой вопрос: могу ли я как-то сказать компилятору, что этот указатель, возвращаемый mallo c, является указателем массива, а его размеры равны N * M? Я могу использовать массив для указателей, указатель на массив или указатель на указатель, но во всех случаях мне придется искать 2 адреса. Я хочу иметь непрерывную память в куче и рассматривать ее как многомерный массив. как я написал бы:

int arr[N][M];

Есть ли способ достичь этого?

Ответы [ 4 ]

3 голосов
/ 05 марта 2020

В программе на C ++ вы должны использовать оператор new.

Что касается mallo c, то в C ++ M должно быть константным выражением, если вы хотите выделить двумерный массив.

Вы можете написать, например,

int ( *arr )[M] = ( int ( * )[M] )malloc( N * M * sizeof(int) );

или

int ( *arr )[M] = ( int ( * )[M] )malloc( sizeof( int[N][M] ) );

Если использовать оператор new, то распределение может выглядеть следующим образом:

int ( *arr )[M] = new int[N][M];

Если M не является константой времени компиляции, тогда вы можете использовать стандартный контейнер std::vector, как показано в демонстрационной программе ниже

#include <iostream>
#include <vector>

int main() 
{
    size_t n = 10, m = 10;

    std::vector<std::vector<int>> v( n, { m } );

    return 0;
} 
2 голосов
/ 05 марта 2020

То, что вам нужно, это класс "матрицы", такой как

template <typename T>
class matrix
{
    size_t len;
    size_t width;
    std::vector<T> data;
public:
    matrix(size_t len, size_t width) : len(len), width(width), data(len*width) {}
    T& operator()(size_t row, size_t col) { return data[width * row + col]; }
    const T& operator()(size_t row, size_t col) const { return data[width * row + col]; }
    size_t size() const { return len * width; }
};

int main(int argc, char const *argv[])
{
    matrix<int> m(5, 7);
    m(3, 3) = 42;
    std::cout << m(3, 3);
}

. Он хранит все данные в одном непрерывном буфере и не имеет неопределенного поведения в отличие от всех других примеров, которые используют malloc. Это также RAII, и вам не нужно писать никаких копий или перемещать конструкторы, так как все члены «делают правильные вещи» с компилятором при условии значений по умолчанию. Вы можете сделать этот класс более сложным, предоставить прокси-объект, чтобы вы могли перегружать operator[] и иметь возможность делать m[][], но на его основе это то, что вам нужно.

0 голосов
/ 05 марта 2020

Если вам нужно избегать использования стека, и вам нужен большой отдельный блок данных, чтобы сохранить двумерный массив постоянного размера (это необходимо знать во время компиляции), то это лучший чистый способ сделать это:

std::vector<std::array<int, M>> arr(N);
arr[x][y] = 3;

Теперь, если вам нужно M - это значение, известное во время выполнения, лучше всего использовать boost :: multi_array

Я не вижу причин для использования malloc.

0 голосов
/ 05 марта 2020

Вы можете делать именно то, что хотите, с помощью вспомогательной функции. Это позволяет вам указать размер массива во время выполнения, и он использует mallo c в соответствии с запросом (хотя обычно вы должны использовать new):

#include <iostream>
#include <string>
#include <memory>

template <class T>
T** Get2DMalloc(size_t m, size_t n) {
    T** ret = (T**)malloc(sizeof(T*) * m);
    for (size_t i = 0; i < m; ++i) {
        ret[i] = (T*)malloc(sizeof(T) * n);
    }

    return ret;
}

template <class T>
void Free2D(T** arr, size_t m, size_t n) {
    for (int i = 0; i < m; ++i) {
        free(arr[i]);
    }

    free(arr);
}

int main() {
    int m = 3;
    int n = 3;

    int** a = Get2DMalloc<int>(3, 3);


    for (int x = 0; x < m; ++x) {
        for (int y = 0; y < n; ++y) {
            a[x][y] = x * m + y;
        }
    }

    for (int i = 0; i < m * n; ++i) {
        std::cout << a[i / m][i % n] << std::endl;
    }

    Free2D<int>(a, m, n);

    system("pause");
    return 0;
}
...