Solved

Multidimensional array of pointers

Posted on 2004-04-07
23
38,004 Views
Last Modified: 2013-12-14
Hi,

I've been trying to allocate a multidimensional array of pointers, but have been unsuccessful as it seems that the multidimensional array examples have been of int, etc.

Lets say I have a class Foo and class Bar. I want to allocate a multidimensional array of Bar pointers

in class Foo{
Foo();
public:
  Bar *** mybararray;
}

in Foo(){

//initialize mybararray

}


so that eventually, I can do something like

Bar *myBar = mybararray[10][15];

But I've been having trouble, in that it seems that for different variations, my compiler complains that I pass back a "Bar" instead of "Bar*" when i do mybararray[10][15];

Thanks.

-Edward
0
Comment
Question by:edwardt
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 10
  • 4
  • 2
  • +4
23 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 10777998
>>But I've been having trouble, in that it seems that for different variations, my compiler complains

In which variations exactly?
0
 

Author Comment

by:edwardt
ID: 10778223
Lets say within Foo {

(Bar*) **mybararray;

}

within Foo(){
mybararray = Foo*[rows][cols];

}

gives me the following error

cannot convert `
   Foo* (*)[((cols - 1) + 1)]' to `Foo***' in assignment
0
 

Author Comment

by:edwardt
ID: 10778235
I've also done things like declare

Bar **mybararray;

but when I do

Bar * mybar = mybararray[1][2];

The compiler complains that I can't return a Bar type into a Bar* type.

-Edward
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
LVL 86

Expert Comment

by:jkr
ID: 10778273
>>but when I do
>>Bar * mybar = mybararray[1][2];
>>The compiler complains that I can't return a Bar type into a Bar* type.

And the compiler is right about that - you cannot do that. If you need a Bar*, you have to use

Bar * mybar = *mybararray[1][2];


0
 
LVL 23

Expert Comment

by:chensu
ID: 10778296
Bar mybar = mybararray[1][2];

or

Bar * mybar = &(mybararray[1][2]);
0
 
LVL 9

Accepted Solution

by:
Cayce earned 500 total points
ID: 10778332
I infer you're trying to create a Matrix of pointers to Bar.

So basically you need multidimensional arrays of (Bar*).

I think the best way is to go to dynamic structs, suchs as Vector or Deque.
If you don't want dynamic structs, I included the code for using normal ones at the end.

/* this typedef would help to easily understand the code for anyone */
typedef Bar* BarPtr;

/* C++ style, using dynamics structs - not really a good performer */

void foo() {
  std::deque< std::deque<BarPtr> > MyBarArray;

  const int XDIM = 9;
  const int YDIM = 17;
  MyBarArray.resize(XDIM);
  for(int x = 0; x < XDIM; x++)
  {
    MyBarArray[x].resize(YDIM);
    for(int y = 0; y < YDIM; y++)
      MyBarArray[x][y] = new Bar;
  }

  /* work with it */

  for(int x = 0; x < XDIM; x++)
    for(int y = 0; y < YDIM; y++)
      delete MyBarArray[x][y];
}

/* C-Style */

void foo() {
  BarPtr** MyBarArray = NULL;

  const int XDIM = 9;
  const int YDIM = 17;
  MyBarArray = (BarPtr**) malloc(sizeof(BarPtr*) * XDIM);
  for(int x = 0; x < XDIM; x++)
  {
    MyBarArray[x] = (BarPtr*) malloc(sizeof(BarPtr)* YDIM);
    for(int y = 0; y < YDIM; y++)
      MyBarArray[x][y] = new TObject;
  }

  /* work with it */

  for(int x = 0; x < XDIM; x++)
  {
    for(int y = 0; y < YDIM; y++)
      delete MyBarArray[x][y];
    free(MyBarArray[x]);
   }
   free(MyBarArray);

}
0
 

Author Comment

by:edwardt
ID: 10778365
Ok,

I've changed it so that I can have

        mybararray = new Bar * [rows];

     Bar * h = &(mybararray[3][3]);

works.

If I do Bar * h = *mybararray[3][3]; it gives
"no match for `*
   Bar&' operator"


Now I am trying to assign a few entries, like
mybararray[2][5] = new Bar(values); but the compiler complains
" invalid   conversion from `Bar*' to `int' "

Any ideas? :)

Also, what would be the proper way to instantiate the array? I know that my rows = rows and cols = cols in the constructor.

Thanks

-Edward


0
 

Author Comment

by:edwardt
ID: 10778404
Cayce - your stuff looks pretty complete. Let me take some time to implement and digest that.

Thanks.

-Edward
0
 
LVL 23

Expert Comment

by:chensu
ID: 10778464
>mybararray[2][5] = new Bar(values);

new Bar() returns Bar *. What is the data type of mybararray[2][5]? Bar? Int?
0
 

Author Comment

by:edwardt
ID: 10778549
the data type of mybararray[2][5] should be Bar*.
0
 

Author Comment

by:edwardt
ID: 10778671

Cayce, your code lets my rest of the code compile, except where I need to return a row of the array, lke

Bar * getRow( int i){
return mybararray[i];

}

It gives me
cannot convert `
   std::deque<Bar*, std::allocator<Bar*> >' to `
   Bar*' in return

as an error. Any work around?
0
 

Author Comment

by:edwardt
ID: 10778750
Ah - Cayce, I just used your C code instead and it compiles... i'll be testing it now...
0
 
LVL 9

Expert Comment

by:Cayce
ID: 10779079
Ed:

The C code should work flawlessy to return complete rows.

But you forgot a * on your function declaration:

Bar* getRow(int i)

should be:

Bar** getRow(int i) {

or

BarPtr* getRow(int i) {

Using typedefs is a very good practice.
0
 
LVL 30

Expert Comment

by:Axter
ID: 10779117
I recommend you use either a vector<vector<Bar> > type class, or to use the following class:
template < class T>
class dynamic_2d_array
{
public:
    dynamic_2d_array(int row, int col):m_row(row),m_col(col), m_data((row!=0&&col!=0)?new T[row*col]:NULL){}
    ~dynamic_2d_array(){if(m_data) delete []m_data;}
    inline T* operator[](int i) {return (m_data + (m_col*i));}
    inline T const*const operator[](int i) const {return (m_data + (m_col*i));}
private:
    const int m_row;
    const int m_col;
    T* m_data;
};


You can use the above class in the following manner:
dynamic_2d_array<Bar> My_2d_Bar(10, 15);

Where 10 is the first dimension, and 15 the second dimension.
You can reference the above type just like a C style 2D array.
My_2d_Bar[2][11] = xyz;

This is much safer then trying to use new[] operator because you don't have to worry about possible memory leaks that could occur if you don't delete the array.
0
 
LVL 30

Expert Comment

by:Axter
ID: 10779151
For your class, you can create it on the initialize list via following method.

class Foo{
Foo();
public:
  dynamic_2d_array<Bar> mybararray;
};

Foo::Foo()
:mybararray(10, 15) //Initialize variable here, between function name and the body of the function
{
}

Notice the full colon in the line the initialize list....
0
 
LVL 30

Expert Comment

by:Axter
ID: 10779194
>>* C++ style, using dynamics structs - not really a good performer */

FYI:
If you use a vector<> class with iterators, it will out perform the C-Style array, both static and dynamic.

The std::vector class with iterators has a higher optimization then code using index operator[].
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10781465
Hi edwardt,
> Using typedefs is a very good practice.

That's the trick with nested types. Just "typedef" your way around dimension by dimension:

typedef Bar* BarP;
typedef BarP* BarPArr;
typedef BarPArr* BarPArr2;

The good thing here is that you can replace this easily by some other solution later, such as vector:
typedef Bar* BarP;
typedef vector<BarP> BarPArr;
typedef vector<BarPArr> BarPArr2;

...and it's a lot more readable that Bar*** foo;

Cheers,
Stefan
0
 
LVL 12

Expert Comment

by:stefan73
ID: 10781504
edwardt,
Probably the easiest (and most "C++ish") way to solve this is a vector. Unfortunately, vectors don't grow automatically when you insert something new at a particular position, like they do in Perl, awk, or many other scripting languages. But that's just a matter of extending the vector template a little:


Here is an extension of the vector template which grows automatically like in Perl:

#include <vector>
#include <iostream>

using namespace std;



template<typename _Tp>
    class auto_vector : public vector<_Tp>
    {
         public:
         typedef _Tp               value_type;
         typedef value_type&       reference;
        typedef const value_type& const_reference;
        typedef size_t            size_type;
        explicit
        auto_vector()
        : vector<value_type>() { }
       
       
         reference
           operator[](size_type __n) {
                cout << "[" << __n << "] access. size=" << capacity();
                if(__n >= capacity()){
                       reserve((3*__n)/2 + 1); // Slop factor 1.5
                       cout << " -> vector grows to " << capacity();
                }
                cout << endl;
                return *(begin() + __n);
           }
           
           
        const_reference
        operator[](size_type __n) const {
                cout << "[" << __n << "] const access. size=" << capacity();
                if(__n >= capacity()){
                       reserve((3*__n)/2 + 1); // Slop factor 1.5
                       cout << " -> vector grows to " << capacity();
                }
                cout << endl;
             return *(begin() + __n);
        }    
        reference
        at(size_type __n) {return (*this)[__n]; }        
       
        const_reference
        at(size_type __n) const {return (*this)[__n]; }        
           
};
         

main(){
     auto_vector<auto_vector<int> > v2;
     
     v2[126][112]=32;
     cout << "v2[126][112]=" << v2[126][112] << endl;
     cout << "v2[126].capacity()=" << v2[126].capacity() << endl;
     cout << "v2[125].capacity()=" << v2[125].capacity() << endl;
}

...just remove the debug output lines once it's working and replace the in by BarP.

(probably the tons of typedefs at the beginning of the class definition are not necessary, as they're already definied in the parent class.)

Stefan
0
 

Author Comment

by:edwardt
ID: 10787444
Cayce,

How concerned should I be with memory leaks under your C version? I'm hoping I don't have to be considering to keep track of these arrays and continuously call delete.

Thanks.

-Edward
0
 
LVL 30

Expert Comment

by:Axter
ID: 10788037
>>How concerned should I be with memory leaks under your C version? I'm hoping I don't have to be considering to keep track of these arrays and continuously call delete.

When ever you use dynamic memory with dumb pointers, you have to be concern with memory leaks.
That's why I would advice against using a pointer method.

Instead use a container, which is similar to a smart poitner, in that it does the clean up job for you.
The dynamic_2d_array class I previously posted will do that for you.

If you use vector class with static objects, it will also clean up the memory for you.

Using a vector<> with pointers is just as bad as using a C-Style 2D pointer, in that you have to make sure you delete all the objects.
0
 

Author Comment

by:edwardt
ID: 10862322
Thanks guys - at this point, I'll work with the original C style coding. If / when I realize some issues with memory leaks, I'll come back ;)-Edward
0
 

Author Comment

by:edwardt
ID: 10862347
Axter - your stuff was really good too I'll create another quesition for you for me to accept your answer.
- Edward
0
 
LVL 6

Expert Comment

by:SJT2003A
ID: 11016343
Edward,

    What I understand from your initial post is that you are trying to point an array (row) of bars which is a subset of mybararray. Since the mybararray has been declared with three stars (pointers), taking each star as a single array or row of elements, mybararray can be used/treated as a three dimensional arrays. As I see in your declaration

Bar *myBar = mybararray[10][15];

your intention is to point a row of values located at 10th row and 15 column in the triple dimension value array.  Your declaration should work, but some compiler which are not completely ASNI compatable may complain about it. Not to side track or put you in different direction, I suggest you to use the address of first element of that row, like

Bar *myBar = &mybararray[10][15][0];

This is same as your declaration, but for some reason, it does not work, you can this one for the same. But keep in mind, you are using pointers so you should also little bother about freeing the memory if you using it of heap.

Hope this helps. Good luck :)
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
How to install Selenium IDE and loops for quick automated testing. Get Selenium IDE from http://seleniumhq.org Go to that link and select download selenium in the right hand column That will then direct you to their download page. From that p…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

630 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question