a pointer to a multidimensional array

I'm trying to make a pointer to a multidimensional array. Any idea how to do that?

In my old post I already found out how to do that with one array.
http://arduino.cc/forum/index.php/topic,53807.0.html

My code.

int _rybWheel[25][3] = 
	{ 	{ 0  , 255, 255 }, // 0
		{ 12 , 255, 255 }, // 15
		{ 24 , 255, 255 }, // 30
		{ 30 , 255, 255 }, // 45
		{ 36 , 255, 255 }, // 60
		{ 42 , 255, 255 }, // 75
		{ 48 , 255, 255 }, // 90
		{ 54 , 255, 255 }, // 105
		{ 60 , 255, 255 }, // 120
		{ 72 , 255, 255 }, // 135
		{ 84 , 255, 255 }, // 150
		{ 108, 255, 255 }, // 165
		{ 120, 255, 255 }, // 180
		{ 154, 255, 255 }, // 195
		{ 180, 255, 255 }, // 210
		{ 206, 255, 255 }, // 225
		{ 225, 255, 255 }, // 240
		{ 240, 255, 255 }, // 255
		{ 260, 255, 255 }, // 270
		{ 265, 255, 255 }, // 285
		{ 280, 255, 255 }, // 300
		{ 300, 255, 255 }, // 315
		{ 315, 255, 255 }, // 330
		{ 333, 255, 255 }, // 345
		{ 360, 255, 255 }  // 360  
	};

I declare the array in the .h file like this:

int* rybWheel;

And in the constructor I write.

rybWheel = _rybWheel;

And I do this in a function (thats the error on line 360)

Serial.println(rybWheel[rybWheelIndex+1][0],DEC);

I get these errors:

/Users/macbook/Dropbox/code/_arduino/libraries/ColorLight/ColorLight.cpp: In constructor 'ColourPalette::ColourPalette()':
/Users/macbook/Dropbox/code/_arduino/libraries/ColorLight/ColorLight.cpp:55: error: cannot convert 'int [25][3]' to 'int*' in assignment
/Users/macbook/Dropbox/code/_arduino/libraries/ColorLight/ColorLight.cpp: In member function 'void ColourPalette::ColourAtRYBWheel(int, int*)':
/Users/macbook/Dropbox/code/_arduino/libraries/ColorLight/ColorLight.cpp:360: error: invalid types 'int[int]' for array subscript

I've looked up some information on pointers, but I cannot find clear information about pointers to multidimensional arrays and how I can use that with Arduino.

A two dimensional array is really an array of pointers to one dimensional arrays. So, a pointer to a 2D array needs two stars.

int** rybWheel;

Yes, but if I try that then I get this error:

/Users/macbook/Dropbox/code/_arduino/libraries/ColorLight/ColorLight.cpp:55: error: cannot convert 'int [25][3]' to 'int**' in assignment

I tried this as well:

rybWheel = &_rybWheel;

error: /Users/macbook/Dropbox/code/_arduino/libraries/ColorLight/ColorLight.cpp:55: error: cannot convert 'int (*)[25][3]' to 'int**' in assignment

Pointer is still a hard subject to grab for me.

Yes, but if I try that then I get this error:

Lean a little to the left. I can't see line 55.

A little further...

No, still can't see.

Ooh, careful, don't fall off the chair.

Ok, sorry for not clearly documenting it. I've made a minimized version of the code, that gives me the error.

The Colorlight.h file

#ifndef ColorLight_h
#define ColorLight_h

#include "WProgram.h"

class ColourPalette
{
  public:
    ColourPalette();
    
    int** rybWheel;
};
#endif

The ColorLight.cpp file

#include "WProgram.h"
#include "ColorLight.h"

int _rybWheel[25][3] = 
	{ 	{ 0  , 255, 255 }, // 0
		{ 12 , 255, 255 }, // 15
		{ 24 , 255, 255 }, // 30
		{ 30 , 255, 255 }, // 45
		{ 36 , 255, 255 }, // 60
		{ 42 , 255, 255 }, // 75
		{ 48 , 255, 255 }, // 90
		{ 54 , 255, 255 }, // 105
		{ 60 , 255, 255 }, // 120
		{ 72 , 255, 255 }, // 135
		{ 84 , 255, 255 }, // 150
		{ 108, 255, 255 }, // 165
		{ 120, 255, 255 }, // 180
		{ 154, 255, 255 }, // 195
		{ 180, 255, 255 }, // 210
		{ 206, 255, 255 }, // 225
		{ 225, 255, 255 }, // 240
		{ 240, 255, 255 }, // 255
		{ 260, 255, 255 }, // 270
		{ 265, 255, 255 }, // 285
		{ 280, 255, 255 }, // 300
		{ 300, 255, 255 }, // 315
		{ 315, 255, 255 }, // 330
		{ 333, 255, 255 }, // 345
		{ 360, 255, 255 }  // 360  
	};


ColourPalette::ColourPalette()
{	
	rybWheel = _rybWheel; 
}

This will give the error below:

/Users/macbook/Dropbox/code/_arduino/libraries/ColorLight/ColorLight.cpp: In constructor 'ColourPalette::ColourPalette()':
/Users/macbook/Dropbox/code/_arduino/libraries/ColorLight/ColorLight.cpp:37: error: cannot convert 'int [25][3]' to 'int**' in assignment

Line 37 is rybWheel = _rybWheel;

A two dimensional array is really an array of pointers to one dimensional arrays

No, that would be an Iliffe vector.

A two dimensional array is really just a concatentation of one dimensional arrays.

In the ColorLight.cpp file, you are defining a global variable, _rybWheel. I guess that I am at a loss to understand why you need a member variable that points to it, but, this compiles:

ColourPalette::ColourPalette()
{	
  rybWheel = (int **)_rybWheel; 
}

Well, I think I don't really get what I'm doing. Declaring things in the .h file is new for me for example.

The problem was that I got back a lot of number that we're not in the array. So for sure the array didn't exist anymore and I got back some other data from the same memory address.

I now declared the array as a normal global array and not as a member variable (I suppose a member variable is a variable of an object). Is it right that I don't have to put those global variables in the header (.h) file? It works for now at least.

I'm trying to port some classes I wrote in Processing to Arduino, but that seems more difficult then I expected.

int _rybWheel[25][3] =
Serial.println(rybWheel[rybWheelIndex+1][0],DEC);

The problem is that the declaration tells the compiler that your array consists of twenty-five rows of three "int"s.
The rows are arranged in memory one after the other, so _rbyWheel[1][0] has an address six bytes (two bytes per "int") higher than _rbyWheel[0][0]

If you simply assign a pointer to the start of the array int* rybWheel = _rybWheel;, then the compiler has lost the ability to know what the length of each row is - the pointer could point to an array of three rows of twenty-five elements, or a simple vector of seventy-five elements.
However, the compiler doesn't need to know the number of rows, just their length.

int (*rybWheel)[3] = _rybWheel;

I'm still struggling with strange values. However I don't know how to solve it. I thought its was related to the pointer and the array, but I'm not sure now.

I've updated my code and now use a normal global array (for this example I removed the multidimensional array that I used above).

My code:
header file:

#ifndef ColorLight_h
#define ColorLight_h

#include "WProgram.h"

class ColourBase
{
  public:
    ColourBase();  	
  	int baseHue;           // hue value on the circle  
	float *wheelHSBColor; 
};

class ColourPalette
{
  public:
    ColourPalette();
  
	int mainHue;
	int complementOffset;
	int hueAngle;
	int complementAngle; 
	
	ColourBase cArray[6]; 
	void updatePalette();
	void ColourAtRYBWheel(int, float*);
	
	float lerp(float, float, float);	
};
#endif

.cpp file

#include "WProgram.h"
#include "ColorLight.h"

const int rybHueWheel[25] = 
{ 0  , 12 , 24 , 30 , 36 , 42 , 48 , 54 , 60 , 72 , 84 , 108, 120, 154, 180, 206, 225, 240, 260, 265, 280, 300, 315, 333, 360 };

ColourBase::ColourBase()
{	float wheelHSBColor[3];
}

ColourPalette::ColourPalette()
{	mainHue = 5;
	complementOffset = 0;
	hueAngle = 30; 
	complementAngle = 30;   
	
	updatePalette();
}

void ColourPalette::updatePalette()
{ 
  Serial.println("update palette");	 
  cArray[0].baseHue = mainHue;
  cArray[1].baseHue = mainHue - hueAngle;
  cArray[2].baseHue = mainHue + hueAngle;
  cArray[3].baseHue = mainHue + 180 + complementOffset;
  cArray[4].baseHue = cArray[3].baseHue - complementAngle;
  cArray[5].baseHue = cArray[3].baseHue + complementAngle;

  // convert to new hue numbers with the new ColorWheel (HueToRYB)
  for (int i=0; i<6;i++)
  { ColourAtRYBWheel(cArray[i].baseHue, cArray[i].wheelHSBColor);
  }        
}

void ColourPalette::ColourAtRYBWheel(int hue, float c[3]) {
  	
  if (hue<0)    hue = 360+hue;      
  hue = hue%360; // stick to 0 - 359

  int   rybWheelIndex  = hue/15;      	// colourWheel has 24 base colours 
  
  float rybWheelAmount = (hue%15)/15.0; // interpolate amount

  c[0] = lerp(rybHueWheel[rybWheelIndex], rybHueWheel[rybWheelIndex+1], rybWheelAmount);
  c[1] = lerp(rybHueWheel[4], rybHueWheel[5], rybWheelAmount);
  c[2] = lerp(255, 255, rybWheelAmount);  
    
  Serial.print("hue : ");
  Serial.println(hue, DEC);
  
  Serial.print("wheelindex: ");
  Serial.println(rybWheelIndex, DEC);
  
  Serial.print("wheelamount: ");
  Serial.println(rybWheelAmount,DEC);
     
  Serial.println("===================");
}

float ColourPalette::lerp(float a, float b, float x)
{ return(a*(1-x) + b*x);
}

If I print this I'll get:

update palette
hue : -32704
wheelindex: 0
wheelamount: -30704688.0000000000
===================
hue : -24509
wheelindex: 0
wheelamount: -30704688.0000000000
===================
hue : -12223
wheelindex: 0
wheelamount: -30704688.0000000000
===================
hue : 835
wheelindex: 0
wheelamount: -30704688.0000000000
===================
hue : -18366
wheelindex: 0
wheelamount: -30704688.0000000000
===================
hue : 15427
wheelindex: 0
wheelamount: -30704688.0000000000
===================?

However when I comment the lines that start with c[1] and [c2] I get the right output.

  c[0] = lerp(rybHueWheel[rybWheelIndex], rybHueWheel[rybWheelIndex+1], rybWheelAmount);
  //c[1] = lerp(rybHueWheel[4], rybHueWheel[5], rybWheelAmount);
  //c[2] = lerp(255, 255, rybWheelAmount);
update palette
hue : 5
wheelindex: 0
wheelamount: 0.3333333492
===================
hue : 335
wheelindex: 22
wheelamount: 0.3333333492
===================
hue : 35
wheelindex: 2
wheelamount: 0.3333333492
===================
hue : 185
wheelindex: 12
wheelamount: 0.3333333492
===================
hue : 155
wheelindex: 10
wheelamount: 0.3333333492
===================
hue : 215
wheelindex: 14
wheelamount: 0.3333333492
===================?

So repeatedly calling the lerp function gives this bug. Has it the do with a lack of memory?

I don't know if its smart to use floats (since I read about speed issues), but I cannot find good examples of fixed point or integer linair interpolation functions.

Also the question if its possible to use the Flash library like this (Flash | Arduiniana) in my library. Is it just including the .h and files? Are there any examples on that?

ColourBase::ColourBase()
{	float wheelHSBColor[3];
}

What do you think this is doing? You've declared a local variable that immediately goes out of scope. You are not assigning any values to it.

class ColourBase
{
  public:
    ColourBase();  	
  	int baseHue;           // hue value on the circle  
	float *wheelHSBColor; 
};

The variable ColourBase::wheelHSBColor is a pointer that points nowhere. This is likely NOT what you want, since the constructor doesn't point it anywhere, either.

ColourAtRYBWheel(cArray[i].baseHue, cArray[i].wheelHSBColor);

You are calling this function with a pointer (cArray*.wheelHSBColor) that points nowhere.*
```
*void ColourPalette::ColourAtRYBWheel(int hue, float c[3]) {
 
// Snipped some code

c[0] = lerp(rybHueWheel[rybWheelIndex], rybHueWheel[rybWheelIndex+1], rybWheelAmount);
  c[1] = lerp(rybHueWheel[4], rybHueWheel[5], rybWheelAmount);
  c[2] = lerp(255, 255, rybWheelAmount);*
```
And, even though c is not a real array (you have allocated no space for it), you try to write to that space.
As you have figured out, you can't do that (successfully).

Paul thanks for the great help you provide here in the forum helping to solve some problems.

I think I've solved part of the problem. Stupid indeed not to assign values to the arrays and the ColourBase object.

Although I have the idea that I did everything good now, there still goes something wrong with the c array in combination with the ColourAtRYBWheel function.

My .h file

#ifndef ColorLight_h
#define ColorLight_h

#include "WProgram.h"

class ColourBase
{
  public:
    ColourBase();  	
    
  	int baseHue;           // hue value on the circle  
	int *wheelHSBColor; 
};

class ColourPalette
{
  public:
    ColourPalette();
  
	int mainHue;
	int complementOffset;
	int hueAngle;
	int complementAngle; 
	
	ColourBase *cArray; 
	void updatePalette();
	void ColourAtRYBWheel(int, int*);
	
	int lerpInt(int, int, int, int);		
};
#endif

My .cpp file

##include "WProgram.h"
#include "ColorLight.h"

const int rybHueWheel[25] = 
{ 0  , 12 , 24 , 30 , 36 , 42 , 48 , 54 , 60 , 72 , 84 , 108, 120, 154, 180, 206, 225, 240, 260, 265, 280, 300, 315, 333, 360 };

ColourBase::ColourBase()
{	int wheelHSBColor[] = {0, 0, 0};
}

ColourPalette::ColourPalette()
{	
	ColourBase cArray[6];
	
	for (int i=0;i<6; i++)
    { cArray[i] = ColourBase();
    } 	
	
	mainHue = 5;
	complementOffset = 0;
	hueAngle = 30; 
	complementAngle = 30;   
	
	updatePalette();
}

void ColourPalette::updatePalette()
{ 
  Serial.println("update palette");	 
  cArray[0].baseHue = mainHue;
  cArray[1].baseHue = mainHue - hueAngle;
  cArray[2].baseHue = mainHue + hueAngle;
  cArray[3].baseHue = mainHue + 180 + complementOffset;
  cArray[4].baseHue = cArray[3].baseHue - complementAngle;
  cArray[5].baseHue = cArray[3].baseHue + complementAngle;

  // convert to new hue numbers with the new ColorWheel (HueToRYB)
  for (int i=0; i<6;i++)
  { ColourAtRYBWheel(cArray[i].baseHue, cArray[i].wheelHSBColor);
  }        
}

void ColourPalette::ColourAtRYBWheel(int hue, int c[3]) {
  	
  if (hue<0)    hue = 360+hue;      
  hue = hue%360; // stick to 0 - 359

  int rybWheelIndex  = hue/15;      	// colourWheel has 24 base colours 
  int rybWheelAmount = hue%15; 
  
  c[0] = lerpInt(rybHueWheel[rybWheelIndex], rybHueWheel[rybWheelIndex+1], rybWheelAmount,15);
 
  Serial.print("hue : ");
  Serial.println(hue, DEC);
  
  Serial.print("wheelindex: ");
  Serial.println(rybWheelIndex, DEC);
  
  Serial.print("val in wheelindex: ");
  Serial.println(rybHueWheel[rybWheelIndex], DEC);  
  Serial.print("val in wheelindex +1 : ");
  Serial.println(rybHueWheel[rybWheelIndex+1], DEC);
  
  Serial.print("wheelamount: ");
  Serial.println(rybWheelAmount,DEC);
  
  Serial.print("result in array: ");
  
  Serial.println(c[0],DEC);  
  Serial.print("result direct: ");
  Serial.println(lerpInt(rybHueWheel[rybWheelIndex], rybHueWheel[rybWheelIndex+1], rybWheelAmount,15));

  Serial.println("===================");
}

int ColourPalette::lerpInt(int a, int b, int f, int max)
{ 	// f is a number between 0 - max
	return a + ( (b-a) * f/max );
}

I think something goes wrong with writing values to the c array in the function ColourAtRYBWheel. Probably its still not declared ok, but how can I solve that.

The results I print. In all cases the "result in array" should be the same as "result direct". I two cases thats not the case, so the number changes somewhere in between.

update palette
hue : 5
wheelindex: 0
val in wheelindex: 0
val in wheelindex +1 : 12
wheelamount: 5
result in array: 198
result direct: 4
===================
hue : 335
wheelindex: 22
val in wheelindex: 315
val in wheelindex +1 : 333
wheelamount: 5
result in array: 321
result direct: 321
===================
hue : 35
wheelindex: 2
val in wheelindex: 24
val in wheelindex +1 : 30
wheelamount: 5
result in array: 0
result direct: 26
===================
hue : 185
wheelindex: 12
val in wheelindex: 120
val in wheelindex +1 : 154
wheelamount: 5
result in array: 131
result direct: 131
===================
hue : 16
wheelindex: 1
val in wheelindex: 12
val in wheelindex +1 : 0
wheelamount: 1
result in array: 12
result direct: 12
===================
hue : 10
wheelindex: 0
val in wheelindex: 0
val in wheelindex +1 : 12
wheelamount: 10
result in array: 8
result direct: 8
===================?

I've implemented a lerp with only integers, so that part of the problem is solved.

ColourPalette::ColourPalette()
{	
	ColourBase cArray[6]; // GET RID OF THIS!
	
	for (int i=0;i<6; i++)
    { cArray[i] = ColourBase();
    } 	
	
	mainHue = 5;
	complementOffset = 0;
	hueAngle = 30; 
	complementAngle = 30;   
	
	updatePalette();
}
	int *wheelHSBColor;

Changing the type from float to int doesn't change the fact that this points nowhere.

ColourBase::ColourBase()
{	int wheelHSBColor[] = {0, 0, 0};
}

Changing the type from float to int doesn't change the fact that this is a local variable that goes out of scope as soon as the constructor ends. The pointer still points nowhere.

  c[0] = lerpInt(rybHueWheel[rybWheelIndex], rybHueWheel[rybWheelIndex+1], rybWheelAmount,15);

The c pointer still points to no reserved space, so you still can't write there.

I'm puzzled. Its clear for me that changing the type doesn't change anything.
I don't get that I'm pointing to nowhere.

Let me explain how I think and what I want.

I've made a ColourBase object to store different variables and arrays.
I this case I have only the wheelHSBColor array and the baseHue integer, but I'd like to use more arrays and variables.

So I make 6 ColourBase objects in the constructor of the ColourPalette

ColourBase cArray[6]; // calling this I allocated the space for an array with 6 ColourBase objects?
	
for (int i=0;i<6; i++)
{ cArray[i] = ColourBase(); // here I will "fill up" the array with new created ColourBase objects. 
}

By calling ColourBase(); I assume that I create 6 ColourBase() objects and also allocate memory space for the wheelHSBColor[] array since I create an array by doing this in the ColourBase constructor:

int wheelHSBColor[] = {0, 0, 0};

In the updatePalette() function called from the ColourPalette constructor I will set the value of each baseHue variable in each ColourBase object

  cArray[0].baseHue = mainHue;
  cArray[1].baseHue = mainHue - hueAngle;
  cArray[2].baseHue = mainHue + hueAngle;
  cArray[3].baseHue = mainHue + 180 + complementOffset;
  cArray[4].baseHue = cArray[3].baseHue - complementAngle;
  cArray[5].baseHue = cArray[3].baseHue + complementAngle;

Then I'll call the ColourAtRYBWheel function to fill the wheelHSBColor array in each ColourBase object (stored in the cArray)

for (int i=0; i<6;i++) {
   ColourAtRYBWheel(cArray[i].baseHue, cArray[i].wheelHSBColor);
}

In my assumption does c[0] point to index[0] of the wheelHSBColor array as index c[1] will point to wheelHSBColor[1].
Since I use a for-loop I think I'll fill each wheelHSBColor array for each ColorBase object.

I hope I cleared up my way of thinking. Hope you can point out what goes wrong. Thank you in advance.

I don't get that I'm pointing to nowhere.

A pointer is like a card with an address on it. When you dereference the pointer, you look at the address on the card to find where the data is/goes.

Your pointers are like blank cards. When you want to store data at the address on the card, and there is no address on the card, what do you do?

Write there anyway is not the right answer.

You need to make the pointer point to some space where you have permission to write to. That can be a static array, or to a dynamically allocated block of memory. Either way, you get an address on your card, so you CAN store data there.

Pointers are powerful, but they are not magic. Something (that's code you write) needs to make the pointer point somewhere.

By calling ColourBase(); I assume that I create 6 ColourBase() objects and also allocate memory space for the wheelHSBColor[] array since I create an array by doing this in the ColourBase constructor:

You are defining an array, but that array is local in scope (limited to the constructor) and lifetime (it goes away when the constructor ends).

Yes, using pointers is still hard to grasp for me, thank your for the clear metaphor.

You are defining an array, but that array is local in scope (limited to the constructor) and lifetime (it goes away when the constructor ends).

So I have to do this in the .h file in the public section of the class?

int wheelHSBColor[3];

And for the cArray:

ColourBase cArray[6];

I thought I couldn't initialize anything in the .h files, but I think I was wrong?

I thought I couldn't initialize anything in the .h files, but I think I was wrong?

You can't initialize things in the header file. Initialization is done in the source file.

Yes, those changes are needed and proper.

Completely clear now. Thanks for the effort explaining it.

And back again with another question. .. :frowning:

I think I have a problem with the Colourbase objects. Because I get back some messed up values again.

I initialize my ColourBase objects like this:

for (int i=0;i<6; i++)
{ cArray[i] = ColourBase();
}

Is that good or is the memory space then not allocated? I've read that the "new" is not supported. I looked in this forum post:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1216134904
and try to include the code, but I get a multiple definition error (so I suppose its already somewhere, but where?).

I try to refer to the ColourBase objects in a function like this:

calculateShadeTint(cArray[i]);  // call to function and passing the object

void ColourPalette::calculateShadeTint(ColourBase c)
{
  c.tintHSBColor[0] = c.wheelHSBColor[0];
  c.tintHSBColor[1] = 255;
  c.tintHSBColor[2] = 255; 
}

What do I do wrong?