Array with different number of bytes in each "element" stumping me!

Hi all,

I don’t know if I’m just stupid or if what I’m trying to do is not possible, but here’s what I need help with:

Consider this array:

const char codes[] = {
    {0x00,},
    {0x10, 0x11,},
    {0x20, 0x21, 0x22,},
    {0x30, 0x31, 0x32, 0x33,},
    {0x40, 0x41, 0x42, 0x43, 0x44,},
    {0x50, 0x51, 0x52, 0x53, 0x54, 0x55,},
    {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,},
};

Now, this line:

[b]uint32_t n = sizeof (codes) / sizeof (*codes)[/b];

correctly returns the value “7” telling me that there are seven different “chunks” in the array.

And, I can iterate through them like this:

int main (void)
{
    init ();
    Serial.begin (115200);

    uint32_t x;
    uint32_t n = sizeof (codes) / sizeof (*codes);

    for (x = 0; x < n; x++) {
        fprintf (stdout, "value is 0x%02X\n", codes[x]);
    }

    while (1);
}

and I get the first byte of each “chunk”:

[b]value is 0x00
value is 0x10
value is 0x20
value is 0x30
value is 0x40
value is 0x50
value is 0x60[/b]

What’s stumping me is how to get the size of each “chunk”. For example, I want “the code” to tell me that the first chunk has one byte, the second one two, etc…

Then I want to be able to access each byte in any order I want. For example, if I did something like this (pseudo code):

[b][tt][tt]print (codes [3][1]);[/tt][/b]
[/tt]
I would get the second byte of “chunk” 3 which is “0x31”.

But I can’t seem to figure out how to get the length of each chunk. I can do this:

[b][tt][tt]print (codes [3] + 1);[/tt][/b]
[/tt]
…and get the “0x31” result, but I have no way of knowing how long “codes[3]” is.

I’m sure I’ll kick myself in the behind when I get the answer… it’s probably so simple I can’t see it. :confused:

Any help will, of course, be greatly appreciated. Thanks!

– Roger

I don't think you can. Not like that.

const char codes[] = {
    {0x00,},
    {0x10, 0x11,},
    {0x20, 0x21, 0x22,},
    {0x30, 0x31, 0x32, 0x33,},
    {0x40, 0x41, 0x42, 0x43, 0x44,},
    {0x50, 0x51, 0x52, 0x53, 0x54, 0x55,},
    {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,},
};

"warning: braces around scalar initialiser"
"warning: excess elements in scalar initialiser"

Google "Iliffe vector"

That is not how arrays in C work. Two dimensional arrays have to be rectangular.
So you either need to have some blank spacer or use strings to hold your data.

Alternatively use a linked list.

I’ve been meaning to wrap my head around C++11’s variadic templates for a while. This seems like a suitable problem for them.

The solution what I have allows code like this:

polyArray< char, 2,3,4 > array = {
  1,2, { 
  3,4,5, {
  6,7,8,9 }
}};
  
void setup() {
  Serial.begin( 9600 );

  for( int i = 0 ; i < array.length ; ++i ){
    for( int j = 0 ; j < array.sizeAt(i) ; ++j ){
      Serial.print( array[i][j], DEC );
      Serial.print( ',' );
    }
    Serial.print( '\n' );
  }
}

void loop(){}

The actual class is below, it was an absolute b*tch to piece together, but it works nicely. If your head explodes trying to read it, don’t worry, mine did while writing it.

//Written by Christoper Andrews.

template< typename T, unsigned... args > struct polyArray{};

template< typename T, unsigned N, unsigned... args >
  struct polyArray< T, N, args... >{
    enum{length = sizeof...(args) + 1 };
    unsigned sizeAt( int idx ){ return !idx ? N : next.sizeAt( --idx ); }
    T *operator[]( int idx ){ return !idx ? data : next[ --idx ]; }    
    T data[ N ];
    polyArray< T, args... > next;
};

template< typename T, unsigned N >
  struct polyArray< T, N >{
    enum{ length = 1 };
    T *operator[]( int idx ){ return data; }
    unsigned sizeAt( int idx ){ return N; }
    T data[ N ];
};

It is small at the moment, but vast improvements can be made, including bounds checking. For now, if your indices are bad then… pop

Two dimensional arrays do NOT have to be rectangular, but they DO have to be the correct type.

The sort of array the OP is trying to define, has to be an array of pointers to char. Not an array of char.

You might find the discussion here helpful

pYro_65:
I’ve been meaning to wrap my head around C++11’s variadic templates for a while. This seems like a suitable problem for them.

The solution what I have allows code like this:

polyArray< char, 2,3,4 > array = {

1,2, {
 3,4,5, {
 6,7,8,9 }
}};
 
void setup() {
 Serial.begin( 9600 );

for( int i = 0 ; i < array.length ; ++i ){
   for( int j = 0 ; j < array.sizeAt(i) ; ++j ){
     Serial.print( array[i][j], DEC );
     Serial.print( ‘,’ );
   }
   Serial.print( ‘\n’ );
 }
}

void loop(){}




The actual class is below, it was an absolute b*tch to piece together, but it works nicely. If your head explodes trying to read it, don't worry, mine did while writing it.


//Written by Christoper Andrews.

template< typename T, unsigned… args > struct polyArray{};

template< typename T, unsigned N, unsigned… args >
 struct polyArray< T, N, args… >{
   enum{length = sizeof…(args) + 1 };
   unsigned sizeAt( int idx ){ return !idx ? N : next.sizeAt( --idx ); }
   T *operator( int idx ){ return !idx ? data : next[ --idx ]; }    
   T data[ N ];
   polyArray< T, args… > next;
};

template< typename T, unsigned N >
 struct polyArray< T, N >{
   enum{ length = 1 };
   T *operator( int idx ){ return data; }
   unsigned sizeAt( int idx ){ return N; }
   T data[ N ];
};




It is small at the moment, but vast improvements can be made, including bounds checking. For now, if your indices are bad then... *pop*

It’s too early in the morning for me to even look at this (not to mention I haven’t had any coffee yet). I’ll look later. Thanks.

michinyon:
You might find the discussion here helpful

http://stackoverflow.com/questions/1088622/how-do-i-create-an-array-of-strings-in-c

Yeah, I see it now. I didn't want to have to do it that way, but I will probably have to.

Ultimately, that table will be ANSI/VT100 control codes that I'm going to use to lookup and discard ANSI sequences (except for a rare few).

For example, the "F12" key generates a hideous string something like:

[b]"0x1B, 0x5B, 0x33, 0x34, 0x7e"[/b]

and wreaks havoc on my menu program.

And, these sequences are of varying length, from 3 bytes all the way to 7!

But, there are a few that I DO want to capture and use, for example:

[b]"0x1B, 0x5B, 0x44"[/b]

which is "left arrow" (I convert to backspace).

I need to "catch all" and "use a few". I've been beating my head against the wall trying to implement this the "right" way (a state machine) and it's turning out to be too complicated... I also tried using a timeout because the ANSI sequences come fast, so "0x1B" plus "anything else" within a certain time frame is probably an ANSI code, but that wasn't reliable.

I have no need for high speed so a slow, kludgy lookup table interpreter will have to do.

That's what all this is about (the "Y" part of the XY problem Nick!) ;D

The throbbing pain in my head says you are right! ;D

An array of string pointers is the way then, surely?
You'll need a terminating null, but you'd need an excess byte anyway to hold the size (unless you marked the last character in the vector some other way, like setting bit 7)

It's too early in the morning for me to even look at this (not to mention I haven't had any coffee yet). I'll look later. Thanks.

No need to look at the class, only the sketch is important.

You wanted to do:
print (codes [3][1]); and get the size of each "chunk",

Well that's exactly what you can do:

** **Serial.print( array[i][j], DEC );** **

array.sizeAt(i)

Even sizeof( array ) == 9 bytes, so there is no extra overhead.

AWOL:
An array of string pointers is the way then, surely?
You’ll need a terminating null, but you’d need an excess byte anyway to hold the size (unless you marked the last character in the vector some other way, like setting bit 7)

Hmmm… that’s an idea. None of the bytes in the real lookup table will ever be “0x00”, so I could flag “end of sequence” with a zero!

What I plan to do is this (pseudo code):

[b]if char == 0x1B {
  compare to string[n][index] table
  if mismatch, then index = 0; next string in table
  if match then index++
  if char in string == 0x00 {
    we got a match!
    break; // "n" points to match
  }
  if end of table {
    failed to find match
  }
}[/b]

pYro_65:
No need to look at the class, only the sketch is important.

You wanted to do:
print (codes [3][1]); and get the size of each “chunk”,

Well that’s exactly what you can do:

** **Serial.print( array[i][j], DEC );** **

array.sizeAt(i)

Even sizeof( array ) == 9 bytes, so there is no extra overhead.

OH. I see. Sorry as I said I’m not in any shape to look at code yet. Need coffee. Badly.
I’m sure I’ll have it working by the time I go home today. Thanks again!

(gee for that matter, I don’t even need the “0x1B” (first entry in each line of the table) because that’s what triggers me to look at the table in the first place!)

You could make your own little function and go through each element to see which one is not NULL and update a counter.

The codes[0][0] will return 0, because if you use this, 0x00 does equal NULL

for(byte X = 0; X < 7; X++)
{
  byte count = 0;
  for (byte Y = 0; Y < 7; Y++)
  {
    if(codes[X][Y] != NULL) 
      count++;
  }
  Serial.print( X ); Serial.print( ": " ); Serial.println(count);
}

Result:

0: 0
1: 2
2: 3
3: 4
4: 5
5: 6
6: 7