views:

96

answers:

6

I'm new to C++, and I have a question that should be easy, but it's making me crazy. I'm trying to set up a 2D array. The array is declared in Solver.h like so:

 protected:
    static const int gridSize = 9;
    int theGrid[gridSize][gridSize]
    int *boxes[gridSize][gridSize];
...

and I'm trying to initialize it in Solver::Solver() like so:

boxes[0] ={ &theGrid[0][0],&theGrid[0][1],&theGrid[0][2],
            &theGrid[1][0],&theGrid[1][1],&theGrid[1][2],
            &theGrid[2][0],&theGrid[2][1],&theGrid[2][2] 
          };
...

But the error I'm getting says "expression must be a modifiable lvalue" and "error: expected an expression". This didn't make sense to me, because I was under the impression that boxes[0] was a modifiable lvalue.

So I wrote a tiny little (non OOP) program that just has the following in it's main():

int test[2][2];
test[0]= {1,2};
cout<<test[0][1];   //outputs "2" as expected.

And now I'm stuck and confused. What is wrong with my assignment routine in the Solver class?

To answer some questions:

I do want a multidimensional array, because eventually I'll be setting up boxes[1] with another array of pointers to another set of data inside the theGrid, a third set in boxes[2] and so on. The idea is to take a 9x9 grid and split it into 3x3 squares (sound familiar? "Solver" should solve sudoku sets simply.) so I can check (and modify) all the values in those 3x3 squares independently. I'm trying to get this working in VS2010. I'm sure there's a good algorithm to define which array members are part of each 3x3 "box" based on that boxes number but I haven't hit it yet, and it seems less wasteful to code it once than to have the program re-create those boxes in loops every time it checks an answer. For the scope of this program the size of theGrid is inalterable, so my conscience will let me get away with a little hard coding.

A: 

You declare boxes as boxes[9][9] so in order to initialize it, you would need to specify boxes[0][0]. Well at least initialize that memory block.

I may be mistaken but it looks like you didn't want to make boxes a multi-dimensional array.

Robb
+1  A: 

See that you have

 int *boxes[gridSize][gridSize];

Just make a test and change it to:

 int boxes[gridSize][gridSize];

You can do this for example (I'm using Visual C++ Console Application to test this):

 int boxes[gridSize][gridSize] = {
 {1, 3, 5},      /* y[0][0], y[0][1], y[0][2] */
 {2, 4, 6},      /* y[1][0], y[1][1], y[1][2] */
 {3, 5, 7}       /* y[2][0], y[2][1], y[2][2] */

};

Visual C++ doesn't accept this:

int test[2][2];
test[0]= { 1, 2 }; // error C2059: syntax error : '{'   
cout << test[0][1];
Leniel Macaferi
That's not what he wants… he wants to convolve by indirection.
Potatoswatter
You can't initialize a member variable (except `static` and of integral type) directly in the declaration.
Potatoswatter
The test code at the end is a GCC extension. (Which apparently breaks with multidimensional arrays.)
Potatoswatter
+1  A: 

I think it wants the lvalue to be:

&boxes[0][0] = ...
Brent Arias
Potatoswatter
@Potatoswatter: Ah...then it would be just boxes[0][0].
Brent Arias
+1  A: 

The problem is that { ... } is not an expression, it is an initializer. Some compilers have an extension to allow expressions to be formed using {}, and C++0x adds several new meanings to the braces, but I'm going to keep this to standard C++.

I think the best general solution is to code a loop. You don't really want to write all that redundancy out, right?

Solver::Solver() {
    for ( int boxnum = 0; boxnum < 9; ++ boxnum ) {
        for ( int cellnum = 0; cellnum < 9; ++ cellnum ) {
            boxes[ boxnum ][ cellnum ]
                = &grid[ boxnum/3*3 + cellnum/3 ][ boxnum%3*3 + cellnum%3 ];
        }
    }
}

Checked code… I believe this is the pattern you're going for.

Potatoswatter
then why his test code pass?
lz_prgmr
@dbger: because that code is using a GCC extension, and the extension is apparently fickle.
Potatoswatter
Unfortunately you're right. I tested my little test code at the end in Code::Blocks, which allowed it, but VC++ 2010 doesn't. So now I need to figure out how to create the nested for loop that handles turning a full 9x9 into 9 3x3's.
NateD
@NateD: Is this loop not what you need? If you mean you instead now want to write to a `int *boxes[9][3][3]`, then just change to `boxes[ boxnum ][ row ][ col ] = `
Potatoswatter
I'm an idiot; your first pattern is exactly right, I just didn't read the code close engough. Thank you again!
NateD
@Nate: no prob :v)
Potatoswatter
@NateD: Code::Blocks is an IDE, not a compiler. It can use VC++ as a compiler too. I assume you meant to say MinGW, no?
mingos
@mingos: yeah, I did mean MinGW.
NateD
A: 

I am not sure about the example code given by you works. Atleast my compiler is not able to digest it (gcc 4.2). The reason for that is {...} are used while initialization and what you are doing is assignment.

u can try this

for (unsigned i=0; i < gridSize; ++i) {
     for (unsigned j=0; j < gridSize; ++j) {
            boxes[i][j] = &theGrid[i][j];
      }
}
aeh
A: 
int main(){
   int buf[2][2];
   cout << typeid(buf[0]).name();
}

This pseudo program prints the equivalent of int [2]. This means that the type of buf[0] is an array of 2 integers.

In C++ an array is a non modifiable Lvalue. It can be initalized but not assigned to.

Your code attempts to assign to boxes[0] and this is ill-formed. The solution of course is as suggested by Potatoswatter and many of the above posts

Chubsdad