freeMemory() and memory leak...

I’ve test the program with valgrind, and it gives me 0 memory leak…

running on arduino some thing doesn’t seems right…

#include <stdlib.h>
#include <string.h>

#include <WProgram.h>
#include <WConstants.h>

#include <MemoryFree.h>

#include <Wire.h>
#include <WireFacilities.h>

#define LANGUAGE_EEPROM_ADDRESS 80

#define DATA_DONE 14

#define POS_SETUP_DONE 0
#define POS_LANGUAGE_UPLOAD 1
//position array
#define POS_SOCKET_TYPE 1
#define POS_SOCKET_TIMED_TYPE 2
#define POS_SOCKET_PROBED_TYPE 3
#define POS_MEMORY_OPTIONS 4
#define POS_MENU_OPTIONS 5
#define POS_CONTROL_SOCKET 6
#define POS_MANUAL_SET 7
#define POS_DURATION 8
#define POS_CHANGE_SOCKET_OPTIONS 9
#define POS_PROBE_OPTIONS 10
#define POS_SOCKET_OPTIONS 11
#define POS_SETUP_OPTIONS 12
#define POS_SHORT_DAY_OF_WEEK 13
#define POS_DAY_OF_WEEK 14


#define POS_FOR_DATA 92


const char *socketType[] = {"TEMPORIZZATA", "ACCESA", "SPENTA", "SONDATA", NULL};

const char *socketTimedType[] = {"LUCE", "POMPA", "FILTRO", "RISCALDATORE", "RISALITA", "SKIMMER", "VENTOLE", "REFRIGERATORE", "MANGIATOIA", "LUCE LUNARE", "REATTORE", "KALKWASSER", "ELETTROV. REATTORE", "ELETTROV. VASCA", "RABBOCCO VASCA", "RABBOCCO SUMP", "VENT. MOBILE", "LUCE MOBILE", "VENTOLE PLAFO", "ALTRO", "SPENTA", NULL};

const char *socketProbedType[] = {"RISCALDATORE SONDATO", "ELETTR. REATTORE SONDATA", "ELETTR. VASCA SONDATA", "RABB. VASCA SONDATO", "RABB. SUMP SONDATO", "REFRIG. SONDATO", "VENTOLE SONDATE", "LUCE LUNARE SONDATA", "ORP SONDATO", "VENTOLE PLAFO SONDATE", NULL};

const char *memoryOptions[] = {"NON FORMATTARE", "FORMATTA", "ANNULLA", NULL};

const char *menuOptions[] = {"PAUSA PASTO", "PAUSA CAMBIO", "ACCENDI LUCE MOBILE", "ACCENDI LUCI", "AUTO-MANUALE", "GESTIONE SONDE", "GESTIONE PRESE", "IMPOSTAZIONI", "ESCI", NULL};

const char *controlSocket[] = {"AUTO", "MANUALE", "IGNORA", NULL};

const char *manualSet[] = {"ACCESO", "SPENTO", NULL};

const char *duration[] = {"FINO A", "PER", NULL};

const char *changeSocketOptions[] = {"MODIFICA", "IGNORA", NULL};

const char *probeOptions[] = {"MODIFICA SONDE", "REGOLA SONDE", "ANNULLA", NULL};

const char *socketOptions[] = {"INFO. PRESE", "MODIFICA PRESE", "ANNULLA", NULL};

const char *setupOptions[] = {"NUOVO PROGRAMMA", "DATA & ORA", "ANNULLA", NULL};

const char *shortDayOfWeek[] = {"LUN", "MAR", "MER", "GIO", "VEN", "SAB", "DOM", NULL};

const char *dayOfWeek[] = {"LUNEDI'", "MARTEDI'", "MERCOLEDI'", "GIOVEDI'", "VENERDI'", "SABATO", "DOMENICA", NULL};


const char *startingString = "INIZIO CARICAMENTO DATI";
const char *endingString = "FINE CARICAMENTO DATI";
const char *sizeUsed = "SONO STATI USATI ";


/* --------------- DO NOT MODIFIE ---------------------- */

char **list = NULL;
char str[17];


void freeArr(){
  byte j = 0;
  if(list){
    for(; list[j]; j++){
      free(list[j]);
      list[j] = NULL;
    }
    free(list);
    list = NULL;
  Serial.print("Array deleted: free mem = ");
  Serial.println(freeMemory());
  }
}

int printArr(){
  int i = 0;
  while(list[i])
    Serial.println((char *) list[i++]);
}

int writeString(const char *s, int startPosition, byte maxSize = 15){
	byte j = 0;
	int pos = startPosition;
	while(j < maxSize && s[j])
		eepromWriteData(LANGUAGE_EEPROM_ADDRESS, pos++, s[j++]);
	eepromWriteData(LANGUAGE_EEPROM_ADDRESS, pos++, '\0');
	return pos - startPosition;
}

int writeArr(const char *arr[], int startPosition){
  byte i = 0;
  int pos = startPosition + 1; //lascio uno spazio per scrivere la lunghezza dell'array (come numero di stringhe)
  for(; arr[i]; i++)
	  pos += writeString(arr[i], pos);

  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, startPosition, i);
  delay(5);
  Serial.print("\t\t:");
  Serial.print(pos - startPosition - 1);
  Serial.print(", are really: ");
  return pos;
}

void writeAddress(int pos, int address){
  pos = 2 * pos;
  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, pos, (byte) (address >> 8));
  delay(5);
  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, pos + 1, (byte) (address));
  delay(5);
}

int arrStrlen(const char *arr[]){
  int len = 0, i = 0;
  while(arr[i])
    len += strlen(arr[i++]) + 1;
  Serial.println(len);
  return len;
}

int calculateAddress(byte position){
	int pos = 2 * position;
	return ((eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos) << 8) | eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos + 1));
}

int loadString(int address, bool isAddress = false){
	int pos = isAddress ? address: calculateAddress(address);
	for(byte j = 0; (str[j] = eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos++)); j++)
		;
	return pos - address; // counts even '\0'
}

void loadArr(byte address){
  int pos = 0;
  byte i = 0, n = 0;
  
  Serial.print("before load array free mem = ");
  Serial.println(freeMemory()); 
  
  pos = calculateAddress(address);
  n = eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos++);  
  list = (char **) calloc(n + 1, sizeof(char *)); // n + 1 because I want list[n] = NULL (made by calloc)
  for(; i < n; i++){
    pos += loadString(pos, true);
    list[i] = strdup(str);
  }
  Serial.print("Array loaded(");
  Serial.print((int) address);
  Serial.print("): free mem = ");
  Serial.println(freeMemory());
}


void setup(){
  int pos = POS_FOR_DATA; 
  Serial.begin(9600);
  Wire.begin();
  Serial.println(startingString);
  Serial.print("free mem = ");
  Serial.println(freeMemory());
  
  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, POS_LANGUAGE_UPLOAD, DATA_DONE);
  delay(5);

  writeAddress(POS_SOCKET_TYPE, pos);
  pos = writeArr(socketType, pos) + 1;
  arrStrlen(socketType);
  
  writeAddress(POS_SOCKET_TIMED_TYPE, pos);
  pos = writeArr(socketTimedType, pos) + 1;
  arrStrlen(socketTimedType);
  
  writeAddress(POS_SOCKET_PROBED_TYPE, pos);
  pos = writeArr(socketProbedType, pos) + 1;
  arrStrlen(socketProbedType);
  
  writeAddress(POS_MEMORY_OPTIONS, pos);
  pos = writeArr(memoryOptions, pos) + 1;
  arrStrlen(memoryOptions);
  
  writeAddress(POS_MENU_OPTIONS, pos);
  pos = writeArr(menuOptions, pos) + 1;
  arrStrlen(menuOptions);
  
  writeAddress(POS_CONTROL_SOCKET, pos);
  pos = writeArr(controlSocket, pos) + 1;
  arrStrlen(controlSocket);
  
  writeAddress(POS_MANUAL_SET, pos);
  pos = writeArr(manualSet, pos) + 1;
  arrStrlen(manualSet);
  
  writeAddress(POS_DURATION, pos);
  pos = writeArr(duration, pos) + 1;
  arrStrlen(duration);
  
  writeAddress(POS_CHANGE_SOCKET_OPTIONS, pos);
  pos = writeArr(changeSocketOptions, pos) + 1;
  arrStrlen(changeSocketOptions);
  
  writeAddress(POS_PROBE_OPTIONS, pos);
  pos = writeArr(probeOptions, pos) + 1;
  arrStrlen(probeOptions);
  
  writeAddress(POS_SOCKET_OPTIONS, pos);
  pos = writeArr(socketOptions, pos) + 1;
  arrStrlen(socketOptions);
  
  writeAddress(POS_SETUP_OPTIONS, pos);
  pos = writeArr(setupOptions, pos) + 1;
  arrStrlen(setupOptions);
  
  writeAddress(POS_SHORT_DAY_OF_WEEK, pos);
  pos = writeArr(shortDayOfWeek, pos) + 1;
  arrStrlen(shortDayOfWeek);
  
  writeAddress(POS_DAY_OF_WEEK, pos);
  pos = writeArr(dayOfWeek, pos) + 1;
  arrStrlen(dayOfWeek);
 
  Serial.println(endingString);
  Serial.print(sizeUsed);
  Serial.print(pos);
  Serial.println(" bytes");
  
  Serial.println("Ora ricarico i dati\n");

  loadArr(POS_SOCKET_TYPE);
  printArr();
  freeArr();
  
  loadArr(POS_SOCKET_TIMED_TYPE); 
  printArr();
  freeArr();  
  
  loadArr(POS_SOCKET_PROBED_TYPE);
  printArr();
  freeArr();
     
  loadArr(POS_MEMORY_OPTIONS);
  printArr();
  freeArr();
   
  loadArr(POS_MENU_OPTIONS);
  printArr();
  freeArr(); 
  
  loadArr(POS_CONTROL_SOCKET);
  printArr();
  freeArr();
   
  loadArr(POS_MANUAL_SET);
  printArr();
  freeArr();
   
  loadArr(POS_DURATION);
  printArr();
  freeArr();
   
  loadArr(POS_CHANGE_SOCKET_OPTIONS);
  printArr();
  freeArr();
   
  loadArr(POS_PROBE_OPTIONS);
  printArr();
  freeArr();
  
  loadArr(POS_SOCKET_OPTIONS);
  printArr();
  freeArr();
    
  loadArr(POS_SETUP_OPTIONS);
  printArr();
  freeArr();
    
  loadArr(POS_SHORT_DAY_OF_WEEK);
  printArr();
  freeArr();
    
  loadArr(POS_DAY_OF_WEEK);
  printArr();
  freeArr();
}

void loop(){
  
}

output: (freeMemory gives different value before/after load and free the array...)

INIZIO CARICAMENTO DATI
free mem = 396
        :35, are really: 35
        :226, are really: 229
        :156, are really: 193
        :32, are really: 32
        :115, are really: 119
        :20, are really: 20
        :14, are really: 14
        :11, are really: 11
        :16, are really: 16
        :36, are really: 36
        :35, are really: 35
        :35, are really: 35
        :28, are really: 28
        :62, are really: 62
FINE CARICAMENTO DATI
SONO STATI USATI 941 bytes
Ora ricarico i dati

before load array free mem = 385
Array loaded(1): free mem = 330
TEMPORIZZATA
ACCESA
SPENTA
SONDATA
Array deleted: free mem = 336
before load array free mem = 330
Array loaded(2): free mem = 69
LUCE
POMPA
FILTRO
RISCALDATORE
RISALITA
SKIMMER
VENTOLE
REFRIGERATORE
MANGIATOIA
LUCE LUNARE
REATTORE
KALKWASSER
ELETTROV. REATT
ELETTROV. VASCA
RABBOCCO VASCA
RABBOCCO SUMP
VENT. MOBILE
LUCE MOBILE
VENTOLE PLAFO
A

Array deleted: free mem = 75
before load array free mem = 69
Array loaded(3): free mem = 69
RISCALDATORE SO
ELETTR. REATTOR
ELETTR. VASCA S
RABB. VASCA SON
RABB. SUMP SOND

so... what's the problem?

That’s a lot of string you’ve got there - have you thought about using PROGMEM for them?

I don't remember if i've posted the code using progmem.. But I don't think that the problem is due to using progmem or not.. My target is to save on eeprom some string, then load them in a char *[]. Use the array and then delete it... Of course without memory leak...

My target is to save on eeprom some string, then load them in a char *[]. Use

But all those strings start in RAM

i've posted the wrong code...

however, changes little... even if the strings were in the ram the program works... the problem is that freeMemory() gave different results before loading the array and after free... and that's what I was interested... and should be independent if the strings were PROGMEM or not... I could upload the string, and I did not go in a stack overflow... only freeMemory() detects a decrease in free space... as if something wasn't deallocated... Instead valgrind said that I do not let memory leak... and the code is the same ...

void setup(){
  int pos = POS_FOR_DATA; 
  Serial.begin(9600);
  Wire.begin();
  Serial.println(startingString);
  Serial.print("free memory = ");
  Serial.println(freeMemory());
  
  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, POS_LANGUAGE_UPLOAD, DATA_DONE);
  delay(5);

  writeAddress(POS_SOCKET_TYPE, pos);
  pos = writeArr(socketType, pos) + 1;
  arrStrlen(socketType);
  
  writeAddress(POS_SOCKET_TIMED_TYPE, pos);
  pos = writeArr(socketTimedType, pos) + 1;
  arrStrlen(socketTimedType);
  
  writeAddress(POS_SOCKET_PROBED_TYPE, pos);
  pos = writeArr(socketProbedType, pos) + 1;
  arrStrlen(socketProbedType);
  
  writeAddress(POS_MEMORY_OPTIONS, pos);
  pos = writeArr(memoryOptions, pos) + 1;
  arrStrlen(memoryOptions);
  
  writeAddress(POS_MENU_OPTIONS, pos);
  pos = writeArr(menuOptions, pos) + 1;
  arrStrlen(menuOptions);
  
  writeAddress(POS_CONTROL_SOCKET, pos);
  pos = writeArr(controlSocket, pos) + 1;
  arrStrlen(controlSocket);
  
  writeAddress(POS_MANUAL_SET, pos);
  pos = writeArr(manualSet, pos) + 1;
  arrStrlen(manualSet);
  
  writeAddress(POS_DURATION, pos);
  pos = writeArr(duration, pos) + 1;
  arrStrlen(duration);
  
  writeAddress(POS_CHANGE_SOCKET_OPTIONS, pos);
  pos = writeArr(changeSocketOptions, pos) + 1;
  arrStrlen(changeSocketOptions);
  
  writeAddress(POS_PROBE_OPTIONS, pos);
  pos = writeArr(probeOptions, pos) + 1;
  arrStrlen(probeOptions);
  
  writeAddress(POS_SOCKET_OPTIONS, pos);
  pos = writeArr(socketOptions, pos) + 1;
  arrStrlen(socketOptions);
  
  writeAddress(POS_SETUP_OPTIONS, pos);
  pos = writeArr(setupOptions, pos) + 1;
  arrStrlen(setupOptions);
  
  writeAddress(POS_SHORT_DAY_OF_WEEK, pos);
  pos = writeArr(shortDayOfWeek, pos) + 1;
  arrStrlen(shortDayOfWeek);
  
  writeAddress(POS_DAY_OF_WEEK, pos);
  pos = writeArr(dayOfWeek, pos) + 1;
  arrStrlen(dayOfWeek);

  Serial.println(endingString);
  Serial.print(sizeUsed);
  Serial.print(pos);
  Serial.println(" bytes");
  
  Serial.println("Ora ricarico i dati\n");

  loadArr(POS_SOCKET_TYPE);
  printArr();
  freeArr();
  
  loadArr(POS_SOCKET_TIMED_TYPE); 
  printArr();
  freeArr();  
  
  loadArr(POS_SOCKET_PROBED_TYPE);
  printArr();
  freeArr();
     
  loadArr(POS_MEMORY_OPTIONS);
  printArr();
  freeArr();
   
  loadArr(POS_MENU_OPTIONS);
  printArr();
  freeArr(); 
  
  loadArr(POS_CONTROL_SOCKET);
  printArr();
  freeArr();
   
  loadArr(POS_MANUAL_SET);
  printArr();
  freeArr();
   
  loadArr(POS_DURATION);
  printArr();
  freeArr();
   
  loadArr(POS_CHANGE_SOCKET_OPTIONS);
  printArr();
  freeArr();
   
  loadArr(POS_PROBE_OPTIONS);
  printArr();
  freeArr();
  
  loadArr(POS_SOCKET_OPTIONS);
  printArr();
  freeArr();
    
  loadArr(POS_SETUP_OPTIONS);
  printArr();
  freeArr();
    
  loadArr(POS_SHORT_DAY_OF_WEEK);
  printArr();
  freeArr();
    
  loadArr(POS_DAY_OF_WEEK);
  printArr();
  freeArr(); 
}

void loop(){
  
}

(continue)

#include <stdlib.h>
#include <string.h>

#include <avr/pgmspace.h>

#include <WProgram.h>
#include <WConstants.h>

#include <MemoryFree.h>

#include <Wire.h>
#include <WireFacilities.h>

#define LANGUAGE_EEPROM_ADDRESS 80

#define DATA_DONE 14

#define POS_SETUP_DONE 0
#define POS_LANGUAGE_UPLOAD 1
//position array
#define POS_SOCKET_TYPE 1
#define POS_SOCKET_TIMED_TYPE 2
#define POS_SOCKET_PROBED_TYPE 3
#define POS_MEMORY_OPTIONS 4
#define POS_MENU_OPTIONS 5
#define POS_CONTROL_SOCKET 6
#define POS_MANUAL_SET 7
#define POS_DURATION 8
#define POS_CHANGE_SOCKET_OPTIONS 9
#define POS_PROBE_OPTIONS 10
#define POS_SOCKET_OPTIONS 11
#define POS_SETUP_OPTIONS 12
#define POS_SHORT_DAY_OF_WEEK 13
#define POS_DAY_OF_WEEK 14

#define POS_FOR_DATA 92


prog_char str0[] PROGMEM = "TEMPORIZZATA";
prog_char str1[] PROGMEM = "ACCESA";
prog_char str2[] PROGMEM = "SPENTA";
prog_char str3[] PROGMEM = "SONDATA";

prog_char str4[] PROGMEM = "LUCE";
prog_char str5[] PROGMEM = "POMPA";
prog_char str6[] PROGMEM = "FILTRO";
prog_char str7[] PROGMEM = "RISCALDATORE";
prog_char str8[] PROGMEM = "RISALITA";
prog_char str9[] PROGMEM = "SKIMMER";
prog_char str10[] PROGMEM = "VENTOLE";
prog_char str11[] PROGMEM = "REFRIGERATORE";
prog_char str12[] PROGMEM = "MANGIATOIA";
prog_char str13[] PROGMEM = "LUCE LUNARE";
prog_char str14[] PROGMEM = "REATTORE";
prog_char str15[] PROGMEM = "KALKWASSER";
prog_char str16[] PROGMEM = "ELETTROV. REATTORE";
prog_char str17[] PROGMEM = "ELETTROV. VASCA";
prog_char str18[] PROGMEM = "RABBOCCO VASCA";
prog_char str19[] PROGMEM = "RABBOCCO SUMP";
prog_char str20[] PROGMEM = "VENT. MOBILE";
prog_char str21[] PROGMEM = "LUCE MOBILE";
prog_char str22[] PROGMEM = "VENTOLE PLAFO";
prog_char str23[] PROGMEM = "ALTRO";
prog_char str24[] PROGMEM = "SPENTA";

prog_char str25[] PROGMEM = "RISCALDATORE SONDATO";
prog_char str26[] PROGMEM = "ELETTR. REATTORE SONDATA";
prog_char str27[] PROGMEM = "ELETTR. VASCA SONDATA";
prog_char str28[] PROGMEM = "RABB. VASCA SONDATO";
prog_char str29[] PROGMEM = "RABB. SUMP SONDATO";
prog_char str30[] PROGMEM = "REFRIG. SONDATO";
prog_char str31[] PROGMEM = "VENTOLE SONDATE";
prog_char str32[] PROGMEM = "LUCE LUNARE SONDATA";
prog_char str33[] PROGMEM = "ORP SONDATO";
prog_char str34[] PROGMEM = "VENTOLE PLAFO SONDATE";

prog_char str35[] PROGMEM = "NON FORMATTARE";
prog_char str36[] PROGMEM = "FORMATTA";
prog_char str37[] PROGMEM = "ANNULLA";

prog_char str38[] PROGMEM = "PAUSA PASTO";
prog_char str39[] PROGMEM = "PAUSA CAMBIO";
prog_char str40[] PROGMEM = "ACCENDI LUCE MOBILE";
prog_char str41[] PROGMEM = "ACCENDI LUCI";
prog_char str42[] PROGMEM = "AUTO-MANUALE";
prog_char str43[] PROGMEM = "GESTIONE SONDE";
prog_char str44[] PROGMEM = "GESTIONE PRESE";
prog_char str45[] PROGMEM = "IMPOSTAZIONI";
prog_char str46[] PROGMEM = "ESCI";

prog_char str47[] PROGMEM = "AUTO";
prog_char str48[] PROGMEM = "MANUALE";
prog_char str49[] PROGMEM = "IGNORA";

prog_char str50[] PROGMEM = "ACCESO";
prog_char str51[] PROGMEM = "SPENTO";

prog_char str52[] PROGMEM = "FINO A";
prog_char str53[] PROGMEM = "PER";

prog_char str54[] PROGMEM = "MODIFICA";
prog_char str55[] PROGMEM = "IGNORA";

prog_char str56[] PROGMEM = "MODIFICA SONDE";
prog_char str57[] PROGMEM = "REGOLA SONDE";
prog_char str58[] PROGMEM = "ANNULLA";

prog_char str59[] PROGMEM = "INFO. PRESE";
prog_char str60[] PROGMEM = "MODIFICA PRESE";
prog_char str61[] PROGMEM = "ANNULLA";

prog_char str62[] PROGMEM = "NUOVO PROGRAMMA";
prog_char str63[] PROGMEM = "DATA & ORA";
prog_char str64[] PROGMEM = "ANNULLA";

prog_char str65[] PROGMEM = "LUN";
prog_char str66[] PROGMEM = "MAR";
prog_char str67[] PROGMEM = "MER";
prog_char str68[] PROGMEM = "GIO";
prog_char str69[] PROGMEM = "VEN";
prog_char str70[] PROGMEM = "SAB";
prog_char str71[] PROGMEM = "DOM";

prog_char str72[] PROGMEM = "LUNEDI'";
prog_char str73[] PROGMEM = "MARTEDI'";
prog_char str74[] PROGMEM = "MERCOLEDI'";
prog_char str75[] PROGMEM = "GIOVEDI'";
prog_char str76[] PROGMEM = "VENERDI'";
prog_char str77[] PROGMEM = "SABATO";
prog_char str78[] PROGMEM = "DOMENICA";


const char *startingString = "INIZIO CARICAMENTO DATI";
const char *endingString = "FINE CARICAMENTO DATI";
const char *sizeUsed = "SONO STATI USATI ";



PROGMEM const char *socketType[] = {
	str0,
	str1,
	str2,
	str3,
	NULL
};

PROGMEM const char *socketTimedType[] = {
	str4,
	str5,
	str6,
	str7,
	str8,
	str9,
	str10,
	str11,
	str12,
	str13,
	str14,
	str15,
	str16,
	str17,
	str18,
	str19,
	str20,
	str21,
	str22,
	str23,
	str24,
	NULL
};

PROGMEM const char *socketProbedType[] = {
	str25,
	str26,
	str27,
	str28,
	str29,
	str30,
	str31,
	str32,
	str33,
	str34,
	NULL
};

PROGMEM const char *memoryOptions[] = {
	str35,
	str36,
	str37,
	NULL
};

PROGMEM const char *menuOptions[] = {
	str38,
	str39,
	str40,
	str41,
	str42,
	str43,
	str44,
	str45,
	str46,
	NULL
};

PROGMEM const char *controlSocket[] = {
	str47,
	str48,
	str49,
	NULL
};

PROGMEM const char *manualSet[] = {
	str50,
	str51,
	NULL
};

PROGMEM const char *duration[] = {
	str52,
	str53,
	NULL
};

PROGMEM const char *changeSocketOptions[] = {
	str54,
	str55,
	NULL
};

PROGMEM const char *probeOptions[] = {
	str56,
	str57,
	str58,
	NULL
};

PROGMEM const char *socketOptions[] = {
	str59,
	str60,
	str61,
	NULL
};

PROGMEM const char *setupOptions[] = {
	str62,
	str63,
	str64,
	NULL
};

PROGMEM const char *shortDayOfWeek[] = {
	str65,
	str66,
	str67,
	str68,
	str69,
	str70,
	str71,
	NULL
};

PROGMEM const char *dayOfWeek[] = {
	str72,
	str73,
	str74,
	str75,
	str76,
	str77,
	str78,
	NULL
};


/* --------------- DO NOT MODIFIE ---------------------- */

char **list = NULL;
char str[17];


void freeArr(){
  byte j = 0;
  if(list){
    for(; list[j]; j++){
      free(list[j]);
      list[j] = NULL;
    }
    free(list);
    list = NULL;
  Serial.print("Array cancellato: memoria libera = ");
  Serial.println(freeMemory());
  }
}

int printArr(){
  int i = 0;
  while(list[i])
    Serial.println(list[i++]);
}

int writeString(const char *s, int startPosition, byte maxSize = 16){
  byte j = 0;
  int pos = startPosition;
  while(j < maxSize && s[j])
    eepromWriteData(LANGUAGE_EEPROM_ADDRESS, pos++, s[j++]);
  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, pos++, '\0');
  return pos - startPosition;
}

int writeArr(PROGMEM const char *arr[], int startPosition){
  byte i = 0;
  int pos = startPosition + 1; //lascio uno spazio per scrivere la lunghezza dell'array (come numero di stringhe)
  char buffer[100];
  for(; (char*) pgm_read_word(&(arr[i])); i++){
    strcpy_P(buffer, (char*) pgm_read_word(&(arr[i])));
    pos += writeString(buffer, pos, 15);
  }
  
  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, startPosition, i);
  delay(5);
  Serial.print("\t\t:");
  Serial.print(pos - startPosition - 1);
  Serial.print(", in realta' sono di: ");
  return pos;
}

void writeAddress(int pos, int address){
  pos = 2 * pos;
  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, pos, (byte) (address >> 8));
  delay(5);
  eepromWriteData(LANGUAGE_EEPROM_ADDRESS, pos + 1, (byte) (address));
  delay(5);
}

int arrStrlen(const char *arr[]){
  int len = 0, i = 0;
  char buffer[100];
  while((char*) pgm_read_word(&(arr[i]))){
    strcpy_P(buffer, (char*) pgm_read_word(&(arr[i++])));
    len += strlen(buffer) + 1;
  }
  Serial.println(len);
  return len;
}

int calculateAddress(byte position){
	int pos = 2 * position;
	return ((eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos) << 8) | eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos + 1));
}

int loadString(int address, bool isAddress = false){
	int pos = isAddress ? address: calculateAddress(address);
	for(byte j = 0; (str[j] = eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos++)); j++)
		;
	return pos - address; // conta anche il '\0'
}

void loadArr(byte address){
  int pos = 0;
  byte i = 0, n = 0;
  
  Serial.print("prima di caricare l'array memoria libera = ");
  Serial.println(freeMemory()); 
  
  pos = calculateAddress(address);
  n = eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos++);  
  list = (char **) calloc(n + 1, sizeof(char *)); // n + 1 because I want list[n] = NULL (set by calloc)
  for(; i < n; i++){
    pos += loadString(pos, true);
    list[i] = strdup(str);
  }
  Serial.print("Array caricato(");
  Serial.print((int) address);
  Serial.print("): memoria libera = ");
  Serial.println(freeMemory());
}

Brig: the problem is that freeMemory() gave different results before loading the array and after free...

The free memory check only checks the distance between the top of stack and the end of the heap. It does not look inside the heap to count up the holes. If the heap isn't shrunk or can't be shrunk due to something being in use, then the memory free will show less than might be available to a subsequent malloc(). There's a good writeup here http://www.nongnu.org/avr-libc/user-manual/malloc.html that explains what the AVR-GCC malloc() can do. Also, before the heap is ever used, there is no freelist structure. On first use, that is initialized and doesn't get released. Looking at your result it seems that all but 6 bytes come back, and it would not surprise me that 6 bytes is what it takes to hold an empty freelist.

Arduino has so little memory and malloc() free() is so prone to fragmenting it, that I am really reluctant to use the heap myself, at least for anything that can't be allocated once and kept on hand forever.

yes... seems right...

so how can I solve my problem? I want the string into eeprom to be able to change it without connecting arduino to pc, thing that I must do if I use variables (progmem or not...)

no idea?

what'll appens when memory ends? it automatically restarts?

Bear in mind some of us live in different time zones to you. Personally I was fast asleep when you made that last post.

When you use up all of your available memory you are likely to get undefined behaviour ... wrong results, restart, hang.

What are you really trying to do here?

You have a lot of literals in PROGMEM - so far so good. But why copy them into RAM all the time? You know that strdup also allocates memory, right?

To display your literals like "MODIFICA PRESE" you should be able to just index into PROGMEM. You don't need to calloc and strdup.

I want the string into eeprom to be able to change it without connecting arduino to pc, thing that I must do if I use variables (progmem or not...)

It isn't really clear what you are really trying to solve here. What has changing things in EEPROM got to do with connecting to PCs? Or freeing memory?

I know, so I waited a few days before pulling on this post 8)

My purpose is not to copy in RAM for a long time, but load, use (no more than a couple of functions) and delete the data loaded ...

I do not want to use PROGMEM because a hypothetical change to a single character would cause recompilation / loading everything ... so I wanted to make the change more easy .. writing to EEPROM (external to Arduino is too small) there is no need to recompile everything ... indeed ... would be something even more functional ..

I know that strdup allocates memory, freeArr deallocates each string one by one ;) fact not valgrind gives memory leak ... Arduino is rather confusing (and I still do not understand why gives problems..)

in other words the purpose is: literals saved in EEPROM and not PROGMEM because they are likely changes and I do not want these changes resulting in compiling / uploading to arduino code

retrieve these strings, use them and delete them ...

There is an alternative to load-use-delete? (above) is no solution to the problem of memory management arduino?

I do not want to use PROGMEM because a hypothetical change to a single character would cause recompilation / loading everything ... so I wanted to make the change more easy .. writing to EEPROM (external to Arduino is too small) there is no need to recompile everything ... indeed ... would be something even more functional ..

Just out of curiosity, how will you change the data saved in EEPROM, if you need to change one or more characters. How will you deal with string lengths changing?

Here I would not have required performance … so immediately I could “write it all” …

I used this reasoning:
I need an array of strings and single strings;
the first data for the ith array/single_string is written in the position EEPROM[2 * i <<8] | EEPROM[2 * i + 1];

in case of array the first data is a byte that contains the number of components of the array strings, in the case of single-string string start directly

each string (either single array) is terminated by ‘\0’…
I am confident that each string is a maximum of x characters, so there is a global variable str that can contain the string, in the case of arrays I load the string in str, then i duplicate str into the array, and repeat…

So I can rewrite all, change the data in EEPROM [2 * i <<8] | EEPROM [2 * i + 1] to point to the first free position and write the data, possibly shrink the memory and writing the modified data as the last data in EEPROM … however I have no performance requirements … and the EEPROM should be veeery great respect to my purposes … for a couple of hundred bytes that I can not use the Arduino … should go forward so much space in the EEPROM …

however this is less of a problem … the problem is related to RAM arduino XD

I do not think that works … but …
read the size of the array and create it in the stack immediately after
something like this… even if still strdup…

void loadArr(byte address){
  ...
  pos = calculateAddress(address);
  n = eepromReadData(LANGUAGE_EEPROM_ADDRESS, pos++);  
  char *list[n];
  for(; i < n; i++){
    pos += loadString(pos, true);
    list[i] = strdup(str);
  }
  ....
}

Brig:
So I can rewrite all, change the data in EEPROM [2 * i <<8] | EEPROM [2 * i + 1] to point to the first free position and write the data, possibly shrink the memory and writing the modified data as the last data in EEPROM … however I have no performance requirements … and the EEPROM should be veeery great respect to my purposes … for a couple of hundred bytes that I can not use the Arduino … should go forward so much space in the EEPROM …

I am very sorry, but I just don’t understand you. However I repeat, what are you really trying to do here?

Judging by the strings you are controlling some sort of gadget - it has lighting, heating, pumps, filters.

You want to display something? A status? Or control something? Like, a dishwasher? A nuclear reactor? A spaceship?

You need to change the strings why? Spelling mistakes? Or you need different languages? Or the device is updated? You are using an external EEPROM chip? How large is it? How would you change that without using a PC? Unplug it and reprogram it?

You can copy data straight from the EEPROM and display it. You don’t need to allocate memory and make a temporary copy. Why are you doing that?

I want make an aquarium controller…

as youn said, I can make new languages, new version… and I save a little of compiled code…
I do not want rebuilt and uploade the code… or I simply use PROGMEM…

I’ve a 24LC512 #512Kbit

I need an array to select and idex of it… I’ve a function that shows an array and (as the phone) flows the list up by ‘2’, down by ‘8’… And I show at maximum 4 elements of the array… that may be larger than 4 elements…

alternately I could make (is efficient?)

int readIndex(int eepromPage){
  char arr[MAX_LINE][MAX_LEN];
  // load the MAX_LINE first string
  // load without strdup... just copy in arr[i]
  do{
    for(i = 0; i < MAX_LINE; i++)
      print(arr[i]);
   if(in == UP){
     for(j = 1; j < MAX_LINE; j++)
       arr[j] = arr[j - 1];
     readStr(index, arr[0]);
   }else if(in == DOWN){
     for(j = 0; j < MAX_LINE - 1; j++)
       arr[j] = arr[j + 1];
     readStr(index, arr[MAX_LINE - 1]);
   }
  }while(in != select);
}

quikly… keep a little array (in stack) to avoid MAX_LINE load for loop, but just one load…
problem 1: is efficient?
problem 2: i need index for each array string to load directly the string… (now I don’t use index… i make a linear scan…)… how can I do? keep a second array that keep the index of the last string read… something like this…
problem 3: can I make a function “readString” where I pass the ith argument string array created (in stack) by readIndex?

p.s. I’ve not understand what you want to know :stuck_out_tongue:

other idea?

other idea?

You could try re-stating your problem. Kinda lost track of things.

What do you suggest?

I've no other idea...

I don't understand your problems.

problem 1: is efficient?

problem 2: i need index for each array string to load directly the string... (now I don't use index... i make a linear scan...)... how can I do? keep a second array that keep the index of the last string read... something like this...

problem 3: can I make a function "readString" where I pass the ith argument string array created (in stack) by readIndex?

As I asked before, what are you really trying to do? Don't just post some code and ask if it is efficient. Who cares, if it an aquarium controller? Either it works or not.

You have a lot of messages that you want to display from time to time? Can you explain the real problem? Eg. you have an LCD display, and if you press a button a message pops up?

as youn said, I can make new languages, new version... and I save a little of compiled code...

The messages will appear in different languages?

  char arr[MAX_LINE][MAX_LEN];
  // load the MAX_LINE first string
  // load without strdup... just copy in arr[i]

What values do MAX_LINE and MAX_LEN have?