Go Down

Topic: Ridimensionare array (Read 1 time) previous topic - next topic

leo72

lesto, non so se te ne sei accorto ma nelle ultime versioni dell'IDE (non so se è già presente nella 1.0.3 perché io ho una 1.0.4 beta, compilando spesso dai sorgenti) sono stati inseriti new e malloc anche nell'Arduino.
Se guardi in core/Arduino trovi i file malloc.c, new.cpp e new.h
In new.h si legge poi:
Quote
Header to define new/delete operators as they aren't provided by avr-gcc by default

Non sapevo che avr-gcc non gestisse new e malloc... mi suona strano

lesto

leo non metto in dubbio questo, le malloc sono sempre esistite, altrimenti non avresti tutto ciò che usa RAM in modo dinamico (anzi, mi sa tutto ciò che usa ram).
La NEW non esisteva ed è stata aggiunta, ma comunque poteva essere creata ad-hoc, visto che come dicevo alla fine non è altro che una malloc con un poco di logica in più, e la delete è una free.

Quello che sto cercando di far capire è che quelle funzioni sono usate in modo magari non errato, ma sicuramente molto border-line, sicuramente non da dare a cuor leggero a chi non capisce cosa sia un puntatore (reply #2)

osservando meglio l'empio di uso postato, alessandro87 ha correttamente usato un puntatore per ricevere il risultato, e non ha sovrascritto perdendo per sempre l'indirizzo di v1, creando garbage.
corretto:
Code: [Select]
int * v2 = changeDim(v1, y);
quello che mi aspeto facia un principiante:
Code: [Select]

v1 = changeDim(v1, y); //errore, la vecchia zona di memoria di v1 è diventata garbage ovvero non più utilizzabile perchè contrassegnata come allocata, ma non più utilizzabile/deallocabile perchè non sappiamo più dov'è


rimane comunque sicuramente l'errore del punto 3. e anzi, aggiungerei un punto 4. nelle "imprecisazioni secondo me": mi sono lamentato della return ma non della
Code: [Select]
if (vector != 0)
che è più leggibile come
Code: [Select]
if (vector != null)

quindi:

Code: [Select]

int* changeDim(int* vector, int newDim){
    if (vector != null ){
        int* newArray = realloc( newDim*sizeof(int) );
        if (newArray != null){
            vector = newArray ;
            return vector;
        }
        newArray = malloc( newDim*sizeof(int) );
        if (newArray != null){
            for (int var = 0; var < newDim; ++var)
                newArray[var] = vector[var];
            free(vector);//dealloca la ram
            vector = newArray;
            return vector;
         }
    }
    return null;
}
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

alesandro87

Ciao lesto,

Per quanto riguarda gli "errori":
1) Il vecchio vettore non si può distruggere perché è creato staticamente infatti nel primo post carletto scriveva che aveva un vettore fatto cosi: byte mioarray[35]. E comunque alla mia funzione non interessa quello che accade sopra e anche se gli interessasse non è di certo sua la responsabilità di eliminare oggetti posti fuori dalla sua scope .
2) Alla funzione passo l'indirizzo a partire dal quale è memorizzato l'array in memoria, non voglio modificare nulla voglio soltanto leggere i valori presenti.
3) Qua ti do ragione.. ma un gioco con arduino non è safety critical. In altre circostanze c'è da tenere conto di questo aspetto.

Per quanto riguarda le imprecisioni
1) Arduino permette l'utilizzo del c++ e io programmo in c++ perchè mi piace di piu e perchè è a oggetti. (conosco gente che programma a oggetti anche con il c ma questo non fa per me)
2) Ho deciso di copiare i vecchi numeri per gioco.
3) (int*) 0 è un exp e si legge cosi: 0 è una var e faccio il cast a puntatore intero. Equivalente a fare questo int* var = 0; return var;(leggi la grammatica del c++) inoltre in c++ la definizione di NULL è 0. http://www.stroustrup.com/bs_faq2.html#null .

E ultima cosa ecco i tuoi errori:

Prova.cpp: In function 'int* changeDim(int*, int)':
Prova.cpp:31:19: error: 'null' was not declared in this scope
Prova.cpp:32:53: error: invalid conversion from 'unsigned int' to 'void*' [-fpermissive]
Prova.cpp:32:53: error: too few arguments to function 'void* realloc(void*, size_t)'
In file included from /usr/share/arduino/hardware/arduino/cores/arduino/Arduino.h:4:0,
                 from Blink.cpp:10:
/usr/lib/gcc/avr/4.7.2/../../../avr/include/stdlib.h:338:14: note: declared here
Prova.cpp:37:47: error: invalid conversion from 'void*' to 'int*' [-fpermissive]
Prova.cpp:46:12: error: 'null' was not declared in this scope

Come puoi notare nell'ultima riga: 'null' was not declared in this scope.

Grazie e ciao  :P

lesto

#23
Feb 05, 2013, 12:22 am Last Edit: Feb 05, 2013, 12:35 am by lesto Reason: 1
ok i punti  1 e 2 però
Quote
ma un gioco con arduino non è safety critical. In altre circostanze c'è da tenere conto di questo aspetto.

insomma. la ram esaurita è una delle cose più difficili da debuggare su un'arduino, e cose del geenre non aiutano.

Quote
(conosco gente che programma a oggetti anche con il c ma questo non fa per me)

vorrei conoscere questa gente... il C non è ad oggetti, si può simulare il comportamento degli oggetti... e in pratica riscrivi il C++  :smiley-mr-green:

Quote
E ultima cosa ecco i tuoi errori:


hai ragione, scivo il codice a lavoro e ogni tanto dimentico di avvisare che non è nemmeno testato in compilazione.
Comunque NULL invece che null, la realloc vuole anche il puntatore all'array da incrementare, e tulle le alloc ritorano un puntatore a void (generico) che va castato in quello che ti interessa

codice compilabile:
Code: [Select]
int* changeDim(int* vector, int newDim){
   if (vector != NULL ){
       int* newArray = (int*)realloc(vector, newDim*sizeof(int) );
       if (newArray != NULL){
           vector = newArray ;
           return vector;
       }
       newArray = (int*)malloc( newDim*sizeof(int) );
       if (newArray != NULL){
           for (int var = 0; var < newDim; ++var)
               newArray[var] = vector[var];
           free(vector);//dealloca la ram
           vector = newArray;
           return vector;
        }
   }
   return NULL;
}


volendo si possono usare i puntatori void per rendere la funzione più generica (notare che non si possono usare gli indici o giocare con gli indirizzi nei puntatori void e quindi li casto ad array di byte, in alcuni compilatori non è necessario):

Code: [Select]
void* changeDim(void* vector, int newDim, int sizeOfType){
   if (vector != NULL ){
       void* newArray = realloc(vector, newDim*sizeOfType );
       if (newArray != NULL){
           vector = newArray;
           return vector;
       }
       newArray = malloc( newDim*sizeOfType );
       if (newArray != NULL){
           for (int var = 0; var < newDim*sizeOfType; var++)
               ((byte*)newArray)[var] = ((byte*)vector)[var];
           free(vector);//dealloca la ram
           vector = newArray;
           return vector;
        }
   }
   return NULL;
}


esempio di uso
Code: [Select]

int* array = (int*)malloc(sizeof(int)*16); //da 16
array = (int*)changeDim(array, 20, sizeof(int)); //a 20


edit:in fine ricorderei che non ci troviamo davanti a vero C o vero C++, tantè che fino a 5 o 6 mesi fa non esisteva la new o la delete.
sei nuovo? non sai da dove partire? leggi qui: http://playground.arduino.cc/Italiano/Newbie

alesandro87

bene.. sarà contento adesso carletto di avere queste soluzioni! Ciaoo e buonanotte

Go Up