Questo sito utilizza cookies, anche di terze parti, per mostrare pubblicità e servizi in linea con il tuo account. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Generare una matrice dinamica generica
Forum - C/C++ - Generare una matrice dinamica generica

Avatar
AldoBaldo (Member)
Guru


Messaggi: 612
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 8:20
Venerdì, 12/02/2021
"Ispirato" dalla brevissima discussione in un altro filone di discussione* in questo stesso forum, ho riscritto una funzione destinata a creare matrici dinamiche in C adatte per qualsiasi tipo di dati. In questa nuova versione ho tentato di ridurre la quantità dei cast di tipo tramite l'uso di size_t in luogo di void*, ma non sono sicuro che si tratti di una pratica accettabile. Io l'ho provato e, con la configurazione di IDE, compilatore e sistema operativo che uso, sembra funzionare tutto a dovere. Qualcuno sa darmi conferma o smentita circa la validità del procedimento che ho impiegato? Ovvero...

1) E' ammissibile trasformare un void* in un size_t e trattarlo come se fosse un semplice valore numerico?
2) E' garantito che size_t possa SEMPRE contenere il valore di un puntatore?

A me pare che la risposta sia sì per entrambi i quesiti, ma al mio livello limitato di esperienza il rischio di incappare in qualche "situazione indefinita" esiste sempre.

Codice sorgente - presumibilmente C#

  1. /*==============================================================================
  2. Alloca dinamicamente spazio in memoria per una matrice di qr*qc elementi di
  3. dimensioni dim_el byte ciascuno. L'area della memoria allocata riservata ai dati
  4. viene inizializzata azzerandola.
  5. In caso di successo, restituisce un void* che deve essere assegnato ad un
  6. puntatore a doppia indirezione di tipo corrispondente al tipo di dati che si
  7. intende immagazzinare nella matrice appena creata.
  8. La matrice puo' essere regolarmente impiegata con i classici operatori di
  9. indicizzazione (matrice[riga][colonna]).
  10. La memoria allocata deve essere liberata dal chiamante tramite free().
  11. In caso di errore restituisce NULL e nessuna memoria risulta allocata.
  12.  
  13. PARAMETRI
  14.  
  15.     qr      quantita' di righe nella matrice
  16.     qc      quantita' di colonne nella matrice
  17.     dim_el  dimensioni (in byte) di un elemento della matrice
  18.  
  19. VALORE DI RITORNO
  20.  
  21.     un puntatore generico allo spazio di memoria allocato dinamicamente e
  22.     in grado di contenere la matrice
  23.  
  24. ESEMPIO
  25.  
  26. int main() {
  27.     const size_t qr = 6;
  28.     const size_t qc = 4;
  29.  
  30.     // crea una matrice di 6x4 elementi in
  31.     // grado di contenere valori di tipo int
  32.     int **m = crea_matrice( qr, qc, sizeof(int) );
  33.  
  34.     if( m ) {
  35.         size_t r, c;
  36.  
  37.         // popola la matrice
  38.         for( r=0; r<qr; ++r )
  39.             for( c=0; c<qc; ++c )
  40.                 m[r][c] = 10*r+c;
  41.  
  42.         // mostra il contenuto della matrice
  43.         for( r=0; r<qr; ++r )
  44.             for( c=0; c<qc; ++c )
  45.                 printf( "%d%c", m[r][c], c!=qc-1?' ':'\n' );
  46.  
  47.         // libera la memoria allocata
  48.         free( m );
  49.         m = NULL;
  50.     }
  51.    
  52.     return 0;
  53. }
  54.  
  55. ==============================================================================*/
  56.  
  57. void *crea_matrice( size_t qr, size_t qc, size_t dim_el ) {
  58.     static const size_t dim_ptr = sizeof( void* );
  59.     void *m = calloc( qr*dim_ptr + qr*qc*dim_el, 1 );
  60.  
  61.     if( m ) {
  62.         size_t pp = (size_t)m;       /* pp: puntatore a puntatore    */
  63.         size_t pr = pp + qr*dim_ptr; /* pr: puntatore a una "riga"   */
  64.  
  65.         while( qr-- ) {
  66.             *((size_t*)pp) = pr; /* colloca il puntatore ad una      **
  67.                                  ** riga nella posizione opportuna   */
  68.             pr += qc*dim_el;     /* rileva il valore del puntatore   **
  69.                                  ** alla riga successiva             */
  70.             pp += dim_ptr;       /* avanza pp alla posizione del     **
  71.                                  ** puntatore alla riga successiva   */
  72.         }
  73.     }
  74.  
  75.     return m;
  76. }


Ultima modifica effettuata da AldoBaldo il 12/02/2021 alle 8:49


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.
PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 824
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 10:23
Venerdì, 12/02/2021
Come al solito, non sono in grado di rispondere ai tuoi quesiti.
Il mio gcc in MinGW, non segnala errori, warning o note, il programma fa quanto promesso.

Quello che noto è che in questo modo la matrice m creata non è trattabile in modo "normale", sicuramente il problema risiede nel fatto che non ho capito il perché e cosa facciano:
    const size_t qr = 6;
    const size_t qc = 4;
e:
    size_t r, c;

nell'introduzione hai cercato di spiegarlo, ma una costante o variabile di tipo size_t, non realizzo cosa produca in pratica e finquando non lo capisco non posso pasticciare con il tuo codice. 8-|


in programmazione tutto è permesso
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 612
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 18:35
Venerdì, 12/02/2021
Stando a quanto lessi millenni fa, il tipo size_t non è altro che un tipo di dato destinato a contenere un valore intero senza segno con capacità sufficiente a rappresentare una qualsiasi quantità di memoria compresa tra il minimo e il massimo ammissibili dal sistema. Da ciò penso di poter dedurre che qualsiasi indirizzo di memoria (che, in definitiva, non è altro che un numero) possa essere convertito in un valore numerico che può essere inserito in una variabile di tipo size_t.

Ai fini pratici dell'esempio, qr e qc puoi tranquillamente sostituirli con int, se preferisci, così come r e c. Li ho usati solo per impostare le dimensioni della matrice e per avere a disposizione due contatori -- qr sta per "quantità righe" e qc per "quantità colonne", laddove r ("riga") e c ("colonna") sostituiscono i classici i e j.


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.
PM Quote
Avatar
Carlo (Member)
Guru


Messaggi: 824
Iscritto: 29/01/2018

Segnala al moderatore
Postato alle 18:58
Venerdì, 12/02/2021
Ho sostituito il size_t con unsigned int e le mie modifiche continuavano a non funzionare, ma ora non più distratto da una cosa che non capivo, l'errore era mio e banale...
Tutto funziona regolarmente anche con size_t.

Una bella funzione per allocare dinamicamente matrici bidimensionali con tutti i tipi di dato.

Ultima modifica effettuata da Carlo il 12/02/2021 alle 19:00


in programmazione tutto è permesso
PM Quote