WARNING: This is an attempt to clarify if there is any safe way to use dynamic arrays on Arduino Platform ! The recommended way often is to avoid dynamic memory allocation due to the missing memory manager who would clean up SRAM after the memory space is freed again. If you want to use dynamic arrays please read the discussion carefully and do NOT start before reading the end.
However - despite of that - from time to time there seems to be some interest in dynamic arrays in Arduino applications. Therefore I looked up some old C code implementations from 1989 and compiled them into a sketch that I tested with IDE1.8.15 and an UNO.
The sketch may be of assistance (at least for 2D arrays) and to demo the basic principle which can be adopted to multidimensional arrays. Experts in the field are welcome to correct and enhance the sketch which I publish here as a start for those who want to use dynamic arrays in their applications.
There are only two functions in the example sketch which are required in an application to create/free 2D arrays that can be addressed like MyArray[irow][col]::
- int **idim2(int row, int col)
and
- void ifree2(int **pa)
Take care to declare the array variable as int **MyArray.
If you need byte or long instead of arrays of integer,you may adopt the idim2 routine.
Be aware that dynamically allocating memory may lead to failures if your application falls short of free heap space ...
// "Old School" creation of dynamic arrays
// based on an example from a C language course
// held in ... 1989 ...
// written by ec2021
//
//
// The following routine is only used to check memory allocation in this example!
// .........................
// Begin of Memory Routine
// .........................
extern unsigned int __bss_end;
extern unsigned int __heap_start;
extern void *__brkval;
int freeMemory() {
int free_memory;
if((int)__brkval == 0)
free_memory = ((int)&free_memory) - ((int)&__bss_end);
else
free_memory = ((int)&free_memory) - ((int)__brkval);
return free_memory;
}
// .........................
// End of Memory Routine
// .........................
// .........................
// Begin of idim2()
// This is where the "real work" is done
// to create the 2D array
// First the memory for all (row*col) data is allocated
// if this does not fail, memory for the pointers to the beginning
// of each row is allocated
// If this is also done successfully (calloc returns NULL in case of
// failure), the pointers are initialized with the address of their
// specific row
// The returned value points to the beginning of the pointer array
// thus allowing the compiler to address rows and cols via "a[rows][cols]"
// .........................
int **idim2(int row, int col)
{
// char *calloc();
int i;
register int **prow, *pdata;
pdata = (int *) calloc(row * col, sizeof(int));
if (pdata == (int *) NULL ){
Serial.println("No heap space for data");
exit(1);
};
prow = (int **)calloc(row, sizeof (int *));
if (prow == (int **) NULL) {
Serial.println("No heap space for row pointers");
exit(1);
};
for (i = 0; i < row; i++) {
prow[i] = pdata;
pdata += col;
};
return prow;
}
// .........................
// End of idim2()
// .........................
void ifree2(int **pa)
{
free(*pa);
free(pa);
}
void Create2D(int rowsc, int colsc) {
int **a;
int inum = 1;
register int i, j;
char out[256];
int memBefore = freeMemory();
Serial.println("\n..........................................................");
Serial.println("Free memory before calloc: "+String(memBefore));
a = idim2(rowsc, colsc);
Serial.println("Free memory after calloc: "+String(freeMemory()));
Serial.println("Memory used : "+String(memBefore-freeMemory()));
for (i = 0; i < rowsc; i++)
for (j = 0; j < colsc; j++)
a[i][j] = inum++;
char Tab = 9;
for (i = 0; i < rowsc; i++)
for (j = 0; j < colsc; j++) {
sprintf(out,"%3d%2c",a[i][j],(j+1) % colsc ? ' ' : '\n');
Serial.print(out);
}
ifree2(a);
}
void setup() {
// Runs once
Serial.begin(115200);
Create2D(2,3);
Create2D(8,8);
Create2D(7,12);
Create2D(4,16);
}
void loop() {
// Nothing to do ...
}