Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Sto passando il tempo tentando di mettere insieme una micro-libreria (per uso personale, nel senso che non voglio farne chissà che) che tratti array dinamici di puntatori di qualsiasi tipo. Come al solito, più insisto più dubbi mi vengono, quindi tento di coinvolgerti.
L'idea parte dal presupposto, che credo corretto, che un puntatore è un puntatore, ovvero un indirizzo di memoria, ovvero un numero che ha una dimensione fissa determinata dal tipo di computer che si sta usando (16 bit ai "miei tempi", poi 32 bit, oggi si viaggia verso i 64 bit...). Per questo dovrei poter trattare un array di puntatori char* come un array di puntatori double* o di puntatori pinco_palla* senza che cambi gran che.
Dunque, definisco una struttura ARRAY_DINAMICO fatta così:
Nella mia fantasia, char **pEl dovrebbe corrispondere a char *pEl[], ovvero una serie di indirizzi (numeri) ciascuno dei quali ha la stessa dimensione in bit che avrebbe in double *pEl[] o pinco_palla *pEl[]. Ipotizzando che char* sia 32 bit, anche double* e' 32 bit e pinco_palla* è 32 bit, giusto?
Allora io alloco char **pEl così:
Codice sorgente - presumibilmente C/C++
char **tmp = calloc( cap+AD_INC)*sizeof(*tmp) );
...dove cap è la capacità corrente dell'array e AD_INC è una costante che definisce un certo numero fisso di elementi da usare ogni volta che si espande o contrae l'array (in questo caso lo sto espandendo). In realtà uso realloc(), ma non credo faccia differenza. Le funzioni di "espansione" e "contrazione" complete sono:
ad->pEl = tmp;// "consolida" il nuovo array, accettandolo in pEl
ad->cap -= AD_INC;// aggiorna la capacita' dell'array
return AD_OK;
}elsereturn!AD_OK;// errore
}elsereturn!AD_OK;// errore
}elsereturn!AD_OK;// errore
}
Ora c'è il punto per me critico: quando implemento funzioni per "scrivere" e "leggere" i puntatori posso usare puntatori generici void* anche se la memoria è stata allocata come char**? Ad esempio con una funzioni tipo:
Codice sorgente - presumibilmente C#
int AD_Inserisci( ARRAY_DINAMICO *ad, void*el, size_t pos ){
Il compilatore che sto usanto (gcc in mingw) non batte ciglio e compila senza neanche un warning, però se non ho capito male a volte ci sono cosette che esulano dallo standard e che determinano comportamenti indefiniti che alcuni compilatori segnalano e altri no.
Lo so che son domande un po' così, però ogni tanto entro in questi odiosi loop di dubbi confusionari e mi torna davvero comodo un parere "a freddo". Mi aiuti, senza voli pindarici troppo alti sopra la mia testa?
Ultima modifica effettuata da AldoBaldo il 28/06/2017 alle 10:41
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
Qui mi pare che manchi una parentesi, ma sarà errore di battitura XD
Comunque, è come dici, in teoria la dimensione di un puntatore è fissata dal sistema in quanto la dimensione di un indirizzo non dovrebbe essere variabile. Però non so i problemi che si creano a creare l' ARRAY void* e successivamente usare nel main un cast() ad esempio.
Ultima modifica effettuata da Mikelius il 28/06/2017 alle 10:58
Hai ragione: è un errore di battitura (infatti la versione che ho nei miei codici è diversa e usa realloc(); copiando, incollando e modificando mi son partite un paio di inesattezze).
Doveva essere:
Codice sorgente - presumibilmente C/C++
char **tmp = malloc( (cap+AD_INC)*sizeof(*tmp) );
Scrivi: "non so i problemi che si creano a creare l' ARRAY void* e successivamente usare nel main un cast", che è proprio quel che sto cercando di capire! Mi sembra che non debbano essercene, ma sarebbe utile se chi se ne intende più di me mi desse conferma o smentita certa.
Ovvio che quando si fanno cast occorre sempre stare attenti, ma quella è una caratteristica comune del C, tanto che le funzioni di allocazione usano tutte void*. Una volta chiarito il mio dubbio, senz'altro mi metterò col cesello in mano a rifinire tutti i dettagli necessari per evitare errori dovuti ai cast.
Ultima modifica effettuata da AldoBaldo il 28/06/2017 alle 11:21
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità.
Un giorno ti convincerò ad usare incrementi moltiplicativi invece che addizionali quando estendi l'array, purtroppo sono un po' impegnato in questi giorni.
Una precisazione: la dimensione di un puntatore dipende da tre fattori: CPU, modo di operazione (modalità reale o protetta) e se il so ha attivato la paginazione. Credo che un indirizzi di memoria virtuale in alcuni sistemi sia di 48bit, correggettermi se sbaglio.
Grazie per le risposte, anche se i miei dubbi non si dissipano ancora. Vi rispondo uno per uno.
==============================
Nessuno, perché quel cast è necessario? A me sembra come quando si fa una cosa tipo...
Codice sorgente - presumibilmente C/C++
int *intPtr = malloc( sizeof(*intPtr) );
In quel caso non si usa il cast, no? Si prende il puntatore void* e lo si usa da quel momento in poi in intPtr come se fosse un puntatore int* qualsiasi. Mi son perso qualcosa (d'altro)?
==============================
Lumo, ricordo la discussione in merito alla tipologia di incremento. Le mie "resistenze" risalgono a quando facevo cose per un computer con 1 MB di RAM in tutto e una gestione della memoria non "protetta", dove ogni programma era "confinato" entro uno spazio preallocato dal sistema e non estendibile che per forza di cose doveva essere alquanto ristretto. Ci sono imprinting dai quali è difficile liberarsi anche quando le condizioni di contorno cambiano drasticamente. E' questo che rende vecchie le persone di una certa età.
==============================
TheDarkJuster, quel che osservi (e di cui non so nulla) che ricadute ha sul caso specifico? E' una cosa che influisce sulla portabilità del codice (che per quel che ho in mente sarebbe poco importante) o può creare problemi nel momento in cui uno stesso programma già compilato viene fatto "girare" in una modalità piuttosto che un'altra anche sullo stesso computer?
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
Ma il codice è bene che sia "portabile" anche verso compilatori C++.
Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità.
Ah, ecco! Ora i conti tornano: io intendevo fare una cosa in C, non in C++. Del resto gli array dinamici in C++ fanno parte dello standard, quindi troverei futile fare qualcosa di personalizzato. Comunque, sì, in C++ quel cast sarebbe inevitabile (se no non compila).
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.