Pages: [1] 2   Go Down
Author Topic: a pointer to a multidimensional array  (Read 1337 times)
0 Members and 1 Guest are viewing this topic.
Enschede - The Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 75
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
int* rybWheel;

And in the constructor I write.
Code:
rybWheel = _rybWheel;

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

I get these errors:
Code:
/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.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45972
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
int** rybWheel;

Logged

Enschede - The Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 75
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
/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:
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.
Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45972
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Enschede - The Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 75
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#ifndef ColorLight_h
#define ColorLight_h

#include "WProgram.h"

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

The ColorLight.cpp file
Code:
#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:
/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:
rybWheel = _rybWheel;
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 238
Posts: 24284
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45972
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
ColourPalette::ColourPalette()
{
  rybWheel = (int **)_rybWheel;
}
Logged

Enschede - The Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 75
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 238
Posts: 24284
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

If you simply assign a pointer to the start of the array
Code:
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:
int (*rybWheel)[3] = _rybWheel;
Logged

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

Enschede - The Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 75
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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:
#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:
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:
  c[0] = lerp(rybHueWheel[rybWheelIndex], rybHueWheel[rybWheelIndex+1], rybWheelAmount);
  //c[1] = lerp(rybHueWheel[4], rybHueWheel[5], rybWheelAmount);
  //c[2] = lerp(255, 255, rybWheelAmount); 

Code:
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?


Logged

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45972
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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:
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:
ColourAtRYBWheel(cArray[i].baseHue, cArray[i].wheelHSBColor);
You are calling this function with a pointer (cArray.wheelHSBColor) that points nowhere.

Code:
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).
Logged

Enschede - The Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 75
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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:
##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:
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.
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 238
Posts: 24284
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
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();
}
Logged

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

Seattle, WA USA
Online Online
Brattain Member
*****
Karma: 547
Posts: 45972
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Code:
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:
  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.
Logged

Enschede - The Netherlands
Offline Offline
Jr. Member
**
Karma: 0
Posts: 75
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
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:
  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:
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.
Logged

Pages: [1] 2   Go Up
Jump to: