[RISOLTO] Ridimensionamento array di struct

Ciao a tutti.
in un mio sketch, dichiaro alcune strutture come queste:

struct __attribute((__packed__)) InfoRecordTapparellaType {
  char topic[64];
  char topic_ACK[64];
  int GPIO_rele_SU;
  int GPIO_rele_GIU;
  int GPIO_bottone_SU;
  int GPIO_bottone_GIU;
  int en_bottone_SU;
  int en_bottone_GIU;
  boolean in_movimento;
  float percentuale;
  float percentuale_inizio_movimento;
  unsigned long ulTime;
  unsigned long millis_target;
  long tempo_max;
  int lock;
};

struct __attribute((__packed__)) InfoRecordInterruttoreType {
  char topic[64];
  char topic_ACK[64];
  int GPIO_rele;
  int GPIO_bottone;
  int bottone_monostabile;
  int en_bottone;
  int GPIO_stato;
  int en_stato;
  unsigned long ulTime;
};

struct __attribute((__packed__)) InfoRecordImpulsoType {
  char topic[64];
  char topic_ACK[64];
  int GPIO_rele;
  int GPIO_bottone;
  int en_bottone;
  unsigned long ulTime;
  boolean rele_eccitato;
};

static InfoRecordTapparellaType     *Tapparella =     (InfoRecordTapparellaType *)      malloc(sizeof(InfoRecordTapparellaType));
static InfoRecordInterruttoreType   *Interruttore =   (InfoRecordInterruttoreType *)    malloc(sizeof(InfoRecordInterruttoreType));
static InfoRecordImpulsoType        *Impulso =        (InfoRecordImpulsoType *)         malloc(sizeof(InfoRecordImpulsoType));

Successivamente, dopo aver letto il file di configurazione, devo ridimensionare gli array facendo in questo modo:

free(Tapparella);
free(Interruttore);
free(Impulso);
static InfoRecordTapparellaType     *Tapparella =     (InfoRecordTapparellaType *)      malloc(configuration.Tapparella_nodi *      sizeof(InfoRecordTapparellaType));
static InfoRecordInterruttoreType   *Interruttore =   (InfoRecordInterruttoreType *)    malloc(configuration.Interruttore_nodi *    sizeof(InfoRecordInterruttoreType));
static InfoRecordImpulsoType        *Impulso =        (InfoRecordImpulsoType *)         malloc(configuration.Impulso_nodi *         sizeof(InfoRecordImpulsoType));

Quando vado pero' a ripopolare le varie variabili, i alcuni valori mi sovrascrivono altri.
Sicuramente mi sfugge qualcosa, c'e' qualcuno che mi puo' dare una mano?

Il mio scopo e' di usare la giusta memoria, perche' a priori non posso sapere quanto sono grossi i vari array e potrei avere bisogno di ridimensionarli in corso d'opera.
Grazie.

Buonasera,
essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il su citato REGOLAMENTO ... Grazie. :slight_smile:

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nessuno ti potrà rispondere, quindi ti consiglio di farla al più presto. :wink:

Con malloc() assegno un area di memoria, se la usi due volte sullo stesso puntatore gli assegni due aree di memoria distinte, con possibile perdita di dati.
Per ridimensionare si usa realloc(), che se assegni una dimensione più grande conserva i dati.

Ridimensionare un puntatore con realloc() è sconsigliato, si preferisce stabilire una dimensione massima dell'array anche se poi non sono usati tutti i suoi elementi.

Con malloc() assegno un area di memoria, se la usi due volte sullo stesso puntatore gli assegni due aree di memoria distinte, con possibile perdita di dati.

Anche se prima uso free() ?

Ridimensionare un puntatore con realloc() è sconsigliato, si preferisce stabilire una dimensione massima dell'array anche se poi non sono usati tutti i suoi elementi.

Purtroppo non posso dichiararli tutti con la dimensione massima, mi occupano troppa memoria.

roncoa:
Anche se prima uso free() ?

Ci provo, vediamo se ho imparato qualcosa sui puntatori, se mi sbaglio, correggetemi :slight_smile:

free() libera lo spazio allocato dal precedente malloc, ma non modifica il puntatore, cioè la sua posizione, quindi se il successivo malloc occupa più spazio, è possible che si vada a sovrascrivere l'area di memoria contigua, che magari contiene già qualcosa.

Federico

Si anche se usi free(), free libera solo e semplicemente la memoria precedentemente riservata da malloc(). Se prima di malloc() uso free() libero la memoria, ma poi malloc() mi riassegna un area di memoria che solo casualmente potrebbe essere la stessa.

roncoa:
Anche se prima uso free() ?
Purtroppo non posso dichiararli tutti con la dimensione massima, mi occupano troppa memoria.

Si chiama deframmentazione della memoria. Accade anche con gli oggetti String che infatti sconsigliamo di usare.
Se hai una memoria occupata di 20 byte, e poi un altro blocco da 20 byte, liberi il primo ma riallochi solo 15, avrai tra i due blocchi un "buco" di 5 byte. Questo ovviamente a forza di allocare/deallocare

torn24:
Si anche se usi free(), free libera solo e semplicemente la memoria precedentemente riservata da malloc(). Se prima di malloc() uso free() libero la memoria, ma poi malloc() mi riassegna un area di memoria che solo casualmente potrebbe essere la stessa.

Anche se la memoria non è la stessa, non fa nulla.
Io faccio i malloc(), poi i free(), poi i malloc() con le dimensioni corrette, poi ripopolo tutti i campi da zero.
Così facendo alcune variabili del primo array me le trovo sporcata con valori del secondo.
Può essere colpa anche delle dichiarazioni static?

nid69ita:
Se hai una memoria occupata di 20 byte, e poi un altro blocco da 20 byte, liberi il primo ma riallochi solo 15, avrai tra i due blocchi un "buco" di 5 byte. Questo ovviamente a forza di allocare/deallocare

Ma io faccio free() di tutto, e poi malloc() di tutto. Solo dopo ripopolo tutti i campi da zero.
Così facendo alcune variabili del primo array me le trovo sporcata con valori del secondo.

Forse non ti è chiara una cosa ...
... NON sei su un PC dove c'è un sistema operativo ed un "garbage collector", sei su una piccola MCU, dove devi fare tutto tu e dove usare malloc() e free(), ovvero l'allocazione e riallocazione dinamica della memoria, porta quasi sempre ... a grossi problemi e sicuri mal di testa !!! :smiling_imp:

Una cosa è partire e, in base alle esigenze, UNA sola volta, allocare dinamicamente quello che occorre, un altra è pensare di allocare e deallocare in continuazione memoria ... se ti serve una cosa del genere, passa a raspberry, almeno li hai un sistema operativo che provvede a sistemare la memoria :smiley:

Guglielmo

roncoa:
Così facendo alcune variabili del primo array me le trovo sporcata con valori del secondo.

Non puoi pensarla come ordinate, se una delle due occupa più spazio della precedente occupazione, è probabile che vada a sovrascrivere parte dell'altra.

Federico

Boh
Credo non sovrascriverà nulla

Se ha spazio alloca dove ha spazio

Se non ha spazio ritorna null

Piuttosto non pulisce la memoria allocata, che rimane sporca, ma non sovrascritta

Salvorhardin:
Boh
Credo non sovrascriverà nulla ...

... concordo, troverà la memoria talmente frammentata che non riuscirà più ad allocare.

Occorre vedere se l'OP ha preso in considerazione tale eventualità ... ::slight_smile:

Guglielmo

Io personalmente di vederei la questione in due parti. Creati una funzione "contaoggetti()" che apre il file Dove sono scritti i vari elementi da inserire nell'array, e ti restituisce il numero di tali elementi.
Successivamente con una sola malloc all'hockey effettivamente la memoria necessaria per contenere suddetti elementi.
Infine una volta creati gli array in questo modo puoi usare funzioni apposite per popolarli.

Questo ha il vantaggio che non si frammenta la memoria più del dovuto, senza dover fare troppi giri con i puntatori. Tuttavia è un metodo lento ( ma tanto un progetto teoricamente lavora per abbastanza tempo, e metterci 30 secondi in più all'avvio é poco importante). Inoltre necessità che tutte le volte che si cambia il contenuto del file il progetto vada riavviato.

  1. Se non ricordo male in C standard una struct non può essere dichiarata static, lo puoi scrivere ma viene ignorato dal compilatore.
    Ma comunque domando a @roncoa, perchè hai usato static per quei puntatori a strutture ? A quale scopo ? Non sono globali (dichiarati in testa a tutto) ?

  2. Inoltre non capisco perché ad inizio allochi spazio per 1 struct per ognuno; se sei ad inizio, prima di leggere da file quei puntatori dovrebbero semplicemente puntare a 0 o NULL.

  3. ma variabili delle strutture, tipo GPIO_rele_SU ma sono mica numero di pin ? Se si, usa byte e non int. I pin non possono avere un valore superiore a 255. Stai sprecando un fracco di byte

  4. come ti hanno scritto sopra, sicuro di non aver occupato tutta la memoria ?
    Sai che malloc() può fallire ? Hai delle struct molto grosse, moltiplicato numero nodi (esempio x configuration.Tapparella_nodi) sicuro di non aver esaurito la memoria ?
    Sai anche che malloc() non azzera la nuova memoria allocata?

Ringrazio tutti per le risposte, adesso la questione malloc() mi e' un po' piu' chiara.
Pero' non ho ancora trovato una soluzione.

Cerco di porre il mio problema in maniera diversa.

Io ho queste ed altre struct definite a inizio sketch:

struct __attribute((__packed__)) InfoRecordTapparellaType {
  char topic[64];
  char topic_ACK[64];
  int GPIO_rele_SU;
  int GPIO_rele_GIU;
  int GPIO_bottone_SU;
  int GPIO_bottone_GIU;
  int en_bottone_SU;
  int en_bottone_GIU;
  boolean in_movimento;
  float percentuale;
  float percentuale_inizio_movimento;
  unsigned long ulTime;
  unsigned long millis_target;
  long tempo_max;
  int lock;
};

struct __attribute((__packed__)) InfoRecordInterruttoreType {
  char topic[64];
  char topic_ACK[64];
  int GPIO_rele;
  int GPIO_bottone;
  int bottone_monostabile;
  int en_bottone;
  int GPIO_stato;
  int en_stato;
  unsigned long ulTime;
};

struct __attribute((__packed__)) InfoRecordImpulsoType {
  char topic[64];
  char topic_ACK[64];
  int GPIO_rele;
  int GPIO_bottone;
  int en_bottone;
  unsigned long ulTime;
  boolean rele_eccitato;
};
ecc.

Le posso definire come array con il numero corretto solo dopo aver letto un file ini (lo faccio SOLO 1 volta) senò mi occuperebbero troppo.

Io avevo pensato di definire gli array all'inizio (dopo la definizione delle struct) con un valore fittizio (per non creare errori di variabili non trovate in fase di compilazione) e poi, (dopo aver letto i valori nel file ini) ridimensionarli con i valori letti (che posso anche essere 0).
Il popolamento di tutti gli array verra in fase successiva.

L'ideale sarebbe stato se si poteva fare
InfoRecordTapparellaType Tapparella[0];
all'inizio dello sketck
e
InfoRecordTapparellaType Tapparella[configuration.Tapparella_nodi];
dopo aver letto il file ini.

Visto che leggere due volte il file non è possibile, io vedo una sola altra soluzione: non usare un Array ma una lista. Per ottenerla è sufficiente aggiungere un parametro alla struttura: un puntatore a struttura che punti all'elemento successivo della lista. Durante la lettura del file, che avverrà un elemento per volta, allocchi la memoria necessaria a contenere l'elemento, riempi l'elemento stesso con i parametri letti nel file, e lo inserisci all'inizio della lista giustapponendo i puntatori.

Vantaggi del metodo: puoi gestire un numero qualsiasi di elementi, aggiungendone anche in corso d'opera.
Svantaggi del metodo: richiede un maggior uso di memoria e una migliore conoscenza del linguaggio.

Non capisco il problema

Tu ad inizio programma dichiari il tipo struct

Poi una variabile globale di tipo pointer a tipo struct

Non inizializzata o inizializzata a zero...

Poi leggi il numero degli elementi

E aggiorni la variabile al puntatore restituito da una calloc()

Ecco fatto un array di tanti elementi quanti te ne servono

Il problema è che così facendo è costretto a leggere due volte il file, cosa che ha ben specificato non vuole fare.

Questo mi era sfuggito

Dove ne parla?