Передача указателя на 2D массив c ++ - PullRequest
6 голосов
/ 22 февраля 2010

У меня эта проблема довольно долгое время - у меня есть двумерный массив фиксированного размера в качестве члена класса.

class myClass
{ 
public:
        void getpointeM(...??????...);
        double * retpointM();

private:

   double M[3][3];

};

int main()
{
     myClass moo;
     double *A[3][3];

     moo.getpointM( A );  ???
     A = moo.retpointM(); ???

} 

Я бы хотел передать указатель на матрицу M снаружи. Это, наверное, очень просто, но я просто не могу найти правильную комбинацию & и * и т. Д.

Спасибо за помощь.

Ответы [ 7 ]

9 голосов
/ 22 февраля 2010

double *A[3][3]; - это двумерный массив double * с. Вы хотите double (*A)[3][3]; .

Затем обратите внимание, что A и *A и **A имеют одинаковый адрес, только разные типы.

Создание typedef может упростить вещи:

typedef double d3x3[3][3];

Это C ++, вы должны передавать переменную по ссылке, а не по указателю:

void getpointeM( d3x3 &matrix );

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

3 голосов
/ 22 февраля 2010

Ваше намерение неясно. Что должен делать getpointeM? Вернуть указатель на внутреннюю матрицу (через параметр) или вернуть копию матрицы?

Чтобы вернуть указатель, вы можете сделать это

// Pointer-based version
...
void getpointeM(double (**p)[3][3]) { *p = &M; }
...
int main() {
  double (*A)[3][3];
  moo.getpointM(&A);
}

// Reference-based version
...
void getpointeM(double (*&p)[3][3]) { p = &M; }
...
int main() {
  double (*A)[3][3];
  moo.getpointM(A);
}

Для retpointM объявление будет выглядеть следующим образом

...
double (*retpointM())[3][3] { return &M; }
...
int main() {
  double (*A)[3][3];
  A = moo.retpointM();
}

Хотя это довольно сложно читать. Вы можете сделать это более понятным, если вы используете typedef-name для своего типа массива

typedef double M3x3[3][3];

В этом случае приведенные выше примеры преобразуются в

// Pointer-based version
...
void getpointeM(M3x3 **p) { *p = &M; }
...
int main() {
  M3x3 *A;
  moo.getpointM(&A);
}

// Reference-based version
...
void getpointeM(M3x3 *&p) { p = &M; }
...
int main() {
  double (*A)[3][3];
  moo.getpointM(A);
}

// retpointM
...
M3x3 *retpointM() { return &M; }
...
int main() {
  M3x3 *A;
  A = moo.retpointM();
}
0 голосов
/ 22 февраля 2010

Сделать M публичным, а не приватным. Поскольку вы хотите разрешить доступ к M через указатель, M все равно не инкапсулируется.

struct myClass { 
  myClass() {
    std::fill_n(&M[0][0], sizeof M / sizeof M[0][0], 0.0);
  }
  double M[3][3];
};

int main() {
  myClass moo;
  double (*A)[3] = moo.M;
  double (&R)[3][3] = moo.M;

  for (int r = 0; r != 3; ++r) {
    for (int c = 0; c != 3; ++c) {
      cout << A[r][c] << R[r][c] << ' ';
      // notice A[r][c] and R[r][c] are the exact same object
      // I'm using both to show you can use A and R identically
    }
  }

  return 0;
}

В общем, я бы предпочел R вместо A , поскольку все длины фиксированы ( A потенциально может указывать на double[10][3], если это было требованием), и ссылка, как правило, приведет к более четкому коду.

0 голосов
/ 22 февраля 2010

Возможно, вы захотите взять код в своей основной функции, которая работает с двумерным массивом значений типа double, и перенести его в myClass в качестве функции-члена. Вам не только не придется сталкиваться с трудностью передачи указателя для этого 2D-массива, но и к внешнему к вашему классу коду больше не нужно будет знать детали того, как ваш класс реализует A, поскольку теперь они будут вызывать функцию в myClass и позволить этому делать работу. Если, скажем, вы позже решили разрешить переменные измерения A и решили заменить массив на vector из vector s, вам не нужно переписывать какой-либо вызывающий код, чтобы он работал.

0 голосов
/ 22 февраля 2010
class myClass
{ 
public:
        void getpointeM(double *A[3][3])
        {
           //Initialize array here
        }

private:

   double M[3][3];

};

int main()
{
     myClass moo;
     double *A[3][3];

     moo.getpointM( A );
} 
0 голосов
/ 22 февраля 2010

В вашей main() функции:

double *A[3][3];

создает массив 3x3 double* (или указатели на двойники). Другими словами, 9 x 32-разрядных смежных слов памяти для хранения 9 указателей памяти.

Нет необходимости делать копию этого массива в main(), если только класс не будет уничтожен, и вы все еще хотите получить доступ к этой информации. Вместо этого вы можете просто вернуть указатель на начало этого массива-члена.

Если вы хотите вернуть только указатель на внутренний член класса, вам действительно нужно только одно значение указателя в main():

double *A;

Но если вы передаете этот указатель в функцию и вам нужна функция для обновления ее значения, вам нужен двойной указатель (который позволит функции возвращать значение real указателя обратно в звонящий:

double **A;

А внутри getpointM() вы можете просто указать A на внутренний элемент (M):

getpointeM(double** A)
{
    // Updated types to make the assignment compatible
    // This code will make the return argument (A) point to the
    // memory location (&) of the start of the 2-dimensional array
    // (M[0][0]).
    *A = &(M[0][0]);
}
0 голосов
/ 22 февраля 2010

Короткий ответ: вы можете получить double * в начале массива:

public:
   double * getMatrix() { return &M[0][0]; }

Вне класса, однако, вы не можете просто тривиально превратить double * в другой 2D-массив напрямую, по крайней мере, не в том паттерне, который я видел ранее.

Вы можете создать 2D-массив в main (double A [3] [3]) и передать , что , в метод getPoint, который может скопировать значения в переданный массив. Это даст вам копию, которая может быть тем, что вы хотите (вместо оригинальных, изменяемых данных). Недостатком является то, что вы, конечно, должны его скопировать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...