Matrice di dimensione variabile.

Ciao a tutti, sto sviluppando il codice per un progetto che consiste in un controller DMX per controllare delle sezioni di strisce NeoPixel.
Ho creato una matrice per poter registrare per ogni sezione e per ciascun colore R G B il valore letto dalla funzione DMXSerial.read, ovvero la matrice: "static int LValue[nTotSeg][3];"

Ho capito che non si può inserire come valore di grandezza della matrice una variabile, ma a mia domanda è... Mi sapreste dire un modo per poter creare una matrice con una grandezza variabile?

Scusate il disordine, ma a forza di provare ho fatto un po di casino :slight_smile:

Questo è il codice:

#include <Adafruit_NeoPixel.h>
#include <DMXSerial.h>

//--------------------------------------------------------------------------
// Variables
#define nLed 60               //Set here the max number of pixels for each bars.
#define pinLed 12             //Define the pin of the output to the ws2812b.
#define feedbackLed 13        //Define the pin of the Dmx status led.


//--------------------------------------------------------------------------
// DIP
int dipPinsAddress[] = {11,10,9,8,7,6,5,4,3,2};
byte dmxAddress()   {
                    int j=0;
                    for(int i=0; i<9; i++)
                      {
                      j = (j << 1) | digitalRead(dipPinsAddress[i]);
                      }
                    return j;
                    }

int dipPinsNBars[] = {A2,A3,A4,A5};

byte nBars()   {
                    int j=0;
                    for(int i=0; i<4; i++)
                      {
                      j = (j << 1) | digitalRead(dipPinsNBars[i]);
                      }
                    return j;
                    }

int dipPinsMode[] = {A0,A1};

byte Mode()   {
                    int j=0;
                    for(int i=0; i<2; i++)
                      {
                      j = (j << 1) | digitalRead(dipPinsMode[i]);
                      }
                    return j;
                    }

int SegForBar, nTotSeg;

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(nBars()*nLed, pinLed, NEO_GRB + NEO_KHZ800);



void setup() 
{

  if (Mode()==0) SegForBar = 1;
  else if (Mode()==1) SegForBar = 2;
  else if (Mode()==2) SegForBar = 6;
  else if (Mode()==3) SegForBar = 10;
  
  nTotSeg = SegForBar * nBars();

static int LValue[nTotSeg][3];
 
  pinMode(feedbackLed,OUTPUT);

  DMXSerial.init(DMXReceiver);
  pixels.begin();
}


void mode0 () 
{
  for (int x; x<nTotSeg; x++) 
  {
    for (int y; y<3; y++)
    {
      LValue[x][y] = DMXSerial.read(dmxAddress() + y + 3*x);
        
      for (int i; i<nLed; i++)
      {
        pixels.setPixelColor(i + nTotSeg*nLed, pixels.Color(LValue[x][0],LValue[x][1],LValue[x][2]));
      }
    }
  }
}




void loop() 
{
  mode0 ();
}

Se ricordo bene, e provare non fa male, se sono locali gli array possono avere dimensione definita da una variabile

Ho capito che non si può inserire come valore di grandezza della matrice una variabile, ma a mia domanda è... Mi sapreste dire un modo per poter creare una matrice con una grandezza variabile?

Ma da cosa dipende la grandezza della matrice (array) e in che momento si conosce la grandezza?
Ciao Uwe

Ciao! Ho letto nella presentazione che hai 15 anni, io ne ho molti di più e ci sono cose nel codice che hai postato che non capisco! Adesso se fai copia e incolla e poi vorresti andare a modificare un codice che non capisci, difficilmente ottieni qualcosa di buono.

Lascerei perdere "una matrice dinamica", dovresti prevedere una matrice con i massimi elementi e poi usarne solo i necessari. Dichiaro una matrice con numero elementi sufficienti e in una variabile tengo conto di quanti elementi utilizzare effettivamente.

come dice uwefed, tutto sta a capire "quando" si conosce la dimensione della matrice
se a compiletime si tratta di una costante e non ci sono problemi
se si conosce una volta a runtime puoi dichiarare la matrice locale e non ci dovrebbero essere problemi, se non che non puoi "uscire" dalla loop. Devi quindi scrivere il programma in maniera da restare sempre nella prima esecuzione della loop, non è difficile
se invece la dimensione cambiasse di continuo dovresti passare per l'allocazione dinamica della memoria, te lo sconsiglio, non è il 'C' il linguaggio ideale per farlo, non è una MCU tipo arduino la macchina ideale e non è banale da fare
se fosse così dimensiona una matrice globale di grandezza sufficente, al limite tutto quello che puoi, tanto se non ci stai con una matrice globale di dimensione "tutto quello che hai" non ci staresti nemmeno con l'allocazione dinamica

EDIT: incrociato con torn24, col quale concorquoto (siccome concordo allora quoto)

ri-EDIT
un esempio di programma che crea una matrice di dimensione conosciuta a runtime e non esce mai dalla prima loop, evitando quindi di "perdere" la matrice:

// di Nelson "StandardOil"
// Idea da sviluppare: matrici a runtime

#define LIMITARBITRARIO 100 // per esempio
void setup(void)
{
}

void loop(void)
{
    while (1)
    {
        // non esco mai dalla prima loop
        int dimensione = analogRead(A0);

        if (dimensione > LIMITEARBITRARIO)
        {
            // errore, non abbastanza memoria
            while (1);

            // interrompo l'esecuzione
        }

        int matrice[dimensione];
        // ecco creata una matrice di dimensione ignota a runtime
    }
}

[OT]

Scusate, mi stavo chiedendo, a parte l'esempio didattico...

Standardoil:
Devi quindi scrivere il programma in maniera da restare sempre nella prima esecuzione della loop, non è difficile

è "corretto", in generale, scrivere procedure che di fatto bloccano il loop principale o comunque lo fermano per un tempo molto lungo?

Nella mia ignoranza, lo eviterei il più possibile. Sbaglio?

TIA
Federico

Federico66:
è "corretto", in generale, scrivere procedure che di fatto bloccano il loop principale o comunque lo fermano per un tempo molto lungo?

... assolutamente NO, l'ottimo è che giri il più in fretta possibile per svolgere i vari compiti :slight_smile:

Guglielmo

gpb01:
... assolutamente NO, l'ottimo è che giri il più in fretta possibile per svolgere i vari compiti :slight_smile:

... e quindi, viva la mia ignoranza :slight_smile:

Grazie
Federico

Boh forse sono troppo "pragmatico" io, ma dico questo: dando per scontato che la dimensione massima dell'array è minore dello spazio disponibile (altrimenti appena dovesse servire una dimensione maggiore ovviamente il sistema non potrebbe più funzionare), quale vantaggio ci sarebbe a gestire "dinamicamente" la dimensione?

Ok, diciamo che l'array al massimo occuperebbe 1k di RAM (se lo metto in RAM), bene, ma io quel kbyte di RAM non posso comunque usarlo, se non rischiando che tutto vada a donnine allegre! Se so che occupa al massimo 1k, ok, alloco 1k!!! Se invece so che potrebbe essere di più e con le altre variabili non ci entrerei, allora ho un problema che non risolvo con un array dinamico.

Per cui la domanda è: a che serve tutto sto discorso? O mi sfugge qualcosa?

docdoc:
Per cui la domanda è: a che serve tutto sto discorso? O mi sfugge qualcosa?

su arduino: quasi a nulla, ma secondo me è buona pratica di programmazione limitare le risorse impiegate
Comunque se volessimo fare un programma portatile, tra UNO e MEGA e magari anche ESP non possiamo 'partire' con l'impegnare il massimo della memoria

Concordo con quanti sostengo la scarsa utilità dell'operazione avendo a che fare con un unico array. Secondo me, cambia il discorso dovendo operare con 2 o più array. In questo caso se non si conoscono a priori il numero di dati che andranno su ogni array in quanto generati da eventi non prevedibili in fase di programmazione, con una struttura statica, dovremmo dividere lo spazio massimo disponibile per il numero di array. Nel caso di gestione dinamica, con le inevitabili complicazione del caso, potremmo invece, per assurdo, utilizzare anche l'intero spazio per i dati di un solo array.

Standardoil:
su arduino: quasi a nulla, ma secondo me è buona pratica di programmazione limitare le risorse impiegate

Si in genere magari si, ma su Arduino, dove gira UN solo programma e che ha a disposizione tutte le risorse, non ha senso.

Comunque se volessimo fare un programma portatile, tra UNO e MEGA e magari anche ESP non possiamo 'partire' con l'impegnare il massimo della memoria

Ma in quel caso imposti la dimensione massima (sarà una #define per capirci) proprio in base alla piattaforma corrente rilevata verificando i relativi simboli ed assicurare che non si vada ad allocare più memoria del necessario.
Ad esempio per riconosce una MEGA:

#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

Poi se uno vuole sbattersi a usare malloc() e free(), contento lui.. :wink: