Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - Matrice bidimensionale void?
Forum - C/C++ - Matrice bidimensionale void?

Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 10:02
Sabato, 03/08/2019
Per puro intrattenimento presente e futuro, ieri invece di dedicarmi all'opera di Piero Bartezzaghi o rimbecillirmi davanti alla TV, mi interrogavo sul modo in cui potrebbe essere possibile "generalizzare" in C (non C++) la creazione in memoria dinamica di matrici a due dimensioni che non fossero tipizzate. Dal momento che non ho alcuna formazione "ufficiale", ovviamente mi son venute in mente le cose più fantasiose, magari ingenue o semplicemente idiote, e ho provato a realizzarne una nella quale si usano solo puntatori a void e una struttura di supporto per conservare le "impostazioni" che descrivono la matrice creata. Ho dato al codice una forma tale da poterne fare una specie di "minilibreria" indipendente, così da poterla riutilizzare al bisogno.

Mi piacerebbe sapere se quel che ho messo insieme ha una sua dignità o è inutilizzabile (se non addirittura "pericoloso" - nelle prove casalinghe che ho fatto sembra funzionare tutto secondo le aspettative, ma non si sa mai) e se c'è qualche punto nel quale avrei potuto fare meno "rigiri" da impasticcato.

Primo file, m2d.h

Codice sorgente - presumibilmente C++

  1. #ifndef M2D_H_INCLUDED
  2. #define M2D_H_INCLUDED
  3.  
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7.  
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. typedef struct {
  12.     void *dm;
  13.     size_t w, h;
  14.     size_t dEl;
  15. } M2D_Struct_t;
  16.  
  17. enum {
  18.     M2DErr_NoErr,
  19.     M2DErr_NullPtr,
  20.     M2DErr_NoMem,
  21.     M2DErr_DatiEsistenti,
  22.     M2DErr_DatiInesistenti,
  23.     M2DErr_DimZero,
  24.     M2DErr_CampiNonValidi,
  25.     M2DErr_CampiIncompatibili
  26. };
  27.  
  28. int M2D_Crea( M2D_Struct_t *m, size_t w, size_t h, size_t dEl );
  29. int M2D_Duplica( M2D_Struct_t *mDup, const M2D_Struct_t mOrig );
  30. int M2D_Copia( M2D_Struct_t mDest, const M2D_Struct_t mSorg );
  31. int M2D_CampiValidi( const M2D_Struct_t s );
  32. int M2D_CampiCompatibili( const M2D_Struct_t s1, const M2D_Struct_t s2 );
  33. int M2D_Distruggi( M2D_Struct_t *m );
  34.  
  35. const char *M2D_DescrizioneErrore( int codice );
  36.  
  37.  
  38. /*==============================================================================
  39.  
  40. CAMPI DELLA STRUTTURA M2D_Struct_t
  41.  
  42.  w      w: [w]idth, ovvero "larghezza" della matrice
  43.         La quantita' delle colonne in una matrice
  44.  
  45.  h      h: [h]eight, ovvero "altezza" della matrice
  46.         La quantita' delle righe in una matrice
  47.  
  48.  dEl    dEl; [d]imensioni degli [El]ementi della matrice
  49.         Le dimensioni, in byte, di ciascuno degli elementi di una matrice
  50.  
  51.  dm     dm: [d]ati della [m]atrice
  52.         Punta allo spazio in memoria occupato dalla matrice;
  53.         In realta', non si tratta di un vero puntatore, bensi' di un...
  54.           - puntatore a DOPPIA indirezione...
  55.           - che punta al puntatore del primo elemento...
  56.           - di un array di puntatori di h elementi...
  57.           - ciascuno dei quali e' il puntatore a un array di w elementi...
  58.           - ciascuno dei quali occupa dEl byte.
  59.         In C, questo puntatore si puo' tranquillamente assegnare a un int**,
  60.         a un char**, a un float** o a qualsiasi altro puntatore a doppia
  61.         indirezione a qualsiasi tipo.
  62.         In C++ si puo' fare la stessa cosa, ma occorre procedere con un cast
  63.         esplicito.
  64.  
  65.  
  66. VALORE DI RITORNO DELLE FUNZIONI
  67.  
  68. Tutte le funzioni restituiscono un codice d'errore che descrive la situazione
  69. in uscita. I codici sono quelli dell'enumerazione gli elementi della quale
  70. iniziano col prefisso M2DErr_:
  71.  
  72.   M2DErr_NoErr                Nessun errore, tutto a posto
  73.   M2DErr_NullPtr              E' stato incontrato un puntatore NULL laddove
  74.                               non ci sarebbe dovuto essere un puntatore NULL
  75.   M2DErr_NoMem                E' fallita un'allocazione di memoria necessaria
  76.   M2DErr_DatiEsistenti        Una struttura M2D_Struct_t per la quale ci si
  77.                               aspettava che il campo dm fosse NULL, contiene
  78.                               invece un campo dm non NULL
  79.   M2DErr_DatiInesistenti      Una struttura M2D_Struct_t per la quale ci si
  80.                               aspettava che il campo dm non fosse NULL,
  81.                               contiene invece un campo dm NULL
  82.   M2DErr_DimZero              E' stato richiesto di elaborare una matrice
  83.                               riguardante elementi di dimensioni zero, oppure
  84.                               con almeno una delle dimensioni w o h zero.
  85.   M2DErr_CampiNonValidi       Una struttura passata come parametro presenta
  86.                               campi non validi.
  87.   M2DErr_CampiiIncompatibili  I campi di due strutture passate come parametri
  88.                               hanno caratteristiche tali da renderle
  89.                               incompatibili nei termini dell'operazione
  90.                               richiesta.
  91.  
  92. ==============================================================================*/
  93.  
  94. #ifdef __cplusplus
  95. }
  96. #endif
  97.  
  98. #endif // M2D_H_INCLUDED



Secondo file, m2d.c

Codice sorgente - presumibilmente C++

  1. #include "m2d.h"
  2.  
  3. static const size_t kSizeofVoidPtr = sizeof(void*);
  4.  
  5. static void *M2D_DistruggiSpazioMemoria( void *m,size_t w,size_t h,size_t dEl )
  6. {
  7.     if( m ) {
  8.         if( (size_t)-1 != h ) {
  9.             for( size_t r=0; r<h; ++r ) {
  10.                 void *aux;
  11.  
  12.                 memcpy( &aux, m+r*kSizeofVoidPtr, kSizeofVoidPtr );
  13.  
  14.                 if( aux )
  15.                     free( aux );
  16.             }
  17.         }
  18.  
  19.         free( m );
  20.         m = NULL;
  21.     }
  22.  
  23.     return m;
  24. }
  25.  
  26. int M2D_Crea( M2D_Struct_t *m, size_t w, size_t h, size_t dEl )
  27. {
  28.     void *dmTmp;
  29.  
  30.     if( !m )
  31.         return M2DErr_NullPtr;
  32.     if( m->dm )
  33.         return M2DErr_DatiEsistenti;
  34.     if( !w || !h || !dEl )
  35.         return M2DErr_DimZero;
  36.  
  37.     dmTmp = calloc( h, kSizeofVoidPtr );
  38.  
  39.     if( dmTmp ) {
  40.         size_t r;
  41.  
  42.         for( r=0; r<h; ++r ) {
  43.             void *aux = calloc( w, dEl );
  44.  
  45.             if( aux )
  46.                 memcpy( dmTmp+r*kSizeofVoidPtr, &aux, kSizeofVoidPtr );
  47.             else
  48.                 break;
  49.         }
  50.  
  51.         if( r == h ) {
  52.             m->dm  = dmTmp;
  53.             m->w   = w;
  54.             m->h   = h;
  55.             m->dEl = dEl;
  56.             return M2DErr_NoErr;
  57.         }
  58.         else {
  59.             m = M2D_DistruggiSpazioMemoria( m, w, h-1, dEl );
  60.         }
  61.     }
  62.  
  63.     return M2DErr_NoMem;
  64. }
  65.  
  66. int M2D_Duplica( M2D_Struct_t *mDup, const M2D_Struct_t mOrig )
  67. {
  68.     int err = M2D_Crea(mDup,mOrig.w,mOrig.h,mOrig.dEl);
  69.  
  70.     if( M2DErr_NoErr == err )
  71.         err = M2D_Copia( *mDup, mOrig );
  72.  
  73.     return err;
  74. }
  75.  
  76. int M2D_Copia( M2D_Struct_t mDest, const M2D_Struct_t mSorg )
  77. {
  78.     if( !mDest.dm )
  79.         return M2DErr_DatiInesistenti;
  80.     if( !M2D_CampiValidi(mSorg) )
  81.         return M2DErr_CampiNonValidi;
  82.     if( !M2D_CampiCompatibili(mDest,mSorg) )
  83.         return M2DErr_CampiIncompatibili;
  84.  
  85.     for( size_t r=0; r<mSorg.h; ++r ) {
  86.         void *aux_mSorg, *aux_mDest;
  87.         memcpy( &aux_mSorg, mSorg.dm+r*kSizeofVoidPtr, kSizeofVoidPtr );
  88.         memcpy( &aux_mDest, mDest.dm+r*kSizeofVoidPtr, kSizeofVoidPtr );
  89.         memcpy( aux_mDest, aux_mSorg, mSorg.w*mSorg.dEl );
  90.     }
  91.  
  92.     return M2DErr_NoErr;
  93. }
  94.  
  95. int M2D_CampiValidi( const M2D_Struct_t s )
  96. {
  97.     return NULL!=s.dm && 0!=s.w && 0!=s.h && 0!=s.dEl;
  98. }
  99.  
  100. int M2D_CampiCompatibili( const M2D_Struct_t s1, const M2D_Struct_t s2 )
  101. {
  102.     return s1.w==s2.w && s1.h==s2.h && s1.dEl==s2.dEl;
  103. }
  104.  
  105. int M2D_Distruggi( M2D_Struct_t *m )
  106. {
  107.     if( !m )
  108.         return M2DErr_NullPtr;
  109.     if( !M2D_CampiValidi(*m) )
  110.         return M2DErr_CampiNonValidi;
  111.  
  112.     m->dm = M2D_DistruggiSpazioMemoria( m->dm, m->w, m->h, m->dEl );
  113.  
  114.     m->w   = 0;
  115.     m->h   = 0;
  116.     m->dEl = 0;
  117.  
  118.     return M2DErr_NoErr;
  119. }
  120.  
  121. const char *M2D_DescrizioneErrore( int codice )
  122. {
  123.     switch( codice ) {
  124.     case M2DErr_NoErr:
  125.         return "nessun errore";
  126.     case M2DErr_NullPtr:
  127.         return "puntatore NULL";
  128.     case M2DErr_NoMem:
  129.         return "allocazione di memoria fallita";
  130.     case M2DErr_DatiEsistenti:
  131.         return "la struttura fa riferimento a dati gia' allocati";
  132.     case M2DErr_DatiInesistenti:
  133.         return "la struttura non presenta il puntatore ai dati allocati";
  134.     case M2DErr_DimZero:
  135.         return "la struttura descrive una matrice con dimensioni inesistenti";
  136.     case M2DErr_CampiNonValidi:
  137.         return "uno o piu' campi della struttura con valore non valido";
  138.     case M2DErr_CampiIncompatibili:
  139.         return "uno o piu' campi con valori incompatibili tra le strutture";
  140.     default:
  141.         return "errore imprevisto";
  142.     }
  143. }


Ultima modifica effettuata da AldoBaldo il 03/08/2019 alle 10:32


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