Привести (C как) указатель на матрицу C ++

Я хотел бы передать матрицу из одной функции в другую, поэтому я сделал:

#include <cstdlib>
using namespace std;

const int N = 2;

void init_matrix(int (*matrix)[N])
{
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
matrix[i][j] = 1;
}

int main()
{
int *x = (int*)malloc(N*N*sizeof(int));
init_matrix( (int (*)[N]) x );
return 0;
}

Как мне позвонить init_matrix() Полегче? Я представляю это как init_matrix(x, N),

Пожалуйста, обратите внимание, что я как бы избегаю std::vector потому что я буду играть с параллельным программированием (pthreads, OpenMP, MPI) вскоре после этого.
Поэтому я попрошу решение без std подходит для построения матрицы.

2

Решение

Просто не надо.

Многомерный массив — это не то место, где C ++ в лучшем виде. Здесь это все еще приемлемо, потому что N — постоянная времени компиляции, но если бы это была переменная времени выполнения, вы были бы отключены, потому что VLA не поддерживаются в стандарте C ++ (даже если они поддерживаются как расширение реализации некоторыми реализациями, такими как gcc и clang).

Так что если вам действительно нужно иметь дело с настоящими 2D-массивами, просто используйте пользовательский класс, содержащий базовый std::array для фиксированного измерения времени компиляции или вектора для измерений времени выполнения для общего размера и предоставьте 2d методы доступа к нему. Как std::arrays а векторы — это объекты, вы избегаете копирования и перемещения ресурсов (*).

Упрощенная реализация может быть:

class matrix {
std::vector<int> vec;
int  rows;
int cols;

public:
matrix(int i, int j): rows(i), cols(j), vec(i * j) {}

int& at(int i, int j) {
return vec[j + i * cols];
}

const int& at(int i, int j) const {
return vec[j + i * cols];
}
};

Таким образом, базовая структура по-прежнему является истинным 2D-массивом, и у вас есть методы для ее использования с двумя измерениями.

Чего еще не хватает здесь:

  • индексы и размеры, вероятно, должны быть size_t вместо int
  • индексы могут быть проверены, чтобы быть в приемлемом диапазоне в at методы — если вы не проверяете их, функция не должна вызываться at
  • другие конструкторы для построения матрицы поверх существующего двумерного массива (который может быть, например, из унаследованного кода C)

Дополнительное замечание:

Вы говорите, что хотите избежать векторов для возможного многопоточности. Во-первых, я не могу себе представить, почему вектор был бы менее многопоточным, чем динамический массив, выделенный вручную. Во-вторых, если вам действительно нужно ручное размещение, вам нужно будет следовать правилу трех / пяти и реализовать пользовательские конструкторы копирования / перемещения и оператор присваивания в дополнение к пользовательскому деструктору.


(*) У меня есть проект для написания универсального контейнера D, поддерживающего operator [] и итераторы, так что я знаю, что это довольно сложная задача. Я уже отправил предварительную версию обзор кода но это все еще далеко от того, чтобы быть просто полезным.

3

Другие решения

Вы можете использовать псевдоним, чтобы звонок выглядел лучше:

#include <cstdlib>
#include <iostream>
using namespace std;

const int N = 2;

using TypeMatrix =int (*)[N]; //alias

void init_matrix(TypeMatrix matrix) { //simply use the alias
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
matrix[i][j] = 1;
}int main() {
TypeMatrix x = (TypeMatrix)(int*)malloc(N*N*sizeof(int)); //avoid malloc
init_matrix(x);
}

Также обратите внимание, что вы можете перейти на следующий уровень, используя псевдоним шаблона, как показано ниже:

#include <cstdlib>
#include <iostream>
using namespace std;

const int N = 2;

template<typename T , int K>
using TypeMatrix =T (*)[K];

using MatrixInt =TypeMatrix<int,N>;
using MatrixDouble =TypeMatrix<double,N>;template <typename Matrix>
void init_matrix(Matrix matrix) {
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
matrix[i][j] = 1.1;
}template <typename Matrix>
void print(Matrix matrix) {
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
std::cout<<matrix[i][j]<< " ";
}int main() {
MatrixInt x = (MatrixInt) (new int[N*N]);
MatrixDouble y = (MatrixDouble) (new double[N*N]);
init_matrix(x);
init_matrix(y);
print(x);
print(y);
}

Тем не менее, я настоятельно не рекомендую использовать сырые указатели и смешивать C и C ++ (malloc против new) для такой работы. использование std::array или же std::vector вместо.

3

Не обращая внимания на плохую практику использования malloc в C ++, то …

Вы можете заменить указатель массива в параметре функции на массив. Это будет затухать обратно к указателю массива, но это делает интерфейс функции немного понятнее.

Вы не можете конвертировать между int(*)[N] а также (int*) ни в C, ни в C ++. Они не являются совместимыми типами указателей. Даже если они указывают на один и тот же адрес, вы получите неопределенные проблемы поведения, вызванные строгим псевдонимом указателя.

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

#include <cstdlib>
using namespace std;

const int N = 2;

void init_matrix(int matrix[N][N]) {
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
matrix[i][j] = 1;
}

int main() {
int (*x)[N] = (int(*)[N])malloc(N*N*sizeof(int));
init_matrix(*x);
}

Я не рекомендовал бы это в C ++ — этот стиль довольно громоздок без функции VLA в C. В C ++, вероятно, разумнее использовать std::array& вместо.

0

Если по какой-то причине вам нужно динамическое выделение смежных целых чисел, вы можете использовать вектор массивов или умный указатель.

std::vector<int[N]> x(N);
std::unique_ptr<int[][N]> x = std::make_unique<int[][N]>(N);

Используя вашу реализацию init_matrix, вы можете просто передать адрес первого элемента.

init_matrix(&x[0]);

Однако было бы предпочтительнее передать вектор или умный указатель по ссылке.

void init_matrix (std::vector<int[N]> &matrix) {
...
}

void init_matrix (std::unique_ptr<int[][N]> &matrix) {
...
}

...
init_matrix(x);
0

Там нет ничего плохого в использовании std::vector например, для многопоточного программирования Вот. Любое другое хранилище так же опасно.

Помимо всех векторных примеров, показанных в других ответах: Если вы используете матрицы фиксированного размера, вы можете даже рассмотреть возможность использования шаблонов на основе std::array,

#include <iostream>
#include <array>

template <class T, size_t rows, size_t cols>
class Matrix {
public:
Matrix() {}
Matrix(T init) { data.fill(init); }
double& operator() (size_t row, size_t col)
{
if (row < rows && col < cols) return data[cols*row + col];
throw std::out_of_range("Matrix subscript out of bounds.");
}
double operator() (size_t row, size_t col) const
{
return data(row, col);
}
private:
std::array<T, rows*cols> data;
};

int main()
{
Matrix<double, 2, 2> mat(1.0);
mat(1,1) = 2.3;
std::cout << "mat(1,1) = " << mat(1,1) << std::endl;
}

постскриптум в примере реализована проверка неверного размера.

0
По вопросам рекламы [email protected]