My mind hit a brick wall - How to do int arrays with different length elements?

Hi all,

I need to do something like this:

static const uint8_t vectors[][] PROGMEM = {
    first element: 0x10,0x00,0xFF,0xFF
    second element: 0x0A,0x00,0x05,0x13,0x05,0x14,0x05,0x15,0xFF,0xFF
    third element: 0x09,0x00,0x05,0x13,0x05,0x14,0x05,0x15,0x06,0x18,0x06,0x21,0x05,0xFF,0xFF
   .....etc... (different number of bytes in each "element").
   96 in total
};

And I need to be able to access any element at random and either read it byte by byte, or else keep reading until the 0xFF,0xFF marker is found (prefer to use the string length).

Or, should I just create each one separately:

    vector[0] = 0x10,0x00,0xFF,0xFF;
    vector[1] = 0x0A,0x00,0x05,0x13,0x05,0x14,0x05,0x15,0xFF,0xFF;
    vector[2] = 0x09,0x00,0x05,0x13,0x05,0x14,0x05,0x15,0x06,0x18,0x06,0x21,0x05,0xFF,0xFF;
...etc.....

This should be easy, but I am just not seeing it. Any help will be appreciated.

-- Roger

(edit to add): It all has to be in PROGMEM, by the way.....

You can't declare an array of arrays of different lengths. Instead of using an array of arrays, you need to use an array of pointers; each pointer would be initialised to point to an array holding your data values, which you have defined and initialised previously. If this lot is to be held in progmem then it's going to take considerable care (and trial and error) to make sure that you get the pointer dereferencing via progmem correct.

Here's a simple example to show the general idea, ignoring the progmem issue:

// uncompiled, untested
static const uint8_t alpha[] = { 0x10,0x00,0xFF,0xFF };
static const uint8_t beta[] = { 0x0A,0x00,0x05,0x13,0x05,0x14,0x05,0x15,0xFF,0xFF };
static const uint8_t gamma[] = { 0x09,0x00,0x05,0x13,0x05,0x14,0x05,0x15,0x06,0x18,0x06,0x21,0x05,0xFF,0xFF };
static const uint8_t *vectors[] = { alpha, beta, gamma };
// it probably needs a few more 'consts' in there too ...

PeterH:
You can't declare an array of arrays of different lengths. Instead of using an array of arrays, you need to use an array of pointers;

Yup. I see what you mean. No wonder I couldn't get it to work! :slight_smile:

Thanks!

--- Roger

PeterH:
You can't declare an array of arrays of different lengths. Instead of using an array of arrays, you need to use an array of pointers; each pointer would be initialised to point to an array holding your data values, which you have defined and initialised previously. If this lot is to be held in progmem then it's going to take considerable care (and trial and error) to make sure that you get the pointer dereferencing via progmem correct.

Here's a simple example to show the general idea, ignoring the progmem issue:

Got it to work:

static const uint8_t char20[] PROGMEM = {
	0x10,0x00,0xff,0xff
};
static const uint8_t char21[] PROGMEM = {
0x0a,0x00,0x05,0x1c,0x05,0x1b,0x05,0x1a,0x05,0x19,0x05,0x18,0x05,0x17,0x05,0x16,0x05,0x15,0x05,0x14,0x05,0x13,0x05,0x12,0x05,0x11,0x05,0x10,0x05,0x0f,0x05,0x0e,0x04,0x08,0x05,0x07,0x06,0x08,0x05,0x09,0xff,0xff
};
static const uint8_t char22[] PROGMEM = {
	0x10,0x00,0x04,0x1c,0x04,0x1b,0x04,0x1a,0x04,0x19,0x04,0x18,0x04,0x17,0x04,0x16,0x04,0x15,0x0c,0x1c,0x0c,0x1b,0x0c,0x1a,0x0c,0x19,0x0c,0x18,0x0c,0x17,0x0c,0x16,0x0c,0x15,0xff,0xff
};
/////////////// lots deleted in the middle /////////////
static const uint8_t char7e[] PROGMEM = {
0x18,0x00,0x03,0x0d,0x03,0x0e,0x04,0x12,0x05,0x12,0x06,0x13,0x07,0x13,0x08,0x13,0x09,0x13,0x0a,0x12,0x0b,0x11,0x0c,0x11,0x0d,0x10,0x0e,0x0f,0x0f,0x0f,0x10,0x0e,0x11,0x0e,0x12,0x0e,0x13,0x0e,0x14,0x10,0x03,0x0f,0x03,0x10,0x04,0x11,0x05,0x11,0x06,0x12,0x07,0x12,0x08,0x12,0x09,0x12,0x0a,0x11,0x0b,0x10,0x0c,0x10,0x0d,0x0f,0x0e,0x0e,0x0f,0x0e,0x10,0x0d,0x11,0x0d,0x12,0x0d,0x13,0x0d,0x14,0x0e,0x14,0x0f,0x15,0x10,0x15,0x11,0x15,0x12,0x15,0x13,0xff,0xff
};

static const uint8_t char7f[] PROGMEM = {
0x0e,0x00,0x05,0x1c,0x04,0x1b,0x04,0x1a,0x03,0x19,0x03,0x18,0x03,0x17,0x03,0x16,0x04,0x15,0x05,0x15,0x06,0x14,0x07,0x14,0x08,0x14,0x09,0x14,0x0a,0x15,0x0a,0x16,0x0b,0x17,0x0b,0x18,0x0b,0x19,0x0b,0x1a,0x0a,0x1b,0x09,0x1b,0x08,0x1c,0x07,0x1c,0x06,0x1c,0xff,0xff
};

// pointers to all the strings
static const uint8_t *table[] PROGMEM = {
	char20, char21, char22,	char23, char24, char25, char26, char27, char28, char29, char2a, char2b, char2c, char2d, char2e, char2f,
///////////// deleted for clarity ////////////
	char70, char71, char72,	char73, char74, char75, char76, char77, char78, char79, char7a, char7b, char7c, char7d, char7e, char7f
};

To access each set of data:

** **pgm_read_byte(pgm_read_word(&table[character_code]) + offset into string);** **

I need a PROGMEM read word to get a pointer to the particular string of data, then use PROGMEM read byte of the word address + offset to get it all.

I can't get a string length, so I have to just blindly grab data until I hit 0xFF.

Oh well, clumsy but it works.

Thanks for the idea! It helped me on the right path.

-- Roger

For reference, they're called Iliffe vectors.
Useful for odd-shaped arrays.

Hmmm, you guys seem to be making PROGMEM use really hard for yourselves. It can be far simpler, well in my opinion anyway.

I whipped up this and gave it a quick test on an uno:

struct A{
  
  char StrA[10];
  char StrB[15];
  char StrC[20];
  
} StrSet PROGMEM = {
  { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', '\0'},
  "0123456789abcd",
  { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', '\0'},
};

void setup(){ 
  char buffer[ 20 ];
  
  Serial.begin( 9600 );
  strcpy_P( buffer, StrSet.StrA );
  Serial.println( buffer );
  
  strcpy_P( buffer, StrSet.StrB );
  Serial.println( buffer );
  
  strcpy_P( buffer, StrSet.StrC );
  Serial.println( buffer );   
}

void loop(){ return; }

Hopefully it helps :slight_smile:

I can't get a string length, so I have to just blindly grab data until I hit 0xFF.
Oh well, clumsy but it works.

You could add an additional array holding the lengths... (are as PASCAL used to do, store the length in element [0]