Allocating Multidimensional Arrays

Hello all!

I've been reading 'Jumping into C++' by Alex Allain. Great book, easy to understand, and the practice problems really help reinforce what I've learned in each chapter. Chapter 14 has put a bit of a roadblock in the learning process for me. For whatever reason I can't wrap my head around dynamically allocated multidimensional arrays. I get that it's a pointer that points to an array, which points to another array. So really you've got several linear arrays at different points in memory that act like a normal multidimensional array. However, normal multidimensional arrays can't be dynamically allocated. Using pointers however, we can resize this multidimensional array. Well, after getting to problem #2 I've realized I don't understand the application and syntax as well as I had initially thought. The problem is as follows:

Write a function that takes three arguments, a length, width and height, dynamically allocates a three dimensional array with those values and fills the three dimensional array with multiplication tables. Make sure to free the array when you are done.

Here is my proposed solution:

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
#include <string>

using namespace std;

void getargs(int& height, int& width, int& length);
int **initializearray(int& height, int& width, int& length, int** carray);
void printarray(int& height, int& width, int& length, int** carray);
bool goagain();
void freearray(int** carray);

//Main function declares variables, then cycles
//through functions to get arguments from user,
//then set the carray pointer to the value
//the user specifies. Then print array.
//Next, use a while loops to determine if the
//user would like to resize the array.
//If so then repeat, otherwise free memory.
int main()
{
int height, width, length;
int **carray=new int*[1];
do
{
getargs(height, width, length);
carray = initializearray(height, width, length, carray);
printarray(height, width, length, carray);
}
while(goagain());
freearray(carray);
}

//Function takes in arguments declared in main and
//sets them to a user defined value.
void getargs(int& height, int& width, int& length)
{
    cout<<"Enter a height for your array:"<<endl;
    cin>>height;
    cout<<"Enter a width for your array:"<<endl;
    cin>>width;
    cout<<"Enter a length for your array:"<<endl;
    cin>>length;
}

//Get values defined by user. Pass array into function.
//Allocate a 3 dimensional array and give it values.
//Delete the old array and pass the pointer to the new memory.
int **initializearray(int& height, int& width, int& length, int* carray)
{
    int **p_temparray = new int*[length];
    for(int i=0;i<length;i++)
    {
        p_temparray[i] = new int*[width];
        for(int j=0;j<width;j++)
        {
            p_temparray[i][j]=new int[height];
            for(int x=0;x<height;x++)
            {
                p_temparray[i][j][x]=i*j*x;
            }
        }

    }
    delete [] carray;
    return p_temparray;
}

//Get height width and length then print the values for each
//array coordinate.
void printarray(int& height, int& width, int& length, int* carray)
{
    for(int i=0;i<length;i++)
    {
        for(int j=0;j<width;j++)
        {
            for(int x=0;x<height;x++)
            {
                cout<<"carray["<<i<<"]["<<j<<"]["<<x<<"]="<<carray[i][j][x]<<endl;
            }
        }
    }
}

//Check to see if user wants to resize array.
//If so, then loop functions again.
bool goagain()
{
    string arg;
    cout<<"Would you like to resize the array?\n";
    cin>>arg;
    if(arg=="y")
    {
        return true;
    }
    else
    {
        return false;
    }
}

//Cycle through the array and delete allocated memory.
void freearray(int** carray)
{
    for(int i=0;i<length;i++)
    {
        delete [] carray[i];
        for(int j=0;j<width;j++)
        {
            delete [] carray[i][j];
        }

    }
    delete [] carray;
    return p_temparray;
}


Upon compilations errors are abound. Specifically:

Line|53|error: cannot convert 'int**' to 'int*' in assignment|
Line|56|error: invalid conversion from 'int*' to 'int' [-fpermissive]|

There are the first couple of errors, I can add more but I was afraid I might overdo it with the length of this post!

Is there someone out there who can lift the fog in my mind in regard to dynamically allocated multidimensional arrays?
Last edited on
This is something that C and C++'s terse syntax has going against it.

The type of things matter.

For the purposes of our discussion, I'm going to mistreat arrays a little here.

An array name is a pointer to the element type. For example:

    int xs[ 12 ];    create an array of twelve integers.

You can think of xs as a pointer to the first int in the array. Its (degenerate) type is...

    int*

You can dynamically allocate the array as well:

    int* xs = new int[ 12 ];    create an array of twelve integers.


Now for the untangling. The compiler knows the length of an "array" -- the statically-allocated thing we first created. We can ask it for that information.

There is no way for the compiler (or us) to know the length of a dynamic array -- that is, we don't know how many elements a pointer points to. We have to track that information ourselves.



Alright, so now we have an array, created either statically (first method) or dynamically (second method). The type of thing the array contains (the type of the elements) is int.

But now we want to have an array of arrays -- a 2D array. That is, we want an

    array[ 4 ] of (array[ 3 ] of integers)


C and C++ syntax doesn't help us with that:

    int** my_2d_array;

Since the entire array is dynamic, we need a pointer to it. Hence one of those stars (*).

Since the outer dimension is an array of pointers, we need the second star (*).

And since the elements of the inner dimension is integers, we need the int.


To help track it easier, let's use some typedefs.

1
2
3
4
5
6
7
8
9
10
typedef int                  element_type;
typedef element_type*         inner_dimension_type;
typedef inner_dimension_type* outer_dimension_type;

// remember, our outer dimension is an array of inner dimension
outer_dimension_type my_2d_array = new inner_dimension_type[ 4 ];

// and each inner dimension is an array of elements
for (int n = 0; n < 4; n++)
  my_2d_array[ n ] = new element_type[ 3 ];

That's all I have time for ATM. Look it over and try to start using typedefs in your code to separate things into managable types.

Hope this helps.
Thanks for your help! Suddenly something clicked about the data types and I realized I wasn't using ***, **, and * properly. I'll definitely need to do a few more practice problems, but it's starting to sink in! Here's the code, it compiles properly!

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <iostream>
#include <string>

using namespace std;

void getargs(int& height, int& width, int& length);
int ***initializearray(int& height, int& width, int& length, int*** carray);
void printarray(int& height, int& width, int& length, int*** carray);
bool goagain();
void freearray(int& height, int& width, int& length, int*** carray);


//Main function declares variables, then cycles
//through functions to get arguments from user,
//then set the carray pointer to the value
//the user specifies. Then print array.
//Next, use a while loops to determine if the
//user would like to resize the array.
//If so then repeat, otherwise free memory.
int main()
{
int height, width, length;
int ***carray;
do
{
getargs(height, width, length);
carray = initializearray(height, width, length, carray);
printarray(height, width, length, carray);
}
while(goagain());
freearray(height, width, length, carray);
}

//Function takes in arguments declared in main and
//sets them to a user defined value.
void getargs(int& height, int& width, int& length)
{
    cout<<"Enter a height for your array:"<<endl;
    cin>>height;
    cout<<"Enter a width for your array:"<<endl;
    cin>>width;
    cout<<"Enter a length for your array:"<<endl;
    cin>>length;
}

//Get values defined by user. Pass array into function.
//Allocate a 3 dimensional array and give it values.
//Delete the old array and pass the pointer to the new memory.
int ***initializearray(int& height, int& width, int& length, int*** carray)
{
    int ***p_temparray = new int**[length];
    for(int i=0;i<length;i++)
    {
        p_temparray[i] = new int*[width];
        for(int j=0;j<width;j++)
        {
            p_temparray[i][j]=new int[height];
            for(int x=0;x<height;x++)
            {
                p_temparray[i][j][x]=i*j*x;
            }
        }

    }
    delete [] carray;
    return p_temparray;
}

//Get height width and length then print the values for each
//array coordinate.
void printarray(int& height, int& width, int& length, int*** carray)
{
    for(int i=0;i<length;i++)
    {
        for(int j=0;j<width;j++)
        {
            for(int x=0;x<height;x++)
            {
                cout<<"carray["<<i<<"]["<<j<<"]["<<x<<"]="<<carray[i][j][x]<<endl;
            }
        }
    }
}

//Check to see if user wants to resize array.
//If so, then loop functions again.
bool goagain()
{
    string arg;
    cout<<"Would you like to resize the array?\n";
    cin>>arg;
    if(arg=="y")
    {
        return true;
    }
    else
    {
        return false;
    }
}

//Cycle through the array and delete allocated memory.
void freearray(int& height, int& width, int& length, int*** carray)
{
    for(int i=0;i<length;i++)
    {
        delete [] carray[i];
        for(int j=0;j<width;j++)
        {
            delete [] carray[i][j];
        }

    }
    delete [] carray;
}
Topic archived. No new replies allowed.