Store 3-dimensional char array in program memory with PROGMEM I'm running a sketch whith a quite big, constant three dimensional char array (or simply, a table of strings). As this takes lots of RAM I'd like to store it in programm memory in order to keep the RAM free. This is the Sketch I'd like to run (my first idea):

const char *rules [16][5] PROGMEM ={ 
 {"1Lorem ipsum dolor sit amet, consetetur sadipscin0g elitr", "sed di7am nonumy 8eirmod tempor invidunt"},
 {"2Lorem ipsum dolor sit amet, consetetur sadipscing2 elitr", "sed diam nonumy 9eirmod tempo5r invidunt"},
 {"3Lorem ipsum dolor sit amet, consetetur sadipscing 4elitr", "sed0 diam nonumy 1eirmod tempor invidunt"},
 {"4Lorem ipsum dolor sit amet, consetetur sadips3cing elitr", "sed diam nonumy 2eirmod tempor in5vidunt"},
 {"5Lorem ipsum dolor sit amet, consetetur 3sadipscing elitr", "sed 7diam nonumy 3eirmod tempor invidunt"},
 {"6Lorem ipsum dolor sit amet, conset9etur sadipscing elitr", "sed diam n8onumy 4eirmod tempor invidunt"},
 {"7Lorem ipsum dolor sit amet, consetetur sadipsc3ing elitr", "sed diam nonumy 5eirmod tempor inv4idunt"},
};

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(115200);
  for(int i = 0; i &lt; 16; i++){
    for(int j = 0; j &lt; 5; j++){
     Serial.println(rules[i][j]); 
    }
  }
}

void loop() {
}


But this fails with the following error:

variable 'rules' must be const in order to be put into read-only section by means of '__attribute__((progmem))'


According to Arduino's FAQ this can be solved by changing the array's declaration to

const char * const rules [16][5] PROGMEM ={


The sketch compiles now without errors, but the global variables (here only the array) still need lots of RAM:

Sketch uses 2484 bytes (7%) of program storage space. Maximum is 32256 bytes.
Global variables use 880 bytes (42%) of dynamic memory, leaving 1168 bytes for local variables. Maximum is 2048 bytes.


I'm not sure what causes this, but is it possible that only the pointers to the strings are stored in program memory, while the strings theirselves are still copied to RAM?

How do I put the whole arary in programm memory?

There has already been a question like this on StackOverflow, but the answer recommends using prog_chars, which are according to the AVR documentation deprecated.
Here you have:

const char * const rules [16][5] PROGMEM ={ 


One const refers to the char* part. It means the pointer value doesn't change.

The other const refers to what it is pointed by. It means the thing this pointer points doesn't change (but the pointer itself can change).

In your sketch the thing that get put into PROGMEM is the pointer array; the texts themselves are still in RAM. Have a look at PROGMEM page and  study this example:

const char string_0[] PROGMEM = "String 0";   // "String 0" etc are strings to store - change to suit.
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";


// Then set up a table to refer to your strings.

const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};


You need to declare each string by itself, and later put them in an array.

As you can see, pointer are inescapable.

Edit: The F() Macro

Here is a proof of concept of how to manage an array of string (lowercase "s") and strings constants in PROGMEM:

const char uno[] PROGMEM = "1Lorem ipsum dolor sit amet, consetetur sadipscin0g elitr";
const char dos[] PROGMEM = "2Lorem ipsum dolor sit amet, consetetur sadipscin0g elitr";
const char tre[] PROGMEM = "3Lorem ipsum dolor sit amet, consetetur sadipscin0g elitr";
const char cua[] PROGMEM = "4Lorem ipsum dolor sit amet, consetetur sadipscin0g elitr";
const char cin[] PROGMEM = "5Lorem ipsum dolor sit amet, consetetur sadipscin0g elitr";

const char * const rules [3][2] = { 
 {uno, dos},
 {tre, cua},
 {cua, cin}
};

void setup() {
  Serial.begin(115200);
  Serial.println(F("PROGMEM string test"));
  Serial.println(F("-------------------"));
  for(int i = 0; i &lt; 3; i++){
    for(int j = 0; j &lt; 2; j++){
      Serial.print(i); Serial.print(" "); Serial.print(j); Serial.print(" ");
     Serial.println((const __FlashStringHelper *) rules[i][j]); 
    }
  }
}

void loop() {
}


Use the F() macro to put constant strings in PROGMEM. Otherwise, the strings will live in RAM. Are running short of RAM? Put the F() macro around those pesky strings and send them out of your RAM.