Go Down

Topic: a pointer to a multidimensional array (Read 1 time) previous topic - next topic

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.
Code: [Select]

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:
Code: [Select]

int* rybWheel;


And in the constructor I write.
Code: [Select]

rybWheel = _rybWheel;


And I do this in a function (thats the error on line 360)
Code: [Select]
Serial.println(rybWheel[rybWheelIndex+1][0],DEC);

I get these errors:
Code: [Select]

/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.

PaulS

A two dimensional array is really an array of pointers to one dimensional arrays. So, a pointer to a 2D array needs two stars.
Code: [Select]
int** rybWheel;


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

Code: [Select]

/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:
Code: [Select]

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.

PaulS

Quote
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
Code: [Select]

#ifndef ColorLight_h
#define ColorLight_h

#include "WProgram.h"

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


The ColorLight.cpp file
Code: [Select]

#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:
Code: [Select]

/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
Code: [Select]
rybWheel = _rybWheel;

AWOL

Quote
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.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

PaulS

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:

Code: [Select]
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.

AWOL

Code: [Select]
int _rybWheel[25][3] =
Code: [Select]
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
Code: [Select]
_rbyWheel[1][0] has an address six bytes (two bytes per "int") higher than
Code: [Select]
_rbyWheel[0][0]

If you simply assign a pointer to the start of the array
Code: [Select]
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.
Code: [Select]
int (*rybWheel)[3] = _rybWheel;
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

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:
Code: [Select]

#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
Code: [Select]

#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:
Code: [Select]

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.
Code: [Select]

  c[0] = lerp(rybHueWheel[rybWheelIndex], rybHueWheel[rybWheelIndex+1], rybWheelAmount);
  //c[1] = lerp(rybHueWheel[4], rybHueWheel[5], rybWheelAmount);
  //c[2] = lerp(255, 255, rybWheelAmount); 


Code: [Select]

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 (http://arduiniana.org/libraries/flash/) in my library. Is it just including the .h and files? Are there any examples on that?



PaulS

Code: [Select]
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.

Code: [Select]
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.

Code: [Select]
ColourAtRYBWheel(cArray[i].baseHue, cArray[i].wheelHSBColor);
You are calling this function with a pointer (cArray.wheelHSBColor) that points nowhere.

Code: [Select]
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
Code: [Select]

#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
Code: [Select]

##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.
Code: [Select]

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.

AWOL

Code: [Select]
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();
}
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

PaulS

Code: [Select]
int *wheelHSBColor;
Changing the type from float to int doesn't change the fact that this points nowhere.

Code: [Select]
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.

Code: [Select]
  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
Code: [Select]

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:
Code: [Select]

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
Code: [Select]

  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)
Code: [Select]

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.

Go Up