views:

536

answers:

7

I'm having this problem for quite a long time - I have fixed sized 2D array as a class member.

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(); ???

} 

I'd like to pass pointer to M matrix outside. It's probably very simple, but I just can't find the proper combination of & and * etc.

Thanks for help.

A: 

The short answer is that you can get a double * to the start of the array:

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

Outside the class, though, you can't really trivially turn the double * into another 2D array directly, at least not in a pattern that I've seen used.

You could create a 2D array in main, though (double A[3][3]) and pass that in to a getPoint method, which could copy the values into the passed-in array. That would give you a copy, which might be what you want (instead of the original, modifiable, data). Downside is that you have to copy it, of course.

quixoto
No! don't give up!
Potatoswatter
+8  A: 

double *A[3][3]; is a 2-dimensional array of double *s. You want double (*A)[3][3]; .

Then, note that A and *A and **A all have the same address, just different types.

Making a typedef can simplify things:

typedef double d3x3[3][3];

This being C++, you should pass the variable by reference, not pointer:

void getpointeM( d3x3 &matrix );

Now you don't need to use parens in type names, and the compiler makes sure you're passing an array of the correct size.

Potatoswatter
You shouldn't use references "because this is C++" or "just because you can". Use them when they are more clear than available alternatives.
Roger Pate
@Roger: yes, well, it is appropriate here, anyway :v)
Potatoswatter
A: 

In your main() function:

double *A[3][3];

creates a 3x3 array of double* (or pointers to doubles). In other words, 9 x 32-bit contiguous words of memory to store 9 memory pointers.

There's no need to make a copy of this array in main() unless the class is going to be destroyed, and you still want to access this information. Instead, you can simply return a pointer to the start of this member array.

If you only want to return a pointer to an internal class member, you only really need a single pointer value in main():

double *A;

But, if you're passing this pointer to a function and you need the function to update its value, you need a double pointer (which will allow the function to return the real pointer value back to the caller:

double **A;

And inside getpointM() you can simply point A to the internal member (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]);
}
LeopardSkinPillBoxHat
well it seems like that is the thing I really wanted to do :) But still with error: cannot convert ‘double [3][3]’ to ‘double*’ in assignment
Moomin
sorry my mistake - forgot to add ** in both lines
Moomin
This just doesn't make any sense to me. The member is declared as `double M[3][3]`. The assigment `*A = M` simply won't compile, because the left-hand side is `double *` and the right-hand side is `double (*)[3]`. These types are not compatible.
AndreyT
@AndreyT - Sorry, my mistake. I have updated the code to make the types compatible.
LeopardSkinPillBoxHat
Roger Pate
@Roger - Sure, that's valid. I was trying to keep my answer in line with what the OP was asking, but what you have suggested is definitely clearer.
LeopardSkinPillBoxHat
A: 
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 );
} 
Dave18
+3  A: 

Your intent is not clear. What is getpointeM supposed to do? Return a pointer to the internal matrix (through the parameter), or return a copy of the matrix?

To return a pointer, you can do this

// 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);
}

For retpointM the declaration would look as follows

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

This is rather difficult to read though. You can make it look a lot clearer if you use a typedef-name for your array type

typedef double M3x3[3][3];

In that case the above examples will transform into

// 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();
}
AndreyT
A: 

You may want to take the code in your main function which works with the 2D array of doubles, and move that into myClass as a member function. Not only would you not have to deal with the difficulty of passing a pointer for that 2D array, but code external to your class would no longer need to know the details of how your class implements A, since they would now be calling a function in myClass and letting that do the work. If, say, you later decided to allow variable dimensions of A and chose to replace the array with a vector of vectors, you wouldn't need to rewrite any calling code in order for it to work.

Josh Townzen
A: 

Make M public instead of private. Since you want to allow access to M through a pointer, M is not encapsulated anyway.

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;
}

I would, in general, prefer R over A because the all of the lengths are fixed (A could potentially point to a double[10][3] if that was a requirement) and the reference will usually lead to clearer code.

Roger Pate