(Multidimensional array of structs Dinamically allocated)

I was given this piece of code for study. I understand much of it, namely the typedef's and such, but I'm really having awefull time trying to understad the placement of some parentheses.... Here's the code:

#include <string>
using namespace std;

struct MapItem
{
int x, y;
string line;
MapItem (int _x, int _y): x(_x), y(_y), line("") {}
};
const int COLUMNS = 10;
const int ROWS = 5;

typedef MapItem* col[COLUMNS];
typedef col* gridtype[ROWS];

int main ()
{
gridtype grid;

for (int i = 0; i < ROWS; i++)
{
grid[i] = new col[COLUMNS];
for (int j = 0; j < COLUMNS; j++)
{
(*grid[i])[j] = new MapItem(i,j);
}
}

// Use of the grid

(*grid[0][0])-> line = "Upper left corner";
// etc...

// Free allocated memory

for (int i = 0; i < ROWS; i++)
delete [] grid[i];
delete grid;

return 0;
}

these are the parentheses, I'm talking about, I really dont get such construction:
*** (*grid[i])[j] = new MapItem(i,j);
why not simply grid[i][j] = new MapItem(i,j); ????? for example... and then this other:
*** (*grid[0][0])-> line = "Upper left corner"; I understand what it's trying to do assigning the line in the struct but the thing is placement of the parentheses.

Someone, any help, any explanation???? Please... Sorry for the format of my post, this is my very first.



Obligatory link: http://cplusplus.com/forum/articles/17108/

Anyway, this code is insanely obfuscated. It doesn't need to be this complicated. Whoever wrote this is doing very strange things with arrays of pointers. To be honest I don't fully understand it (too lazy to disect it) -- and I'm not even sure it works, to be honest. It almost looks like there's a ton of uninitialized pointers being dereferenced -- but again I didn't really look at it very thorough.

A much, much simpler approach would be:

1
2
3
4
5
6
7
8
typedef MapItem* gridtype[ROWS][COLUMNS];

for(...)
{
  grid[y][x] = new MapItem(y,x);
}

grid[0][0]->line = "Upper Left Corner";


or if you don't need the ctor:

1
2
3
4
typedef MapItem gridtype[ROWS][COLUMNS];

gridtype grid;
grid[0][0].line = "Upper Left Corner";



But again... obligatory link: http://cplusplus.com/forum/articles/17108/

Screw MD arrays. They're more trouble than they're worth most of the time.

---------------
EDIT:

Yeah this code you posted is completely broken:

1) It has huge memory leaks. Individual elements are allocated, but are never freed.
2) Things that were never allocated are deleted (like 'grid')
3) Half of the pointers he's dereferencing with this line (*grid[0][0])-> line are bad pointers. This is screaming "heap corruption"

I get the impression whoever wrote it didn't know wtf they were doing and had all sorts of compiler errors, so they just stuck * operators everywhere until the errors went away.

There's no way this code will run though. Even if it doesn't crash the program, it'll screw things up really badly.

So yeah -- there's nothing here to study. The only thing to learn from this code is how not to program.
Last edited on
I know the code is tricky. After usage I understand memory had to freed but that's not the real problem, also it compiles pretty well... I did myself much simpler versions. This code was writte By David Bolton
David Bolton, B.SC is a software developer who develops trading applications for a global investment bank in London, England.

He keeps an About.com tutorial on C/C++/C#.
you can find it at: http://cplus.about.com/od/learning1/ss/pointers_10.htm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <string>
using namespace std;

const maxrows=5;
const maxcolumns=10;

struct mapitem  
{
  int row,column;
  string line;
  mapitem(int _row,int _column) {row=_row,column=_column,line='\0';}
};

typedef mapitem * col[maxcolumns];
typedef col * gridtype[maxrows];

int main(int argc, char* argv[])
{  
  gridtype grid;
  int rowindex,colindex;

  for (rowindex=0;rowindex < maxrows; rowindex++) {
  // Allocate memory for columns in each row  
    grid[rowindex] = new col[maxcolumns];
    for (colindex=0;colindex < maxcolumns;colindex++)
    {
    // Hook up the grid to a new item
    *(grid[rowindex])[colindex] = new mapitem(rowindex,colindex) ;
    }
  }

  // Set the string for the top left corner etc
  (*grid[0][0])->line="Top Left Corner";
  (*grid[maxrows-1][0])->line="Bottom Left Corner";
  (*grid[0][maxcolumns-1])->line="Top Right Corner";
  (*grid[maxrows-1][maxcolumns-1])->line="Bottom Right Corner";
  return 0;
} 


I did myself simpler versions of the code like this one:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <string>  // not iostream
using namespace std;

struct MapItem
{
    int x, y;
    string line;
    MapItem (int _x, int _y): x(_x), y(_y), line("") {}
};

const int COLUMNS = 10;
const int ROWS = 5;

typedef MapItem* col[COLUMNS];
typedef col gridtype[ROWS]; // not col*

int main ()
{
    gridtype grid;

    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLUMNS; j++)
        {
            grid[i][j] = new MapItem(i,j);
        }
    }

    // Use of the grid

    grid[0][0]-> line = "Upper left corner";
    // etc...

    // Free allocated memory

    for (int i = 0; i < ROWS; i++)
    {
        for (int j=0; j<COLUMNS; j++)
        {
            delete  grid[i][j];
        }
    }

    return 0;
}


But it would be huge if someone could explain the original code!!!!

Well from what I'm seeing, I wouldn't recommend learning C++ from this guy's tutorials. This code is atrocious (even if work out all the allocation errors and heap corruption that's going on)

But whatever. Here's your explanation:

1
2
3
4
5
const int COLUMNS = 10;
const int ROWS = 5;

typedef MapItem* col[COLUMNS];
typedef col* gridtype[ROWS];


'col' is an array of pointers. Each pointer points to a MapItem.
'gridtype' is an array of pointers. Each pointer points to a col

Therefore a gridtype is an array of pointers that points to an array of pointers which point to MapItem. Yes it's confusing.

To declare 'grid' without the gridtype typedefs... you could do this:

 
MapItem *(*grid[ROWS])[COLUMNS];


The parenthesis here are necesary because you have an array of pointers to arrays. Without the parenthesis you have this:

 
MapItem** grid[ROWS][COLUMNS];


Which is not an array of pointers to arrays of pointers to MapItems.... instead it's a singular 2D array of pointers to pointers (rather than two 1D arrays)


Moving on:

 
(*grid[i])[j] = new MapItem(i,j);


Let's break this down one operator at a time:

Remember that 'grid' is first and foremost an array (an array of pointers)... therefore 'grid[i]' gets you one pointer from the array (ie: the pointer for the current row).

Next, '*grid[i]' dereferences that pointer, which means '*grid[i]' is of type 'col' So you could do this:

 
col& test = *grid[i];


(note that I have to use a reference col& here because col is an array and therefore you can't assign it like it was a singular variable)

Moving on... '*grid[i]' is a 'col'. And remember that 'col' is first and foremost an array (array of pointers to MapItems)

Therefore: (*grid[i])[j] gets one pointer from the array of pointers. That pointer points to a single MapItem... so you cold do this:

 
MapItem* test = (*grid[i])[j];


The parenthesis are key here because the braket operator [] has a higher priority than the dereference operator *.

If you take out the parenthesis you have a compeltely different expression.

It works out fine for [0][0] because [0] and * effectively mean the exact same thing... but if you want to do, say, [1][2], you're in for a lot of trouble. For example:

1
2
(*grid[1])[2]->line = "This is ok";
(*grid[1][2])->line = "This is BAD.  Bad pointers, heap corruption, etc";


The reason these are so different is because the braket operator [] has a higher priority than the dereference operator *.

In the first 'ok' version, the []s index each of the arrays, as outlined above. Therefore *grid[1] is our col (ie: the same as grid[1][0])

In the BAD version, the [2] dereferences a pointer and the * indexes an array! Therefore grid[1][2] is our col (not grid[1][0] as above!)



Anyway that's about as into it as I'm going to be able to get. Again, I really don't recommend this crap. I'd stop reading this guy's tutorials, too. Like I say.. if there's anything you can learn from this, it's "Things to never do in programming"
Last edited on
Disch wrote:
 
Like I say.. if there's anything you can learn from this, it's "Things to never do in programming"

Your right Disch!
I have to say really thank you very much!

Before no one could tell me none about the code (besides the obvious: the code is grotesque!). As to that way of programming I don't plan to follow that.

It was an assignment: to break the code and explain it, which I couldnt of cuz... But now I see, the explanation above was helpfull indeed ("Disch").
Topic archived. No new replies allowed.