Problem passing Dynamically Allocated 2D array to function.

Hello, and thanks in advance.

I have a program that loads an array from an external file, like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    color *room[30];

    //Read file.
    ifstream fin("./data/map/test.map", ios::binary);

    //Get array width.
    fin.read((char *)(&rwidth), sizeof(rwidth));
    room = new color*[30]; //It's height is always 30.

    //Allocate space accordingly.
    for (int i = 0; i < 30; i++)
    {
        room[i] = new color[30];
    }

    fin.read((char *)(&room), sizeof(room));
    fin.close();


Now, if I perform the above function with out allocation, and instead just read it into:

color room[60][30];

The following function works just fine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
oid class_phys::collision( color room[][30] )
{
    //Get the 4 points to check:
    int top     = int(floor( (fy+yoff)/TILEY ));
    int mid     = int(floor( (fy+yoff+height/2)/TILEY ));
    int bot     = int(floor( (fy+yoff+height-1)/TILEY ));

    int left    = int(floor( (fx+xoff+xspeed)/TILEX ));
    int right   = int(floor( (fx+xoff+xspeed+width)/TILEX ));

    //debug(width, 0);
    //debug(height, 20);

    ///Check only the blocks nearby. Only work if the block is isolated.
    for (int i = left; i < right; i++ )
    {
        if (i >= 0 && i < 10)
        {
           if ( (room[left][top].sol && (room[left][top-1].sol || room[left][top+1].sol) ) ||
                (room[left][mid].sol && (room[left][mid-1].sol || room[left][mid+1].sol) ) ||
                (room[left][bot].sol && (room[left][bot-1].sol || room[left][bot+1].sol) ) )
           {
............................................etc.
}


And I call it like this (it's an inherited class):

collision(room);

But, as soon as I dynamically allocate the array, the function refuses to compile, stating:

error: no matching function for call to 'class_bot::step(color* [30])'

This has had me confused for quite a while, and any help is appreciated. Thankyou.
closed account (D80DSL3A)
Ah yes, that problem again. I'll use integers for this example.

When you declare a 2d array statically like this: int arr[4][5]; a continuous block of memory is set aside for it. The 20 memory spaces are contiguous. The quantity arr is actually a pointer to an array of 5 integers. When you increase the value of the 1st index by one, say from arr[2][1] to arr[3][1], an address 5 integer spaces ahead is read. When a regular int* is incremented by one the pointer is advanced only one integer space ahead. This is why it is necessary to give the value of the 2nd array dimension when passing a 2d array. The 5 in arr[][5] tells the compiler to look ahead 5 spaces when the 1st index is increased.

The dynamically allocated 2d array formed by allocating an array of pointers:
int** ppInt = new int*[4];
followed by separately allocating an array of integers to each pointer:
1
2
for(int i=0; i<4; ++i)
    ppInt[i] = new int[5];

results in space for 5 integers being allocated in 4 different places. Each of the 4 pointers allocated to ppInt point to these different areas of memory. In this case the 1st array index in ppInt[i][j] tells which pointer to refer to.

These are not equivalent array structures. I hope my explanation made sense.

How to fix it? If your functions are going to take an argument color room[][30] then you can still allocate dynamically, but you must use a pointer to 30 colors.

1
2
color (*room)[30];// a SINGLE pointer to an array of 30 colors
room = new color[rows][30];// allocate the 2d array in one shot. 

A continuous block of memory will be allocated for rows x 30 colors, just as if you had declared
1
2
const int rows = 30;
color room[rows][30];

You can now pass room to a function that expects color room [][30].

Don't forget to cleanup! When finished with this array call: delete [] room;
Thanks for the help, however... It compiles, but instantly closes/crashes.
The array is allocated before anything calls the function. Is there a way to check if a variable has been allocated or not in the function itself? (I assume that would fix the problem I'm having).

EDIT: It's not only that. I had a simple 'for' statement that would read through the array, check a certain boolean in each... element I believe it's called? Anyway, it would search each element, check a bool, and draw something if it was true. In essence, none of the data in the array can be accessed without the program crashing. Even when I dynamically allocate 'rows' to be 60, the value I know to work as when it works when not dynamically allocated.
Last edited on
closed account (D80DSL3A)
Sorry, I don't know what is causing the problems.
Could you post a bit more code ?
Oh sorry. Ok, basically, when I do this, it doesn't crash:

1
2
3
4
5
6
7
8
9
10
    color room[60][30];
    ifstream fin("./data/map/test.map", ios::binary);

    fin.read((char *)(&rwidth), sizeof(rwidth));
    //room = new color[rwidth][30];

    fin.read((char *)(&room), sizeof(room));
    fin.close();

    bot.step(room);


But when I do this, it opens for a second, then crashes:

1
2
3
4
5
6
7
8
9
10
    color (*room)[30];
    ifstream fin("./data/map/test.map", ios::binary);

    fin.read((char *)(&rwidth), sizeof(rwidth));
    room = new color[60][30]; //Note how I made it 60, the value that worked before.

    fin.read((char *)(&room), sizeof(room));
    fin.close();

    bot.step(room);


Even though the arrays are the same size, if I allocate that size, the program won't compile.

The allocation of the array is in a class function, class_map::load()

That same class also has a function which contains:

1
2
3
4
5
6
7
8
9
10
    for(int i = 0; i < rwidth; i++)
    {
        for(int j = 0; j < 30; j++)
        {
            if (room[i][j].sol)
            {
                //Draw something.
            }
        }
    }


Basically, all it does is check a boolean value in each struct, and draws something if it's there.

If I comment-out every instance where the memory allocated array 'room' is used, except for this instance, the program STILL crashes. If I comment out everything, including this, the program runs. (Also, just commenting out this instance and leaving all other users of the value alone has the same result).

I hope that helps. Thanks.


EDIT: I just did this to test my problem, and it's still present:

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
46
47
    if (key_s && key_ctrl)
    {
        ofstream fout("map.map", ios::binary); //Open file for writing.

        getwid(); //This gets the width of array 'room'.
        fout.write((char *)(&width), sizeof(width)); //Write the width that the above function just read.

        op = new color[width][MAPY]; //allocate another array of the 'color' struct.

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < MAPY; j++)
            {
                op[i][j] = room[i][j]; //Copy the values from 'room' into 'op'
            }
        }

        fout.write((char *)(&op),  sizeof(op)); //write it to the file.

        fout.close(); //close.


        delete []op; //delete.
    }

    if (key_l && key_ctrl)
    {
        ifstream fin("map.map", ios::binary); //Open file for reading.

        fin.read((char *)(&width), sizeof(width)); //Read the width.

        op = new color[width][MAPY]; //Allocate an array with that width.

        fin.read((char *)(&op),  sizeof(op)); //Read the array.

        fin.close(); //Close.

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < MAPY; j++)
            {
                room[i][j] = op[i][j]; //Assign back to 'room';
            }
        }

        delete []op; //And delete.
    }


I can press 'Ctrl-S' to save it just fine (doesn't crash). But as soon as I press 'Ctrl-L' to load, the program crashes.

This is quite confusing.
Last edited on
closed account (D80DSL3A)
One issue I see. This color (*room)[30] is just a pointer. The sizeof this pointer is just 4 bytes. sizeof(room) will not give the size of the array allocated to it. sizeof(room) = 4.
For a static array color room[60][30]; the sizeof() function WILL give the array size = 60x30xsizeof(color).

So, the file read may not be working as you expect.
Instead of this: fin.read((char *)(&room), sizeof(room));
Try this: fin.read((char *)(&room), rwidth*30*sizeof(color));

I hope that's the problem.
Um... well I did what you said. And now it only sometimes crashes. When it doesn't crash, (the program is meant to draw things according to the array), it displays random colours all over the screen, which pretty much means it's not reading the correct data.

I guess I should provide a more in-depth description of my program. This current program starts out with an array:

color room[60][30];

And by clicking on locations of the screen, you change the colour of the element corresponding to it (like a primitive paint program).

When it saves, it checks what was the rightmost click you made. Aka, what was the 'width' of the array it needs to save (that way, useless data isn't saved). That is what I try to allocate to the array. I know for a fact that the 'width' value is written to the file correctly, but it still won't read it properly.
Topic archived. No new replies allowed.