views:

2009

answers:

4
A: 

Hi. It seems like you need to read up more on pointers in C++ and on pass by reference vs. pass by value.

Your returnPiece method is defined as returning the value of a single cell. Given the index (e.g., [4][4]) you return a copy of the contents of that cell, so you won't be able to change it, or more correctly, changing it would change the copy.

I'm sure someone will give you the correct syntax, but I would really recommend learning this stuff since otherwise you may use the code that you do get incorrectly.

Uri
A: 
More naturally, shouldn't i and j be swapped? (And perhaps use x and y instead for readability.) Also, I think a copy constructor is in order...
strager
i and j are positional, so you can use whatever order you want. Creating a copy constructor would be a good idea.
+3  A: 

When passing your array around, you have to decide whether or not you want to make a copy of the array, or if you just want to return a pointer to the array. For returning arrays, you can't (easily) return a copy - you can only return a pointer (or reference in C++). For example:

// Piece::returnPiece is a function taking no arguments and returning a pointer to a
// 4x4 array of integers
int (*Piece::returnPiece(void))[4][4]
{
    // return pointer to the array
    return &pieceArray;
}

To use it, call it like so:

int (*arrayPtr)[4][4] = myPiece->returnPiece();
int cell = (*arrayPtr)[i][j];  // cell now stores the contents of the (i,j)th element

Note the similarity between the type declaration and using it - the parentheses, dereferencing operator *, and brackets are in the same places.

Your declaration for Grid::InsertArray is correct - it takes one argument, which is a 4x4 array of integers. This is call-by-value: whenever you call it, you make a copy of your 4x4 array, so any modification you make are not reflected in the array passed in. If you instead wanted to use call-by-reference, you could pass a pointer to an array instead:

// InsertArray takes one argument which is a pointer to a 4x4 array of integers
void Grid::InsertArray(int (*arr)[4][4])
{
     for(int i = 0; i < x_ROWS; i++)
     {
         for(int j = 0; j < y_COLUMNS ; j++)
             squares[i][j] = (*arr)[i][j];
     }
}

These type declarations with pointers to multidimensional arrays can get really confusing fast. I recommend making a typedef for it like so:

// Declare IntArray4x4Ptr to be a pointer to a 4x4 array of ints
typedef int (*IntArray4x4Ptr)[4][4];

Then you can declare your functions much more readable:

IntArray4x4Ptr Piece::returnPiece(void) { ... }
void Grid::InsertArray(IntArray4x4Ptr arr) { ... }

You can also use the cdecl program to help decipher complicated C/C++ types.

Adam Rosenfield
Wow. I had no idea you could return a 2d array. K }
Yes. if you want the array to decay, you can return "pieceArray" instead of its address. a pointer to its first element will be returned, which is of type int(*)[4] . but downside is you lose the size of the outer dimension. i think adam's approach is better...
Johannes Schaub - litb
...unless the outer dimension can have an arbitrary size. but it seems to be sized to 4 always.an upside of returning the decayed array is that you have natural iindex syntax of the returned thingy: foo()[4][4] and not (*foo())[4][4] anymore.taking both in consideration,i would still prefer adam's.
Johannes Schaub - litb
No, his original Grid::InsertArray(int arr[4][4]) is Call-by-Reference. There is only one array in memory, it is pieceArray, and it is shared. Values can be changed out from under you. For Call-by-Value (copying)... Best cheat with a struct. (I'll post separately.)
Mr.Ree
A: 

Trouble with Adam Rosenfield's arrayPtr in that Piece::pieceArray can change out from under you. (Copy-by-reference vs Copy-by-value.)

Copy-by-value is inefficient. But if you really want to do it, just cheat:

struct FOO { int  piece [4][4]; };

FOO Piece::returnPiece()
{
  FOO f;
  memcpy( f.piece, pieceArray, sizeof(pieceArray) );
  return f;
}

void Grid::InsertArray( const FOO & theFoo )
{
  // use theFoo.piece[i][j]
}

Of course, a better, more Object-Oriented solution, would be to have returnPiece() create and return a Piece or Array object. (As Juan suggested...)

Mr.Ree
a general approach would be template<typename T> struct wrap { T t; wrap(T const } }; template<typename T> wrap<T> make_wrap(T const } then return make_wrap(pieceArray) and accept wrap<int[4][4]> in the InsertArray method.
Johannes Schaub - litb
litb: You raise a good point. But why generalize a kludge to overcome C/C++'s inability to copy arrays? make_wrap() is unnecessary. Be wary of generalizing the use of memcpy() over to types that include pointers. Given OP's skill with C++, is increasing coding complexity through templates wise?
Mr.Ree