Dynamically declared 2 dimensional arrays

  As this is my first post on cplusplus.com, first of all thank you in advance for the help I anticipate receiving from other members. I am a retired chemist who is studying Visual C++ as a hobby to keep what passes for a brain active. I am still using VC++ 6.0 because the cost of the latest version is prohibitive for my limited uses.
  
I am developing a program which data is entered into a 2 dimensional array (raw_data[30][100]) defined at compile time. I have constructed a dialog box (CEditRawDataDlg) to edit the raw data in case of error in inputting the data. The dialog box asks the user for the row and column number of the incorrect datum and displays the current value in the dialog box. I have achieved this by declaring a reference (&m_pRaw_Data) to raw_data[0][0] (in the document class) in the dialog box class. By invoking the EN_CHANGE I can get the current value of raw_data[rows][columns] using *(m_pRaw_Data + (30 * m_row) + m_col). This works fine for the array declared at compile time.

I now want to use dynamically declared two dimensional array using the vector method. I have hit a problem since the dynamically declared array rows are not contiguous and leads to garbage values being returned (apart from the first row). Has anyone any idea how I might overcome this problem? I’ve tried lots of things but have not succeeded. Please be gentle with me guys because I’m just starting to learn. Thank you in advance.
Allan
  
You should use std::vector or some ready matrix library (there are tons of these in this forum).

dynamically declared array rows are not contiguous

Dynamically allocated array is contiguous but memory is not cleared after allocation. Use memset ( http://www.cplusplus.com/reference/cstring/memset/ ) to clear it before use.

ps. you can use visual studio express editions (2010,2012,2013, etc.)
declaring a reference (&m_pRaw_Data) to raw_data[0][0] (in the document class)

Based on what follows, it sound as if you've declared a pointer to the first element of the array (since you were able to add (30 * m_row) + m_col and then dereference the result). Make sure to not confuse references with pointers, and post actual lines of code.

I can get the current value of raw_data[rows][columns] using *(m_pRaw_Data + (30 * m_row) + m_col)

There are plenty of ways to make m_pRaw_Data[m_row][m_col] work even with arrays, and if you're using vectors of vectors, that would be the normal access. Can't you make the vector of vectors a member of your class?

(as for matrix libraries, boost.ublas and Eigen are popular)
Further to my question of yesterday, here is some more information about the actual coding. I am using the MFC Document/View architecture. I included the following in the document header file.

#include<vector>
using std::vector;

In the document cpp file I declared the 2 dimensional array using the following code in a separate function where I declare other arrays. This function is called when I either read raw data from file or create a new analysis and add raw data.

vector<vector<double> > raw_data;

int width = m + 2; // 2 more columns needed for subsequent processing
int height = n + 2; // 2 more rows needed for subsequent processing
raw_data.resize(height);
for(int i = 0; i < height; i++)
{
raw_data[ i ].resize(width);
}
The article in cplusplus.com uses the format raw_data<i>.resize(width) but when I try to compile the program using this format I get error C2673 binary '<' : no operator defined which takes a left-hand operand of type 'class std::vector<class std::vector<double,class std::allocator<double> >,class std::allocator<class std::vector
<double,class std::allocator<double> > > >' (or there is no acceptable conversion
).

On running the program in debug mode I have TRACE’d the output for a run involving 4 samples of 3 variables with the following result.

Address of raw_data[1][1] = 32131848, raw_data[1][2] = 32131856, raw_data[1][3] = 32131864,
Address of raw_data[2][1] = 32131752, raw_data[2][2] = 32131760, raw_data[2][3] = 32131768,
Address of raw_data[3][1] = 32132184, raw_data[3][2] = 32132192, raw_data[3][3] = 32132200,
Address of raw_data[4][1] = 32131656, raw_data[4][2] = 32131664, raw_data[4][3] = 32131672

As you can see, the columns are contiguous with 8 bytes difference in their addresses. The rows are all over the place and I cannot discern a pattern.

Tath, thanks for your input. I went to the link you suggested but could not follow the logic. Have you any other insights please? Also, I downloaded the latest two versions of Visual Studio Express but due to a bug, the latest version would not convert my versions written in V6.0. Furthermore, I believe that these versions do no support MFC unless I paid for the full editions.

Thanks for your help guys.

Allan

As you can see, the columns are contiguous with 8 bytes difference in their addresses. The rows are all over the place and I cannot discern a pattern.


Well, double type is 8 bytes long. How did you except addressing to be?

I dont know about resize, but all is described here: http://www.cplusplus.com/reference/vector/vector/resize/

Also here is my old post about 2d vectors - might be of use to you: http://www.cplusplus.com/forum/general/107678/

Hi guys.

Well, double type is 8 bytes long. How did you except addressing to be?


That's exactly as I'd expect it to be. My problem was that the columns weren't contiguous in memory and this is what caused my the problems. I've managed to find a way round this problem. I don't think the solution was very elegant but it works! I copied the raw_data[][] array in the Document to the Dialog box and got the data from this.

Thanks once again for your help. No doubt I'll be back when I hit the next snag.

Allan

when you create double array dynamically, array elements will never be contiguous in memory since this array will be array of pointers, ie.:

1
2
3
4
5
int *asd[2]; //these pointers are contiguous

//these arrays are not contiguous since they are assigned random heap address
asd[0] = new int [2]; //some random place
asd[1] = new int[3]; //some random place 


You need to create 1d array (like vector) but access it like 2d.

I wrote example to show you what i mean:
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <iostream>
#include <stdio.h>
#include <vector>

template<typename T>
class matrix
{
private:
    T * pData;
    unsigned colCount, rowCount;
public:
    matrix() : colCount(1), rowCount(1) { this->pData = new T[1];}
    ~matrix() { delete [] this->pData;}
    void resize( unsigned a_colCount, unsigned a_rowCount, T a_value)
    {
        T * pNewData = NULL;

        if ( a_colCount == 0)
            a_colCount = 1;

        if ( a_rowCount == 0)
            a_rowCount = 1;

        pNewData = new T[ a_colCount * a_rowCount];

        for ( unsigned row = 0; row < a_rowCount; row++)
        {
            for ( unsigned col = 0; col < a_colCount; col++)
            {
                if ( row < this->rowCount && col < this->colCount)
                {
                    pNewData[col + a_rowCount * row] = this->pData[col + this->rowCount * row];
                }
                else
                {
                    pNewData[col + a_rowCount * row] = a_value;
                }
            }
        }

        this->colCount = a_colCount;
        this->rowCount = a_rowCount;

        delete [] this->pData;
        this->pData = pNewData;
    }
    T& at( unsigned a_index)
    {
        if ( ( this->colCount + this->rowCount) > a_index)
        {
            return this->pData[ a_index];
        }
        else
        {
            //add some error handling here
            return this->pData[ 0];
        }
    }
    T& at( unsigned a_col, unsigned a_row)
    {
        if ( a_col < this->colCount && a_row < this->rowCount)
        {
            return this->pData[ a_col + this->rowCount * a_row];
        }
        else
        {
            //add some error handling here
            return this->pData[ 0];
        }
    }
    void clear( T a_value)
    {
        if ( NULL == this->pData)
            return;

        for ( unsigned row = 0; row < rowCount; row++)
        {
            for ( unsigned col = 0; col < colCount; col++)
            {
                this->pData[col + this->rowCount * row] = a_value;
            }
        }
    }
    unsigned size(void) const
    {
        return ( this->colCount + this->rowCount);
    }
    unsigned colSize(void) const
    {
        return this->colCount;
    }
    unsigned rowSize(void) const
    {
        return this->rowCount;
    }
};

template<typename T>
void print( matrix<T> * const p)
{
    for ( unsigned row = 0; row < p->rowSize(); row++)
    {
        for ( unsigned col = 0; col < p->colSize(); col++)
        {
            std::cout << p->at( row, col) << " ";
        }
        std::cout << std::endl;
    }
}

#define printMatrix(__a__) print<int> ( &__a__)

int main()
{
    matrix<int> a;

    a.at(0) = 2;

    printMatrix(a);

    a.resize( 10, 10, 7);
    a.at(1,2) = 3;

    printMatrix(a);
    
    a.resize( 5, 5, 5);

    printMatrix(a);

    a.resize( 8, 8, 8);

    printMatrix(a);

    a.clear( 0);

    printMatrix(a);

    system("pause");
    return 1;
}
Last edited on
Thanks tath. Most helpful. Sorry I've not got back to you before. I'll try it

Spara
Thanks a lot tath. I tried this but found that first element of the matrix i.e. a.at(0,0) is not initialized properly. I tried this->pData = NULL in the ctor and it works now.

Vinesh
@vineshgada
it was like that because this->pData = new T[1] create array, but dont initialize any data in it. For simple data like int, float i could simply write:
1
2
this->pData = new T[1];
this->pData[0] = 0;

but for objects like classes not always can be assigned 0;
thats why after creating matrix i assigned 1st value manually:
1
2
matrix<int> a;
a.at(0) = 2;

It can be done nicely by creating constructor with parameter
1
2
3
4
5
matrix(T a_defaultValue) : colCount(1), rowCount(1)
{
this->pData = new T[1];
this->pData[0] = defaultValue;
}
@tath

Thanks for your reply. I am initializing the value in constructor now.

On another note: col + this->rowCount * row should be changed to col + this->colCount * row .

Regards,
Vinesh
Topic archived. No new replies allowed.