[RISOLTO] Lista di array

Ciao a tutti,

in C/C++ è possibile avere una "lista" di array di diverse dimensioni?
Mi spiego, ho delle matrici di varie dimensioni

const PROGMEM uint16_t h_one[4] = {280, 281, 282, 283};
const PROGMEM uint16_t h_two[3] = {204, 205, 206};
const PROGMEM uint16_t h_three[3] = {207, 208, 209};
const PROGMEM uint16_t h_four[7] = {210, 211, 212, 213, 214, 215, 216};

mi piacerebbe poter avere qualcosa del genere, non picchiatemi è un esempio per capirci :slight_smile:

const PROGMEM uint16_t hours[4][] = {
  {280,281,282,283},
  {204,205,206},
  {207,208,209},
  {210,211,212,213,214,215,216}
};

Solitamente in net uso le liste di array (o qualunque altro oggetto), in modo da poter utilizzare l'indice a mio vantaggio; in questo caso l'indice corrisponde all'ora, quindi senza tanti switch, mi basterebbe scrivere hours[ORA-1]
```c
**[/b] per far riferimento all'array che mi interessa.

Ho provato a cercare, anche se non saprei bene cosa cercare, se esiste qualcosa di simile alle liste net, e ho trovato "std::list", ma mi pare d'aver capito che comunque vuole array a dimensione fissa e nn so se utilizzabile in Arduino!

In ogni caso, cerco di arrangiarmi come posso, quindi stavo valutando, di utilizzare array bidimensionale con la seconda fissa, e un riempi-posto dummy, da gestire!

const PROGMEM uint16_t hours[4][11] = {
  {280,281,282,283,999,999,999},
  {204,205,206,999,999,999,999},
  {207,208,209,999,999,999,999},
  {210,211,212,213,214,215,216}
};

Lo so che è uno spreco di memoria, è solo una ipotesi :slight_smile:

Al momento è tutto embrionale quindi accetto proposte, sperando di essere riuscito a spiegare l'obiettivo.

TIA
Federico

[UPDATE]
Per capirci in net posso scrivere questo:

    List<int[]> hours = new List<int[]>() { 
      new int[] {8,9,10,11},
      new int[] {68,69,70},
      new int[] {71,72,73},
      new int[] {74,75,76,77,78,79,80}
    };

e quindi per accedere all'array che mi interessa, mi basta:

pippo = hours[2];**
```

Quindi vorresti avere un array che somigli a un bidimensionale, ma con righe di lunghezza diversa?
La cosa é possibile
A) sprecando memoria e creando un bidim con righe lunghe quanto la più lunga
B) creando un array di puntatori a array, i quali possono avere lunghezza diversa (quindi bisognerebbe fare un array di oggetti e ogni oggetto dovrebbe contenere il puntatore a array e la sua lunghezza). Se piace come idea provo a scrivere un esempio

Silente:
Quindi vorresti avere un array che somigli a un bidimensionale, ma con righe di lunghezza diversa?

Esattamente :slight_smile:

Silente:
La cosa é possibile
A) sprecando memoria e creando un bidim con righe lunghe quanto la più lunga

cioè il mio esempio con i 999

Silente:
B) creando un array di puntatori a array, i quali possono avere lunghezza diversa (quindi bisognerebbe fare un array di oggetti e ogni oggetto dovrebbe contenere il puntatore a array e la sua lunghezza). Se piace come idea provo a scrivere un esempio

Cioè qualcosa del genere?

struct hour_t {
  uint8_t* arr;
  uint8_t len
};

struct hour_t hours[10];

//...

In realtà ci avevo pensato, ma ero fossilizzato sul PROGMEM!
Naturalmente PROGMEM non è fondamentale, era solo una cosa nuova che pensavo di utilizzare :slight_smile:

Grazie
Federico

Federico66:
In realtà ci avevo pensato, ma ero fossilizzato sul PROGMEM!

PROGMEM si usa per risparmiare SRAM nel caso si abbiano valori costanti ... ma fino a quando non stai stretto con la suddetta SRAM, perché complicarsi la vita e rendere decisamente più lento il programma ? :wink:

Guglielmo

Ma da quello che ho capito vuoi usare PROGMEM e salvare i dati in flash, se usassi un array di puntatori salveresti i valori dei puntatori, ma gli array sarebbero salvati in ram. In pratica se ho un puntatore al primo elemento dell'array ho solo l'indirizzo del primo elemento ma l'array è salvato in ram.

OFF TOPIC
La struttura dati in linguaggio C che assomiglia a List in net, sono appunto le liste in C. In C non esiste il tipo dato lista, ma vanno create con uso di struct e puntatori e bisogna creare anche funzioni di ricerca e inserimento. Però liste in c e list in net, hanno in comune di salvare dati non primitivi, struct in c, classi in net, hanno la possibilità aggiungere e togliere elementi, e in C si possono implementare funzioni di ricerca o ordinamento. Essendo le liste salvate e gestite tramiti puntatori, quindi allocate in ram, non fanno al caso tuo.

torn24:
Ma da quello che ho capito vuoi usare PROGMEM e salvare i dati in flash...

Avendo tanti array costanti, ci avevo fatto un pensierino, ma non credo che avrò problemi di sram, quindi posso tranquillamente non usarlo.

Geazie
Federico

gpb01:
PROGMEM si usa per risparmiare SRAM nel caso si abbiano valori costanti ...

A volte mi capita di fare come quelli che imparano un vocabolo al giorno e lo usano in ogni contesto :slight_smile:

Grazie
Federico

Ciao Federico66, forse non ho capito bene il tuo quesito. Se il numero delle righe e la dimensione delle stesse risultano predefinite non ti basta utilizzare un array di strutture ?

esempio:

typedef struct
{
  uint16_t h_one[4];
  uint16_t h_two[3];
  uint16_t h_three[3];
  uint16_t h_four[7];
} Struct_h;

Struct_h hours[4];

Federico66:
Avendo tanti array costanti, ci avevo fatto un pensierino, ma non credo che avrò problemi di sram, quindi posso tranquillamente non usarlo.

Geazie
Federico

Te la butto lì..

Se gli array sono costanti, sappiamo già a priori i valori che devono contenere e le rispettive lunghezze.
Una matrice di questo tipo:

const PROGMEM uint16_t hours[4][] = {
  {280,281,282,283},
  {204,205,206},
  {207,208,209},
  {210,211,212,213,214,215,216}
};

la puoi rappresentare anche così:

const PROGMEM uint16_t hours[17] = {
    280,281,282,283,
    204,205,206,
    207,208,209,
    210,211,212,213,214,215,216
  };

In pratica lo fai diventare un array mono dimensionale in cui le righe della matrice precedente sono una in fila all'altra, poi ti servirà un'altro array per indicizzarlo in modo da accederci senza troppi "magic numbers"

una cosa così:

const PROGMEM byte hoursIndex[4] = { 0, 4, 7, 10 };

In questo modo l'array in posizione n della matrice iniziale inizia all'indice hoursIndex[n], termina all'indice hoursIndex[n+1]-1 ed è di lunghezza hoursIndex[n+1]-hoursIndex[n]

C'è da arzigogolare con l'ultima sequenza perchè non hai l'indice successivo, quindi forse, per uniformare l'accesso dovresti definire l'array di indicizzazione in questo modo:

const PROGMEM byte hoursIndex[5] = { 0, 4, 7, 10, 17 };

aggiungendo in fondo un valore che corrisponde alla lunghezza dell'array iniziale

La soluzione sta in piedi in termini di risparmio di memoria solo se l'indice occupa meno spazio di quello che occuperebbero i valori "jolly" della tua soluzione.

C'è da tenere presente anche che essendo l'accesso alla "matrice" mediato da calcoli, esso è meno efficiente in termini di prestazioni rispetto ad un accesso diretto (la tua soluzione), quindi, come spesso capita, si sta sacrificando tempo macchina a favore di spazio in memoria (o viceversa, qui se c'è qualcuno all'ascolto più fresco di me può approfondire se vuole..)

Ciao
Paolo

Diego67:

typedef struct

{
  uint16_t h_one[4];
  uint16_t h_two[3];
  uint16_t h_three[3];
  uint16_t h_four[7];
} Struct_h;

Struct_h hours[4];

quella struttura equivale:

const uint16_t h_one[4] = {280, 281, 282, 283};
const uint16_t h_two[3] = {204, 205, 206};
const uint16_t h_three[3] = {207, 208, 209};
const uint16_t h_four[7] = {210, 211, 212, 213, 214, 215, 216};

cioè quello che vorrei evitare :slight_smile:

cerco di avere una matrice bidimensionale con righe di lunghezza diversa.

Federico

paolo311:
Te la butto lì..

Interessante soluzione, l'ho già adottata per elaborare le immagini, ma li le righe avevano dimensione fissa :slight_smile:

La prendo in considerazione, non ho alcuna fretta, quindi valuto tutte le alternative.

Grazie
Federico

Avevo 10 minuti, quindi ho fatto qualche prova con entrambe le soluzioni proposte e con buoni risultati

#define HOUR_SIZE 4

//*** Array of struct
struct hour_t {
  const uint16_t* arr;
  uint8_t len = 0;
  void add(const uint16_t a[], uint8_t l) {
    arr = a;
    len = l;
  };
};
struct hour_t hours_list[HOUR_SIZE];

//*** Array of int
const uint16_t hours[14] = {
    11, 12, 13, 14,
    21, 22, 23,
    31, 32, 33, 34, 35,
    41, 42
  };
const uint8_t hours_idx[HOUR_SIZE + 1] = { 0, 4, 7, 12, 14 };

void setup() {
  Serial.begin(9600);

  hours_list[0].add((const uint16_t[]){11, 12, 13, 14}, 4);
  hours_list[1].add((const uint16_t[]){21, 22, 23}, 3);
  hours_list[2].add((const uint16_t[]){31, 32, 33, 34, 35}, 5);
  hours_list[3].add((const uint16_t[]){41, 42}, 2);
  Serial.println("=> Array of struct");
  for (uint8_t r = 0; r < HOUR_SIZE; r++) {
    Serial.print(r);Serial.print(":");
    for (uint8_t c = 0; c < hours_list[r].len; c++) {
      Serial.print(hours_list[r].arr[c]);Serial.print(",");
    }
    Serial.println();
  }

  Serial.println();
  
  Serial.println("=> Array of int");
  for (uint8_t r = 0; r < HOUR_SIZE; r++) {
    Serial.print(r);Serial.print(":");
    for (uint8_t c = hours_idx[r]; c < hours_idx[r + 1]; c++) {
      Serial.print(hours[c]);Serial.print(",");
    }
    Serial.println();
  }
 
}

void loop() {
  //...
}
=> Array of struct
0:11,12,13,14,
1:21,22,23,
2:31,32,33,34,35,
3:41,42,

=> Array of int
0:11,12,13,14,
1:21,22,23,
2:31,32,33,34,35,
3:41,42,

Nel primo caso non sono riuscito a capire se, e come, è possibile inizializzare l'array di strutture, io non ci sono riuscito! :frowning:

Intanto, grazie a tutti
Federico

Non conoscevo questa possibilità di usare gli array

hours_list[0].add((const uint16_t[]){11, 12, 13, 14}, 4);

Credevo che servisse sempre una variabile array e poi assegnare l'indirizzo al puntatore.
Grazie, ho imparato qualcosa di nuovo. :slight_smile:

torn24:
Non conoscevo questa possibilità di usare gli array

...ad essere onesti, neanche io!
Scoperto per caso cercando di evitare l'array di appoggio.
Funziona solo con le costanti, o almeno, è l'unico caso che non genera errore :slight_smile:

const byte* b;
b = (const byte[]){1,2};

e quindi sembra funzionare anche questo

struct hour_t {
  const uint16_t* arr;
  uint8_t len;
} hours_list[4] = {
  {(const uint16_t[]){ 11, 12, 13, 14 }, 4},
  {(const uint16_t[]){ 21, 22, 23 }, 3},
  {(const uint16_t[]){ 31, 32, 33, 34, 35 }, 5},
  {(const uint16_t[]){ 41, 42 }, 2}
};

Federico

Ciao! Ho provato su ide online "ideone", funziona anche con non costanti. Ho provato solo su quell'IDE :slight_smile:

int *p=(int[]){1,2,3,4};

Questo codice non da errore, e al puntatore è assegnato l'array.

torn24:
Ciao! Ho provato su ide online "ideone"...

Ciao, naturalmente avevo già provato su Arduino :frowning:

_DEL02:79:25: error: taking address of temporary array
   int *p=(int[]){1,2,3,4};
                         ^
exit status 1
taking address of temporary array

Credo dipenda dalla versione C

Federico