YA question about copying pointers to arrays of arrays

I am trying to copy an pointer to an array of arrays so I can pass it to other functions (as I understand it you can't pass an array of arrays directly to a function, but you can "flatten" it to one dimension first.)

The original data structure is a XPM bitmap, it looks like this:

/* XPM */
static char * numbers72x46_0_xpm[] = {
"46 72 2 1",
"   c #000000",
".  c #FFFFFF",
"..............................................",
"..............................................",
// 70 more lines like that
};

Just for starters, I am trying to make sense of how the array looks I'm memory by doing this:

void setup () {     
    char * xpm;
    char b = 'X';
    int i;
    Serial.begin(19200);

    Serial.println(numbers72x46_0_xpm[0]);
    Serial.println(numbers72x46_0_xpm[1]);
    Serial.println(numbers72x46_0_xpm[2]);
    Serial.println(numbers72x46_0_xpm[3]);
    Serial.println(numbers72x46_0_xpm[4]);
    Serial.println();
    // As I understand it this assignment should copy the pointer
    // to numbers72x46_0_xpm to xpm, yielding a pointer to a one
    // dimensional array
    xpm = * numbers72x46_0_xpm;
    
    // Why is xpm not a pointer to a one dimensional buffer with all
    // of numbers72x46_0_xpm as a 1-dimensional array?
    for (int i=0; i<200; i++) {
    if (xpm[i] == '\0') {
        Serial.println("<NUL>");
    } else {
        Serial.print(xpm[i]);
    }
    }

}

So, the first five line that have static array indexes print fine, then, in the loop, the first four lines are what I expect, but after that, garbage.

46 72 2 1
 c #000000
. c #FFFFFF
..............................................
..............................................

46 72 2 1<NUL>
 c #000000<NUL>
. c #FFFFFF<NUL>
..............................................<NUL>
<NUL><NUL>
^<NUL>
<NUL>
<NUL>
...

I have not allocated any memory to rpm because, as I understand it, I am copying a pointer to what I think is all of numbers72x46_0_xpm to "xpm" so I don't need to. Is that completely wrong? I seems to be only a pointer to numbers72x46_0_xpm[0].

If I try to

   xpm = numbers72x46_0_xpm;

I get an error

cannot convert 'char* [75]' to 'char*' in assignment

.

Is there no way to do this except to allocate a buffer for "xpm" and them copy the XPM data to it?

I've searched all over and found plenty of examples for passing 1-dimensional arrays by reference, but not two-dimensional ones.

Thanks
w

Here you go:
https://www.google.com/search?q=pass+two+dimensional+array+to+function+c

None of those answers are any good, you have to globally declare the size of the array. Specifically, passing variable sized arrays in a fucntion declaration seems to result in an error:

...
void theneedful(int sz, const char * xpm[sz]) {
....
hrttest.cpp:8:38: error: expected ‘,’ or ‘...’ before ‘xpm’
    8 | void theneedful(int sz, const char * xpm[sz]) {

What I have come up with so far is the apability to copy arrays of pointers, at east inside main(). The XPM data is global, so I should be able to make some progress without needing to pass the entire 2D array in a function:

#include "numbers72x46-0.h"
#include <cstdio>

int main () {
    // Number of elements in xpm
    int sz = sizeof(numbers72x46_0_xpm)/8;
    // didn't know until now that this would work ...
    const char *xpm[sz];
    int i;
    printf("S %i\n",sz);
    printf("SIZEOF numbers72x46_0_xpm %i\n",sizeof(numbers72x46_0_xpm));
    printf("SIZEOF xpm %i\n",sizeof(xpm));

    for (i=0; i<sz; i++) {
        xpm[i] = numbers72x46_0_xpm[i];
        printf("%s\n", xpm[i]);
        // prints a good copy of numbers72x46_0_xpm
    }
}

It's sort of sleazy in that is assumes the size of a pointer is 8, but I know I can get that number from somewhere if the assumption breaks.

Going to withdraw my question. I need to put all this data in PROGMEM since the XPM (font pixmaps) are large, and I guess arrays of arrays in PROGMEM need special consideration since, obviously, a pointer can't point there:

/* XPM */
const unsigned char * numbers72x46_0_xpm[] PROGMEM = {
"46 72 2 1",
" c #000000",
". c #FFFFFF",
"..............................................",
"..............................................",

results in

Arduino: 1.8.12 (Mac OS X), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"

In file included from /Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/Arduino.h:28:0,
                 from sketch/hrttest.ino.cpp:1:
numbers72x46-0.h:2:44: error: variable 'numbers72x46_0_xpm' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
 const unsigned char * numbers72x46_0_xpm[] PROGMEM = {
...

I was thinking I could take a generic approach to stuff the arrays of arrays into progmem, but it looks like massaging the data into fixed sized arrays will be more convenient, and result in a lot less obtuse code.

It's sort of sleazy in that is assumes the size of a pointer is 8, but I know I can get that number from somewhere if the assumption breaks

You could get it from here:

    int sz = sizeof(numbers72x46_0_xpm)/sizeof(numbers72x46_0_xpm[0]);

wsanders:
I guess arrays of arrays in PROGMEM need special consideration since, obviously, a pointer can't point there

Yes and nonsense, respectively.

What is a little inconvenient get is getting a 2-D jagged array of char into PROGMEM. You can't do it in a single step (as far as I know) like you can in RAM. It's a two-step process. And, it's usually not worth the trouble to put the pointer array in PROGMEM, just the characters:

constexpr char string00[] PROGMEM = "46 72 2 1";
constexpr char string01[] PROGMEM = " c #000000";
constexpr char string02[] PROGMEM = ". c #FFFFFF";
constexpr char string03[] PROGMEM = "..............................................";
constexpr char string04[] PROGMEM = "..............................................";

const char * const numbers72x46_0_xpm[] = {string00, string01, string02, string03, string04};
constexpr size_t numPointers = sizeof(numbers72x46_0_xpm) / sizeof(numbers72x46_0_xpm[0]);

void setup() {
  Serial.begin(115200);
  delay(1000);
  for (size_t i = 0; i < numPointers; i++) {
    Serial.println((const __FlashStringHelper *) numbers72x46_0_xpm[i]);
  }
}

void loop() {
}

However, if you insist, you can put the pointer array in PROGMEM too:

constexpr char string00[] PROGMEM = "46 72 2 1";
constexpr char string01[] PROGMEM = " c #000000";
constexpr char string02[] PROGMEM = ". c #FFFFFF";
constexpr char string03[] PROGMEM = "..............................................";
constexpr char string04[] PROGMEM = "..............................................";

const char * const numbers72x46_0_xpm[] PROGMEM = {string00, string01, string02, string03, string04};
constexpr size_t numPointers = sizeof(numbers72x46_0_xpm) / sizeof(numbers72x46_0_xpm[0]);

void setup() {
  const __FlashStringHelper *ptr;
  Serial.begin(115200);
  delay(1000);
  for (size_t i = 0; i < numPointers; i++) {
    memcpy_P(&ptr, numbers72x46_0_xpm + i, sizeof(ptr));
    Serial.println(ptr);
  }
}

void loop() {
}

If you can live with the wasted space of a rectangular array (rather than jagged), it's a little easier:

constexpr char numbers72x46_0_xpm[][50] PROGMEM = {
  "46 72 2 1",
  " c #000000",
  ". c #FFFFFF",
  "..............................................",
  ".............................................."
};

constexpr size_t numPointers = sizeof(numbers72x46_0_xpm) / sizeof(numbers72x46_0_xpm[0]);

void setup() {
  Serial.begin(115200);
  delay(1000);
  for (size_t i = 0; i < numPointers; i++) {
    Serial.println((const __FlashStringHelper *) numbers72x46_0_xpm[i]);
  }
}

void loop() {
}

Thanks for the reply. I ended up just massaging the data into rectangular arrays of a fixed size (char[NN][NN} and reading it back out with prog_read_byte and regular old pointer arithmetic. These arrays are bitmaps for drawing big fonts on one of the old abysmally slow TFT touch shields. It would be easier to not use progmem, but the bitmaps take up 50K and won't fit in RAM.

const char numbers72x46_0_xpm[72][46] PROGMEM = {
  "..............................................",
...