Arrays for C++ newbies

I’m beginning to run into a lot a trouble with this subject.

For the time being I’m trying to get along with single dimension arrays that I set at a fixed size and then use a pointer to access them from another class. All well and good.

My trouble now is using multi-dimensional arrays and establishing array dimensions after declaring that I need an array in the header.

The former I’ve looked up on the net and it looks to be a total arse to do in C++. I cannot find a logical method for dealing with multi-dimensional arrays or a tutorial that covers it.

I also need to find out how to set up array dimensions at constructor time rather than in the header, otherwise I have to rewrite my classes for every single project. Can anyone tell me how to do this please?

I’ve looked around but can’t find anything at the moment. I’ve been told about Vectors, so I can look into those but I’d like to know if there’s any other ways of dealing with these issues because my project is going to have to deal with them a lot.

Thanks.

multidimensional arrays in C/C++ are difficult. i’ve been programming C++ for about ten years now, and i still have trouble getting the syntax right.

you probably don’t actually want to deal with arrays of arrays in raw C++. they’re confusing, which means your code is likely to be buggy, or leaky memory, or just generally not work in subtle ways that might throw you off later down the track. see below for better ways to do it.

but if you really want to use a 2D raw C++ array, the way to do them is to declare this in header file:

  
float** array_of_arrays;  

then in the constructor:

  
array_of_arrays = new float*[num_rows];  
for ( int i=0; i<num_rows; i++ )  
{  
  array_of_arrays[i] = new float[num_cols];  
}  

and then in your destructor (to avoid leaking memory):

  
  
for ( int i=0; i<num_rows; i++ )  
{  
  delete[] array_of_arrays[i];  
}  
delete[] array_of_arrays;  

the trick is to realise that in C++ an array is actually a pointer to a block of memory that is large enough to contain everything you want. so, eg, when i go

  
float* array_of_floats = new float[100];  

what array_of_floats will actually be is a pointer to the start of a block of memory that is (sizeof(float)*100+a little overhead) bytes long. and when you ask for array_of_floats[20] what you’re actually saying is, take the memory address of the start of the array_of_floats and add on (20*sizeof(float)) bytes, and then pull the float from out of that memory location.

for example, if sizeof(float) is 4, and array_of_floats points to memory address 0x8000, then array_of_floats[20] will give me the float at memory address 0x8000 + 0x50 (0x50 is decimal 80 in hexadecimal), ie memory address 0x8050.

confused yet? :slight_smile:

(you can also say things like

  
float* my_random_chunk_of_memory = (float*)0x123456;  

and then run through printing off everything - you’ll be accessing the data starting at memory address 0x123456 as though it was an array of floats, even though it may be something completely different. and if you go

  
my_random_chunk_of_memory[20] = 5.0f;  

then whatever was at my_random_chunk_of_memory[20] is now overwritten with your new data, which is probably a bad thing, depending on what my_random_chunk_of_memory is supposed to be doing. this is how you make self-modifying code - if you can find the memory address where the machine code for your functions are stored, you can rewrite them on the fly. all sorts of fun can be had this way, but you have to be super l33t to pull it off without making your computer crash.)

back to the question. when you make an array of arrays, what actually happens is that you make an array of pointers to arrays. that’s why you get ugly things like float** for an array of float arrays: ‘float**’ means a pointer to a pointer to a float. in other words, when you ask for an array of arrays, you’re actually asking for a pointer to the first element of a list of pointers to the first elements of a bunch of other lists. at this point i usually start to go crosseyed and think about other ways to deal with things.

so, here’s some other ways:

1- use a 1-dimensional array.

the basic concept is: a 2D array of floats that is 20x20 elements in size has 20*20=400 elements in total; then we can say that [0][0] in the 2D array is the same as [0] in the 1D array, and [1][0] is the same as [20], and [2][0] is [40], and [2][1] is [41], & c. so instead of float my_2d_array[20][20], just go my_clever_1d_array[400] , and to access element my_2d_array[5][15], just go my_clever_1d_array[5*20 + 15].

this is how pixel data is dealt with in openFrameworks: to access the pixel at (300,50) in an RGB image (which is actually a three-dimensional array), you go

  
int x = 300;  
int y = 50;  
int width = my_image.width;  
unsigned char* my_image_data = my_image.getPixelData();  
// red component  
unsigned char red = my_image_data[(width*y + x)*3];  
// green component  
unsigned char green = my_image_data[(width*y + x)*3 + 1];  

2- use a vector of vectors

  
  
// declare a vector of vectors (ie, a 2D vector)  
std::vector< std::vector<float> > vector_of_vectors;  
  
// add all the rows you want  
int row_count = 100;  
int col_count = 100;  
// allocate room for all the rows  
vector_of_vectors.resize( row_count );  
// for each row  
for ( int i=0;i<row_count; i++ )  
{  
  // allocate room for all the columns  
  vector_of_vectors[i].resize( col_count );  
}  
  
// now access like you would in a more script-y language:  
vector_of_vectors[38][5] = 10.0f;  
float thingy = vector_of_vectors[99][0] * vector_of_vectors[29][53];  
  

hope this helps
d

st33d,

Multidimensional arrays are just an abstraction for programmers, since we can obtain the same results with a simple array just by putting a factor between its indices:

  
int jimmy [3][5];   // is equivalent to  
int jimmy [15];     // (3 * 5 = 15)   

With the only difference that with multidimensional arrays the compiler remembers the depth of each imaginary dimension for us. Take as example these two pieces of code, with both exactly the same result. One uses a bidimensional array and the other one uses a simple array:

multidimensional array

  
#define WIDTH 5  
#define HEIGHT 3  
  
int jimmy [HEIGHT][WIDTH];  
int n,m;  
  
  for (n=0;n<HEIGHT;n++)  
    for (m=0;m<WIDTH;m++)  
    {  
      jimmy[n][m]=(n+1)*(m+1);  
    }  

pseudo-multidimensional array

  
int jimmy [HEIGHT * WIDTH];  
  
  for (n=0;n<HEIGHT;n++)  
    for (m=0;m<WIDTH;m++)  
    {  
      jimmy[n*WIDTH+m]=(n+1)*(m+1);  
    }  

read this:
http://www.cplusplus.com/doc/tutorial/arrays.html

ding

oh I forgot

I also need to find out how to set up array dimensions at constructor time rather than in the header

I second damian he sounds like he knows what he is talking about,

myclass.h

  
int ** myArray = 0;  
int Rows;  
int Cols;  

myclass.cpp

  
myArray = new *int[Rows];  
if (myArray != NULL) {  
  for (int i = 0; i < Rows; i++) {  
     myArray[i] = new int[Cols];  
  }  
}  

and to remove

  
for (int i = 0; i < Rows; i++) {  
  delete [] myArray[i];  
  myArray[i] = 0;  
}  
delete [] myArray;  
myArray = 0;  

ding

I used to implement my own array classes but once I got over the templates of the STL I never looked back. Here is some code (written from memory) of how you would do 2D arrays with the STL.

  
  
#include <vector>  
  
vector< vector<int> > my2DArray;  
  
  
// push 10x10 items into it  
//  
for( int i=0; i<10; ++i) {  
    vector<int> myNewRow;  
  
    for( int j=0; j<10; ++j) {  
        myNewRow.push_back( i*10+j );  
    }  
  
    my2DArray.push_back( myNewRow );  
}  
  
printf( my2DArray[1][5] );  
  
// results in 15  
  
  

The STL is super powerful and versatile but because of it is not exactly a lib that tells you how things should be done. Documentations and tutorials are usually really bad too. The good thing is once you understand it you understand the entire beast. If you are going to need dynamic data structures a lot it is well worth the time spend, though.

A good STL reference is this:
http://www.cppreference.com/index.html

1 Like

hey, I think I need to use a multidimensional array but I’m not sure, I was hoping I could give a quick run down on what I’m wanting to do and someone could recommend a plan of attack?

For all my scene’s up until this one I’ve had an image sequence (array of images) and I’ve controlled the image sequence by changing its xpos, ypos, and frame.

Now I’m wanting to have duplicate sequences appear on screen when certain conditions conditions are met, but I’m getting errors at the moment because C++ doesn’t like allocating a unknown amount memory I guess.

in my .h file I have:

  
   
  
               #define hairWorkerImages 100  
class ofHairWorker {  
	  
	public:       
  
               int numberWorkers;  
               int hairWorkerFrame[numberWorkers];  
		float xpos[numberWorkers];                           
		float ypos[numberWorkers];     
                ofImage sequencehairWorker[numberWorkers][hairWorkerImages];  
}  

Then in My.cpp:

not sure how to allocate the memory as the program will only need one copy of each image in memory but a variable amount of instances will be displayed.

at the moment I have:

  
  
ofHairWorker::ofHairWorker()  
{  
 numberWorkers = 1;   
  
  
for (int i = 0; i < hairWorkerImages; i++){                 
		string myImageName = "HairWorker" + ofToString(i) + ".png";      
		sequencehairWorker[i].allocate(400, 220, GL_RGBA);      
		sequencehairWorker[i].loadImage(myImageName);  
    }  
  
}  
  
void ofHairWorker::update(){  
  
    if (specialCondition == true){         
                      numberWorkers ++;                                        
                      ypos[numberWorkers ] = 0;      
                      xpos[numberWorkers ] = 0;    
                      hairWorkerFrame[numberWorkers] = 1;  
                                             
                      }  
  
}  
      

The amount of workers in my scene is variable but it will never be able to get really high, eg over a 100 so I was wondering if I could just set up say 100 to begin with and only use a few of them?? Ha I’m sure that’s a terrible idea! but thats all I can think of at the moment.

Sometimes its hard for me to understand explanations so I wont come off like I can understand what you are trying to do. But one thing I know for sure is you need to use a vector if your array is variable and you don’t want to set a max size.

http://www.cplusplus.com/reference/stl/-…-ector.html

ding

  
               int numberWorkers;  
               int hairWorkerFrame[numberWorkers];  
      float xpos[numberWorkers];                           
      float ypos[numberWorkers];     
                ofImage sequencehairWorker[numberWorkers][hairWorkerImages];  
}  

yeah, that’s not going to work.

like ding suggests, use vectors.

it might even be worth your while whipping up a quick class. i usually find if i’m making multiple arrays, all the same size, it’s time to make a new class. here’s an example for how to do this, if you’re just using arrays rather than vectors:

  
  
(put this in the same .h as your definition of class ofHairWorker - just above the class ofHairWorker { line would be fine.)  
  
class Worker  
{  
public:  
  float xpos;  
  float ypos;  
  int frame;  
  ofImage sequence[hairWorkerImages];  
};  
  
class ofHairWorker {  
  
public:  
  #define MAX_WORKERS 100  
  int numberWorkers; // set this to 0 on initialisation  
  Worker workers[MAX_WORKERS];  
  
...  
}  

hth
d

Hey thanks Damian! I’ve quickly tried to set it up as you recommended and I’ve had some early success so horray! ha.

Any contact from a certain uni? I’ve emailed the guy, no reply to me any to you? ha, apparently my supervisor knows you!, small world!

Ian

yeah I use to be afraid of making classes for everything until I figured out that they are just fancy stucts.

They are going alright for me but I do still have one issue. Since the class which is arrayed is allocating memory each time its displayed there is the chance of allocating the memory for the frames 100 times! I’m guessing it only needs to be allocated once since they all use the same images? but I’m not positive about that.

So what I’m trying to do is set up the image sequence in the main class ofHairWorker and have the other class reference that image sequence. The effect being that the memory will only be allocated once.

Not sure if that makes sense so I’ll post what I have so far,

****another idea, Could a pointer work??

  
in my .h:  
  
class Worker  
{  
public:  
  void draw();  
  void update();  
  float xpos;  
  float ypos;  
  int hairWorkerframe;  
  ofImage sequencehairWorker;  
  Worker();  
  
};   
  
class ofHairWorker {  
	  
	public:  
		void setup();  
		void update();  
		void draw();  
		ofImage sequencehairWorker[hairWorkerImages];  
		int numberWorkers;  
		int lastWorkerNumber;  
		#define MAX_WORKERS 1000  
                Worker myworkers[MAX_WORKERS];   
                bool initiated;  
            	ofHairWorker();  
  
}  
  
  
Then in my .cpp  
  
Worker::Worker(){  
                 xpos = 600;  
                 ypos = -100;  
                 hairWorkerframe = 0;  
                 sequencehairWorker = ofHairWorker.sequencehairWorker;   //this is where I'm running into problems trying to have an imageSequence use another imageSequence which is already set up and allocated memory.  
    }  
  
void Worker::draw(){  
	  ofEnableAlphaBlending();  
      ofHairWorker.sequencehairWorker[hairWorkerframe].draw(xpos,ypos);  
      }    
  
 void Worker::update(){     
  
          if ((ypos > 0)&&(hairWorkerframe != 19)) {  
                          hairWorkerframe ++;  
                          }  
                            
          if(hairWorkerframe > hairWorkerImages){  
                           hairWorkerframe = 0;    
                          }                      
}  
  
ofHairWorker::ofHairWorker()  
{  
  
if (initiated == false){  
        for (int i = 0; i < hairWorkerImages; i++){                 
		string myImageName = "HairWorker" + ofToString(i) + ".png";   
		sequencehairWorker[i].allocate(400, 220, GL_RGBA);      
		sequencehairWorker[i].loadImage(myImageName);	  
    }  
    initiated = true;  
}  
  
void ofHairWorker::update(){  
 myworkers[i].update();  
  
                      myworkers[numberWorkers].ypos = ofRandom(0, 700);   
                      myworkers[numberWorkers].xpos = ofRandom(400, 1200);   
}  
  
  
void ofHairWorker::draw(){  
       
       
     for (int i = 0; i < numberWorkers; i++){                 
	  myworkers[i].draw();	  
    }  
}  

oh i get what you’re trying to do.

yes, pointers are the way. try this:

  
  
class Worker {  
    ...  
    ofImage* sequencehairWorker;  
    setImage( ofImage* sequence );  
  
}  
...  
Worker::Worker(){  
                 xpos = 600;  
                 ypos = -100;  
                 hairWorkerframe = 0;  
                 sequencehairWorker = NULL;  
    }   
  
void Worker::setImage( ofImage* sequence ){  
     sequencehairWorker = sequence;  
}  
...  
(when you want to assign an image to a worker)  
worker.setImage( &sequencehairWorke[index] );  
  

no, no word from the uni - but i’ve been chatting with your supervisor (Karen, right?). we used to work together, she’s great. you should check out her video for HDU’s Tunuska, i think it’s on their website.

1 Like

man, I owe you soo much beer! Thanks, I was going to call it a night but now I can burn the midnight oil!

I’ll have a look at her video now, I haven’t actually seen any of her work yet so it’ll be interesting, I’m sure its great. oh and yip its Karen.

That’s unfortunate the guy at Vic hasn’t contacted you yet, I could flick you his email if you want. Although maybe it’d be better to just meet up with him when your over here.

Thanks again!

Ian