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++ - Array multidimensionale generico in C?
Forum - C/C++ - Array multidimensionale generico in C?

Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 0:04
Domenica, 11/08/2019
Galvanizzato dall'entusiasmo travolgente che ha generato il mio ultimo thread (quello sull'ipotesi di un insieme di funzioni per gestire matrici generiche in C), in questi giorni sto buttando giù una "estensione" del concetto, con funzioni per gestire array multidimensionali generici di dimensioni qualsiasi e con una quantità arbitraria di dimensioni.

Una cosa che ho voluto evitare, è l'allocazione di una miriade di minuscoli blocchi di memoria (se non ho capito male, la frammentazione della memoria che potrebbe derivarne non è una buonca cosa). Con le funzioni che seguono, la matrice multidimensionale viene sempre creata in UN UNICO blocco di memoria, allocato con UN'UNICA chiamata a calloc(). I puntatori sono "inglobati" in testa al blocco, e puntano alle posizioni più opportune, tutte nell'ambito dello stesso blocco. Sarà anche un meccanismo banale, magari ho solo reinventato la ruota convinto di avere avuto un'idea originale, però risolvere questo "rebus" mi è costato parecchio in termini di tempo e di sforzo. Spero di non avere commesso errori (dai test non ne ho rilevati).

Mentre la volta scorsa vi ho proposto un codice finito, questa volta è un "lavoro in corso", per cui ci sono ancora rifiniture da mettere a punto, come la definizione dei codici e dei messaggi di errore, il controllo dei parametri è così via. Il codice è comunque funzionante.

Graditi commenti e/o suggerimenti.

File amd.h

Codice sorgente - presumibilmente C++

  1. #ifndef MATRICE_H_INCLUDED
  2. #define MATRICE_H_INCLUDED
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7.  
  8. static const size_t kSizeofPtr = sizeof(void*);
  9.  
  10. typedef struct {
  11.     void *d; // puntatore allo spazio occupato in memoria da dati+puntatori
  12.     size_t *qElXDim; // quantita' di elementi per ogni dimensione dell'array
  13.     size_t totDim; // quantita' totale delle dimensioni dell'array
  14.     size_t dimEl; // le dimensioni (in byte) di ogni elemento dell'array
  15. } AMD; // AMD: Array Multi Dimensionale
  16.  
  17. int AMD_Crea( AMD *m, size_t *qElXDim, size_t totDim, size_t dEl );
  18. int AMD_Distruggi( AMD *m );
  19.  
  20. size_t AMD_QuantitaElementi( AMD *m );
  21. size_t AMD_QuantitaPuntatori( AMD *m );
  22. size_t AMD_DimensioniMemoriaAllocata( AMD *m );
  23. size_t AMD_DimensioniSpazioPuntatori( AMD *m );
  24. size_t AMD_DimensioniSpazioDati( AMD *m );
  25. void  *AMD_InizioSpazioDati( AMD *m );
  26.  
  27. #endif // MATRICE_H_INCLUDED



File amd.c

Codice sorgente - presumibilmente C/C++

  1. #include "amd.h"
  2.  
  3. /*==============================================================================
  4. Viene chiamata solo se l'array ha piu' di una dimensione (con totDim>1).
  5.  
  6. PARAMETRI
  7.  
  8.   pPtrs     "pPtrs": puntatore ai puntatori
  9.             puntatore al blocco di memoria allocato da AMD_Crea();
  10.             in uscita, in testa al blocco si trovera' la schiera dei puntatori
  11.             necessari a rendere utilizzabile la matrice multidimensionale con
  12.             gli operatori []
  13.  
  14.   qPtrs     "qPtrs": quantita' dei puntatori
  15.             la quantita' dei puntatori che devono essere collocati in testa al
  16.             blocco di memoria puntato da pPtrs
  17.  
  18.   qDati     "qDati": quantita' dei dati
  19.             la quantita' complessiva degli elementi presenti nell'intera matrice
  20.             multidimensionale; equivale al prodotto di tutte le dimensioni della
  21.             matrice stessa, come elencate in qElXDim
  22.  
  23.   dimEl     "dimEl": dimensioni dell'elemento
  24.             le dimensioni d'ognuno dei qDati elementi presenti nell'intera
  25.             matrice multidimensionale
  26.  
  27.   qElXDim   "qElXDim": quantita' di elementi per ogni dimensione
  28.             puntatore a un array di valori di tipo size_t, ciascuno dei quali
  29.             rappresenta la quantita' di elementi presenti in una determinata
  30.             dimensione dell'array multidimensionale; le dimensioni sono elencate
  31.             nell'array in ordine da quella piu' esterna (in posizione [0]) a
  32.             quella piu' interna (in posizione [totDim-1])
  33.  
  34.   totDim    "totDim": quantita' totale delle dimensioni
  35.             la quantita' totale delle dimensioni della matrice multidimensionale
  36.             l'array di size_t puntato da qElXDim ha totDim elementi
  37. ==============================================================================*/
  38.  
  39. static void AMD_imposta_ptr( void *pPtrs, size_t qPtrs,
  40.                              size_t qDati, size_t dimEl,
  41.                              size_t *qElXDim, size_t totDim ) {
  42.     void *dst, *srg, *pDati; // dst: destinazione; srg: sorgente
  43.     size_t dimBloccoDati, qBlocchiDati; // vedi sotto
  44.     size_t i, j; // contatori
  45.  
  46.     // lo spazio dei dati comincia subito
  47.     // dopo lo spazio riservato ai puntatori
  48.     pDati = pPtrs + qPtrs*kSizeofPtr;
  49.  
  50.     // ogni gruppo dei dati contenuti nell'ultima
  51.     // dimensione dell'array occupa dimBloccoDati byte
  52.     dimBloccoDati = qElXDim[totDim-1]*dimEl;
  53.  
  54.     // esistono qBlocchiDati blocchi di dati,
  55.     // ciascuno grande dimBloccoDati byte
  56.     qBlocchiDati  = qDati/qElXDim[totDim-1];
  57.  
  58.     // dst punti appena oltre lo spazio destinato ai puntatori
  59.     dst = pPtrs + qPtrs*kSizeofPtr;
  60.     // srg punti appena oltre lo spazio destinato ai dati
  61.     srg = pDati + qBlocchiDati*dimBloccoDati;
  62.  
  63.     // arretra dst di kSizeofPtr byte alla volta lungo lo spazio riservato ai
  64.     // puntatori, arretrando parallelamente srg di dimBloccoDati byte alla volta
  65.     // e memorizzando in dst l'indirizzo di ciascun gruppo di qElXDim[totDim-1]
  66.     // elementi dell'array (qElXDim[totDim-1] e' l'ultima dimensione dell'array)
  67.     for( j=0; j<qBlocchiDati; ++j ) {
  68.         dst -= kSizeofPtr;
  69.         srg -= dimBloccoDati;
  70.         memcpy( dst, &srg, kSizeofPtr );
  71.     }
  72.  
  73.     // arretra dst di kSizeofPtr byte alla volta lungo lo spazio riservato ai
  74.     // puntatori, arretrando parallelamente srg quanto serve per "seguire" la
  75.     // sequenza dei puntatori alle varie dimensioni dell'array e memorizzando in
  76.     // dst l'indirizzo di ciascun puntatore rilevato (elaborare questa soluzione
  77.     // m'ha fatto girare ben bene la testa!)
  78.     for( i=totDim-2; i>0; --i ) {
  79.         for( j=0; j<qElXDim[i-1]; ++j ) {
  80.             dst -= kSizeofPtr;
  81.             srg -= qElXDim[i]*kSizeofPtr;
  82.             memcpy( dst, &srg, kSizeofPtr );
  83.         }
  84.     }
  85. }
  86.  
  87. /*==============================================================================
  88. Valuta la quantita' degli elementi contenuti nell'array multidimensionale,
  89. moltiplicando tra loro le dimensioni elencate nell'array dim.
  90. Non essendo consentito l'accesso "esterno" a questa funzione, non viene
  91. effettuata alcuna verifica della validita' dei parametri.
  92. ==============================================================================*/
  93.  
  94. static size_t AMD_calcola_quantita_elementi( size_t *dim, size_t totDim ) {
  95.     size_t i, qEl;
  96.  
  97.     for( qEl=1, i=0; i<totDim; ++i )
  98.         qEl *= dim[i];
  99.  
  100.     return qEl;
  101. }
  102.  
  103. /*==============================================================================
  104. Valuta la quantita' dei puntatori che occorrera' impostare per permettere
  105. all'array multidimensionale di "funzionare" correttamente con gli operatori [].
  106. Non essendo consentito l'accesso "esterno" a questa funzione, non viene
  107. effettuata alcuna verifica della validita' dei parametri.
  108. ==============================================================================*/
  109.  
  110. static size_t AMD_calcola_quantita_puntatori(
  111.     size_t *dim, size_t totDim, size_t dimIn, size_t exQp ) {
  112.     if( 1==totDim ) return 0; // con una sola dimensione, non servono
  113.                               // calcoli, ne' puntatori "ausiliari"
  114.  
  115.     if( dimIn<totDim ) {
  116.         size_t i, qp;
  117.  
  118.         for( qp=1, i=0; i<dimIn; ++i )
  119.             qp *= dim[i];
  120.  
  121.         return AMD_calcola_quantita_puntatori( dim, totDim, dimIn+1, exQp+qp );
  122.     }
  123.  
  124.     return exQp;
  125. }
  126.  
  127. size_t AMD_QuantitaElementi( AMD *m ) {
  128.     return AMD_calcola_quantita_elementi( m->qElXDim, m->totDim );
  129. }
  130.  
  131. size_t AMD_QuantitaPuntatori( AMD *m ) {
  132.     return AMD_calcola_quantita_puntatori( m->qElXDim, m->totDim, 1, 0 );
  133. }
  134.  
  135. size_t AMD_DimensioniMemoriaAllocata( AMD *m ) {
  136.     return AMD_DimensioniSpazioPuntatori(m) + AMD_DimensioniSpazioDati(m);
  137. }
  138.  
  139. size_t AMD_DimensioniSpazioPuntatori( AMD *m ) {
  140.     size_t qPtrs = AMD_calcola_quantita_puntatori( m->qElXDim, m->totDim, 1,0 );
  141.     return qPtrs*kSizeofPtr;
  142. }
  143.  
  144. size_t AMD_DimensioniSpazioDati( AMD *m ) {
  145.     return AMD_QuantitaElementi(m) * m->dimEl;
  146. }
  147.  
  148. void *AMD_InizioSpazioDati( AMD *m ) {
  149.     return m->d + AMD_DimensioniSpazioPuntatori(m);
  150. }
  151.  
  152. /*==============================================================================
  153.  
  154. ==============================================================================*/
  155.  
  156. int AMD_Crea( AMD *m, size_t *qElXDim, size_t totDim, size_t dEl ) {
  157.     void *dTmp;
  158.     size_t *qElXDimTmp;
  159.     size_t qDati;   // quantita' di elementi nell'array
  160.     size_t qPtrs;   // quantita' di puntatori
  161.     size_t memDati; // quantita' di memoria occupata dai dati (in bytes)
  162.     size_t memPtrs; // quantita' di memoria occupata dai puntatori (in bytes)
  163.  
  164.     if( !m || !qElXDim )     return 1; // parametri NULL
  165.     if( !totDim || !dEl )    return 2; // dimensioni non valide
  166.     if( m->d || m->qElXDim ) return 3; // la struttura m contiene gia' dati?
  167.  
  168.     qDati = AMD_calcola_quantita_elementi( qElXDim, totDim );
  169.     if( !qDati ) return 4; // una delle dimensioni ha 0 elementi
  170.     memDati = qDati*dEl;
  171.  
  172.     qPtrs = AMD_calcola_quantita_puntatori( qElXDim, totDim, 1, 0 );
  173.     memPtrs = qPtrs*kSizeofPtr;
  174.  
  175.     dTmp = malloc( memPtrs+memDati );
  176.  
  177.     if( dTmp ) {
  178.         qElXDimTmp = calloc( totDim, sizeof(*qElXDimTmp) );
  179.  
  180.         if( qElXDimTmp ) {
  181.             memset( dTmp, 0, memPtrs+memDati );
  182.  
  183.             if( 1<totDim ) // solo se l'array e' multidimensionale
  184.                 AMD_imposta_ptr( dTmp, qPtrs, qDati, dEl, qElXDim, totDim );
  185.  
  186.             memcpy( qElXDimTmp, qElXDim, totDim*sizeof(*qElXDim) );
  187.  
  188.             m->d       = dTmp;
  189.             m->qElXDim = qElXDimTmp;
  190.             m->totDim  = totDim;
  191.             m->dimEl   = dEl;
  192.  
  193.             return 0;
  194.         }
  195.  
  196.         free( dTmp );
  197.     }
  198.  
  199.     return 5;   // allocazione fallita
  200. }
  201.  
  202. int AMD_Distruggi( AMD *m ) {
  203.     if( m ) {
  204.         if( m->d ) free( m->d );
  205.         memset( m, 0, sizeof(*m) );
  206.         return 0;
  207.     }
  208.  
  209.     return 1; // parametro NULL
  210. }



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
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 0:52
Lunedì, 12/08/2019
Cambiate un po' di cose, aggiunte un po' di altre...

File amd.h:

Codice sorgente - presumibilmente C++

  1. #ifndef AMD_H_INCLUDED
  2. #define AMD_H_INCLUDED
  3.  
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7.  
  8. #include <stdlib.h>
  9.  
  10. typedef struct {
  11.     void *d;         // puntatore allo spazio occupato in memoria da
  12.                      // dati+puntatori agli elementi dell'array
  13.     size_t *qElXDim; // quantita' di elementi per ogni dimensione dell'array
  14.     size_t totDim;   // quantita' totale delle dimensioni dell'array
  15.     size_t dimEl;    // le dimensioni (in byte) di ogni elemento dell'array
  16. } AMD_struct;        // AMD: [A]rray [M]ulti[D]imensionale
  17.  
  18. typedef AMD_struct *AMD_ptr;
  19.  
  20. enum {
  21.     AMDErr_NoErr,
  22.     AMDErr_PtrNULL,
  23.     AMDErr_NoMem,
  24.     AMDErr_DatiGiaPresenti,
  25.     AMDErr_ZeroDimensioni,
  26.     AMDErr_DimensioneZero,
  27.     AMDErr_DimElZeroByte,
  28.     AMDErr_StrutturaNonValida,
  29.     AMDErr_StruttureNonCompatibili,
  30.     AMD_MaxErr
  31. };
  32.  
  33.  
  34. int AMD_Crea( AMD_ptr amd, size_t dimEl, size_t totDim, ... );
  35. int AMD_Duplica( AMD_ptr duplicato, const AMD_ptr originale );
  36. int AMD_Distruggi( AMD_ptr amd );
  37.  
  38. int AMD_Copia( AMD_ptr copia, const AMD_ptr originale );
  39.  
  40. size_t AMD_QuantitaElementi( const AMD_ptr amd );
  41. size_t AMD_QuantitaPuntatori( const AMD_ptr amd );
  42. size_t AMD_DimensioniMemoriaAllocata( const AMD_ptr amd );
  43. size_t AMD_DimensioniSpazioPuntatori( const AMD_ptr amd );
  44. size_t AMD_DimensioniSpazioDati( const AMD_ptr amd );
  45. void  *AMD_InizioSpazioDati( const AMD_ptr amd );
  46.  
  47. const char *AMD_DescrizioneErrore( int codice );
  48.  
  49. /*==============================================================================
  50.  
  51. CAMPI DELLA STRUTTURA AMD_struct
  52.  
  53.  d        d: [d]ati dell'array
  54.           Punta allo spazio in memoria occupato dall'array;
  55.           In realta', non si tratta di un semplice puntatore, bensi' di un
  56.           puntatore a indirezione multipla, il livello di indirezione del quale
  57.           dipende dalla quantita' delle dimensioni dell'array multidimensionale.
  58.           In C, questo puntatore si puo' tranquillamente assegnare a un
  59.           int*[*...], a un char*[*...], a un float*[*...] o a qualsiasi altro
  60.           puntatore a doppia, tripla, quadrupla... indirezione a qualsiasi tipo.
  61.           In C++ si puo' fare la stessa cosa, ma occorre procedere con un cast
  62.           esplicito.
  63.  
  64.           Nota: oltre allo spazio per "ospitare" i dati, la memoria puntata da d
  65.                 ha dimensioni sufficienti a contenere "in testa" anche i
  66.                 puntatori che servono per rendere utilizzabile l'operatore []
  67.                 con l'array multidimensionale.
  68.  
  69.  qElXDim  qElXDim: [q]uantita' degli [El]ementi [X] per ogni [Dim]ensione
  70.           dell'array multidimensionale.
  71.           E' un puntatore a una serie di valori di tipo size_t, ciascuno dei
  72.           quali definisce la "profondita'" della dimensione corrispondente alla
  73.           sua posizione nella serie. Ad esempio, se qElXDim punta alla serie di
  74.           valori 3,2,4, allora l'array e' tridimensionale, con profondita' della
  75.           dimensione x pari a 4, profondita' della dimensione y pari a 2 e
  76.           profondita' della dimensione z pari a 3, per un totale di 4*3*2=24
  77.           elementi nell'array.
  78.  
  79.  totDim   totDim: [tot]ale delle [Dim]ensioni dell'array
  80.           Indica la quantita' delle dimensioni dell'array, e deve corrispondere
  81.           alla quantita' dei valori presenti nella serie puntata da qElXDim.
  82.           Ad esempio, nel caso dell'array tridimensionale appena descritto,
  83.           totDim deve essere 3.
  84.  
  85.  dimEl    dimEl: [dim]ensioni degli [El]ementi dell'array
  86.           Le dimensioni, in byte, di ciascuno degli elementi dell'array
  87.           multidimensionale.
  88.           Ad esempio, se nel caso dell'array tridimensionale appena descritto
  89.           dimEl fosse 8 (8 byte per elemento), la dimensione complessiva dei
  90.           dati dell'intero array di 4*3*2=24 elementi sarebbe di 24*8=192 byte.
  91.  
  92. ==============================================================================*/
  93.  
  94. #ifdef __cplusplus
  95. }
  96. #endif
  97.  
  98. #endif // AMD_H_INCLUDED



File amd.c:

Codice sorgente - presumibilmente C++

  1. #include "amd.h"
  2.  
  3. #include <string.h>
  4. #include <stdarg.h>
  5.  
  6. static const size_t AMD_SizeofPtr = sizeof(void*);
  7. static const unsigned int AMD_UIntMenoUno = (unsigned int)-1;
  8.  
  9. // costanti usate in AMD_StatoAzzeramentoCampi()
  10. static const unsigned int AMD_Bit_d          = 1U;  // I bit
  11. static const unsigned int AMD_Bit_qElXDim    = 2U;  // II bit
  12. static const unsigned int AMD_Bit_totDim     = 4U;  // III bit
  13. static const unsigned int AMD_Bit_dimEl      = 8U;  // IV bit
  14. static const unsigned int AMD_NoCampiZero    = 15U; // nessun campo azzerato
  15. static const unsigned int AMD_TuttiCampiZero = 0U;  // tutti campi azzerati
  16.  
  17. /// ===> FUNZIONI NON DISPONIBILI PER L'UTENTE <================================
  18.  
  19. /*==============================================================================
  20. Viene chiamata solo se l'array ha piu' di una dimensione (con totDim>1).
  21. Compila lo spazio riservato ai puntatori nell'ambito della memoria allocata per
  22. un array multidimensionale, cosi' da rendere successivamente possibile con esso
  23. l'impiego dell'operatore [].
  24.  
  25. PARAMETRI
  26.  
  27.   pPtrs     "pPtrs": puntatore ai puntatori
  28.             puntatore al blocco di memoria allocato dalla funzione statica
  29.             AMD_crea_da_array_dimensioni();
  30.             in uscita, in testa al blocco si trovera' la schiera dei puntatori
  31.             necessari a rendere utilizzabile la matrice multidimensionale con
  32.             gli operatori []
  33.  
  34.   qPtrs     "qPtrs": quantita' dei puntatori
  35.             la quantita' dei puntatori che devono essere collocati in testa al
  36.             blocco di memoria puntato da pPtrs
  37.  
  38.   qDati     "qDati": quantita' dei dati
  39.             la quantita' complessiva degli elementi presenti nell'intera matrice
  40.             multidimensionale; equivale al prodotto di tutte le dimensioni della
  41.             matrice stessa, come elencate in qElXDim
  42.  
  43.   dimEl     "dimEl": dimensioni dell'elemento
  44.             le dimensioni d'ognuno dei qDati elementi presenti nell'intera
  45.             matrice multidimensionale
  46.  
  47.   qElXDim   "qElXDim": quantita' di elementi per ogni dimensione
  48.             puntatore a un array di valori di tipo size_t, ciascuno dei quali
  49.             rappresenta la quantita' di elementi presenti in una determinata
  50.             dimensione dell'array multidimensionale; le dimensioni sono elencate
  51.             nell'array in ordine da quella piu' esterna (in posizione [0]) a
  52.             quella piu' interna (in posizione [totDim-1])
  53.  
  54.   totDim    "totDim": quantita' totale delle dimensioni
  55.             la quantita' totale delle dimensioni della matrice multidimensionale
  56.             l'array di size_t puntato da qElXDim ha totDim elementi
  57. ==============================================================================*/
  58.  
  59. static void AMD_imposta_ptr( void *pPtrs, size_t qPtrs,
  60.                              size_t qDati, size_t dimEl,
  61.                              size_t *qElXDim, size_t totDim ) {
  62.     void *dst, *srg, *pDati; // dst: destinazione; srg: sorgente
  63.     size_t dimBloccoDati, qBlocchiDati; // vedi sotto
  64.     size_t i, j; // contatori
  65.  
  66.     // lo spazio dei dati comincia subito
  67.     // dopo lo spazio riservato ai puntatori
  68.     pDati = pPtrs + qPtrs*AMD_SizeofPtr;
  69.  
  70.     // ogni gruppo dei dati contenuti nell'ultima
  71.     // dimensione dell'array occupa dimBloccoDati byte
  72.     dimBloccoDati = qElXDim[totDim-1]*dimEl;
  73.  
  74.     // esistono qBlocchiDati blocchi di dati,
  75.     // ciascuno grande dimBloccoDati byte
  76.     qBlocchiDati  = qDati/qElXDim[totDim-1];
  77.  
  78.     // dst punti appena oltre lo spazio destinato ai puntatori
  79.     dst = pPtrs + qPtrs*AMD_SizeofPtr;
  80.     // srg punti appena oltre lo spazio destinato ai dati
  81.     srg = pDati + qBlocchiDati*dimBloccoDati;
  82.  
  83.     // arretra dst di AMD_SizeofPtr byte per volta lungo lo spazio riservato ai
  84.     // puntatori, arretrando parallelamente srg di dimBloccoDati byte alla volta
  85.     // e memorizzando in dst l'indirizzo di ciascun gruppo di qElXDim[totDim-1]
  86.     // elementi dell'array (qElXDim[totDim-1] e' l'ultima dimensione dell'array)
  87.     for( j=0; j<qBlocchiDati; ++j ) {
  88.         dst -= AMD_SizeofPtr;
  89.         srg -= dimBloccoDati;
  90.         memcpy( dst, &srg, AMD_SizeofPtr );
  91.     }
  92.  
  93.     // arretra dst di AMD_SizeofPtr byte per volta lungo lo spazio riservato ai
  94.     // puntatori, arretrando parallelamente srg quanto serve per "seguire" la
  95.     // sequenza dei puntatori alle varie dimensioni dell'array e memorizzando in
  96.     // dst l'indirizzo di ciascun puntatore rilevato (elaborare questa soluzione
  97.     // m'ha fatto girare ben bene la testa!)
  98.     for( i=totDim-2; i>0; --i ) {
  99.         for( j=0; j<qElXDim[i-1]; ++j ) {
  100.             dst -= AMD_SizeofPtr;
  101.             srg -= qElXDim[i]*AMD_SizeofPtr;
  102.             memcpy( dst, &srg, AMD_SizeofPtr );
  103.         }
  104.     }
  105. }
  106.  
  107. /*==============================================================================
  108. Valuta la quantita' degli elementi contenuti nell'array multidimensionale,
  109. moltiplicando tra loro le dimensioni elencate nell'array dim.
  110. Non essendo consentito l'accesso "esterno" a questa funzione, non viene
  111. effettuata alcuna verifica della validita' dei parametri.
  112. ==============================================================================*/
  113.  
  114. static size_t AMD_calcola_quantita_elementi( size_t *dim, size_t totDim ) {
  115.     size_t i, qEl;
  116.  
  117.     for( qEl=1, i=0; i<totDim; ++i )
  118.         qEl *= dim[i];
  119.  
  120.     return qEl;
  121. }
  122.  
  123. /*==============================================================================
  124. Valuta la quantita' dei puntatori che occorrera' impostare per permettere
  125. all'array multidimensionale di "funzionare" correttamente con gli operatori [].
  126.  
  127. PARAMETRI
  128.  
  129.   dim       punta a un array di valori di tipo size_t, ciascuno dei quali
  130.             rappresenta la quantita' degli elementi presenti in una delle
  131.             dimensioni di un array multidimensionale
  132.   totDim    la quantita' dei valori contenuti nell'array dim
  133.   dimIn     indice in dim della dimensione dalla quale iniziare il conteggio
  134.             (NON e' zero based! l'indice alla prima dimensione e' 1, non 0!)
  135.   exQp      la quantita' dei puntatori rilevata valutando la dimensione
  136.             precedente (la funzione e' ricorsiva)
  137.  
  138. Non essendo consentito l'accesso "esterno" a questa funzione, non viene
  139. effettuata alcuna verifica della validita' dei parametri.
  140.  
  141. VALORE DI RITORNO
  142. Restituisce la quantita' dei puntatori occorrenti per implementare l'array
  143. multidimensionale corrispondente ai parametri.
  144. ==============================================================================*/
  145.  
  146. static size_t AMD_calcola_quantita_puntatori(
  147.     size_t *dim, size_t totDim, size_t dimIn, size_t exQp ) {
  148.     if( 1==totDim ) return 0; // con una sola dimensione, non servono
  149.                               // calcoli, ne' puntatori "ausiliari"
  150.  
  151.     if( dimIn<totDim ) {
  152.         size_t i, qp;
  153.  
  154.         for( qp=1, i=0; i<dimIn; ++i )
  155.             qp *= dim[i];
  156.  
  157.         return AMD_calcola_quantita_puntatori( dim, totDim, dimIn+1, exQp+qp );
  158.     }
  159.  
  160.     return exQp;
  161. }
  162.  
  163. /*==============================================================================
  164. Crea un array multidimensionale con le caratteristiche richieste tramite i
  165. parametri qElXdim, totDim e dimEl, allocando la memoria dinamica necessaria e
  166. compilando opportunamente i campi della struttura puntata dal parametro amd.
  167. La struttura puntata da amd, in ingresso deve avere almeno i campi d e qElXDim
  168. azzerati (valore NULL).
  169. Il parametro qElXDim non puo' essere NULL, ne' puo' essere 0 alcuno dei valori
  170. contenuti nell'array da esso puntato.
  171. Il parametro totDim, che non puo' essere 0, deve esplicitare la quantita' dei
  172. valori contenuti nell'array puntato da qElXDim.
  173. Il parametro totDim, che non puo' essere 0, deve esplicitare la dimensione in
  174. byte d'ogni singolo elemento dell'array da creare.
  175. In caso di successo, la funzione restituisce AMDErr_NoErr e i campi della
  176. struttura puntata dal parametro amd sono correttamente compilati. L'array
  177. definito da detta struttura dev'essere distrutto dal chiamante, tramite la
  178. funzione AMD_Distruggi().
  179. In caso di errore, il valore di ritorno e' un codice che identifica il problema
  180. incontrato, la struttura puntata dal parametro amd non viene modificata e
  181. nessuna memoria viene allocata.
  182. ==============================================================================*/
  183.  
  184. static int AMD_crea_da_array_dimensioni(
  185.     AMD_ptr amd, size_t dimEl, size_t *qElXDim, size_t totDim ) {
  186.     void *dTmp;
  187.     size_t *qElXDimTmp;
  188.     size_t qDati;   // quantita' di elementi nell'array
  189.     size_t qPtrs;   // quantita' di puntatori
  190.     size_t memDati; // quantita' di memoria occupata dai dati (in bytes)
  191.     size_t memPtrs; // quantita' di memoria occupata dai puntatori (in bytes)
  192.  
  193.     if( !amd )
  194.         return AMDErr_PtrNULL;         // parametri NULL
  195.     if( !dimEl )
  196.         return AMDErr_DimElZeroByte;   // array di elementi da 0 byte?
  197.     if( !totDim )
  198.         return AMDErr_ZeroDimensioni;  // array "zero dimensionale"?
  199.     if( amd->d || amd->qElXDim )
  200.         return AMDErr_DatiGiaPresenti; // la struttura m contiene gia' dati?
  201.  
  202.     if( !(qDati=AMD_calcola_quantita_elementi(qElXDim,totDim)) )
  203.         return AMDErr_DimensioneZero; // una delle dimensioni ha 0 elementi
  204.     memDati = qDati*dimEl;
  205.  
  206.     qPtrs = AMD_calcola_quantita_puntatori( qElXDim, totDim, 1, 0 );
  207.     memPtrs = qPtrs*AMD_SizeofPtr;
  208.  
  209.     dTmp = malloc( memPtrs+memDati );
  210.  
  211.     if( dTmp ) {
  212.         qElXDimTmp = calloc( totDim, sizeof(*qElXDimTmp) );
  213.  
  214.         if( qElXDimTmp ) {
  215.             memset( dTmp, 0, memPtrs+memDati );
  216.  
  217.             if( 1<totDim ) // solo se l'array e' multidimensionale
  218.                 AMD_imposta_ptr( dTmp, qPtrs, qDati, dimEl, qElXDim, totDim );
  219.  
  220.             memcpy( qElXDimTmp, qElXDim, totDim*sizeof(*qElXDimTmp) );
  221.  
  222.             amd->d       = dTmp;
  223.             amd->qElXDim = qElXDimTmp;
  224.             amd->totDim  = totDim;
  225.             amd->dimEl   = dimEl;
  226.  
  227.             return AMDErr_NoErr;
  228.         }
  229.  
  230.         free( dTmp );
  231.     }
  232.  
  233.     return AMDErr_NoMem;   // allocazione fallita
  234. }
  235.  
  236. /*==============================================================================
  237. Verifica quali campi della struttura puntata da amd sono o non sono azzerati.
  238. Nel valore di ritorno, i bit (a partire dal meno significativo) sono impostati
  239. se il campo di amd corrispondente non e' azzerato, non impostati se il campo di
  240. amd corrispondente e' azzerato.
  241.  
  242.   Nota: se tutti i campi sono azzerati, st e' AMD_TuttiCampiZero (cioe' 0)
  243.         se nessun campo e' azzerato, st e' AMD_NoCampiZero (cioe' 15)
  244.  
  245. Se il puntatore amd e' NULL, il valore di ritorno e' AMD_UIntMenoUno.
  246. ==============================================================================*/
  247.  
  248. static unsigned int AMD_stato_azzeramento_campi( const AMD_ptr amd ) {
  249.     if( NULL != amd ) {
  250.         unsigned int stato = AMD_TuttiCampiZero;
  251.  
  252.         // il I bit corrisponde al campo d
  253.         stato |= AMD_Bit_d * (NULL!=amd->d);
  254.         // il II bit corrisponde al campo qElXDim
  255.         stato |= AMD_Bit_qElXDim * (NULL!=amd->qElXDim);
  256.         // il III bit corrisponde al campo totDim
  257.         stato |= AMD_Bit_totDim * (0!=amd->totDim);
  258.         // il IV bit corrisponde al campo dimEl
  259.         stato |= AMD_Bit_dimEl * (0!=amd->dimEl);
  260.  
  261.         return stato;
  262.     }
  263.  
  264.     return AMD_UIntMenoUno; // solo se amd e' NULL
  265. }
  266.  
  267. /*==============================================================================
  268. Confronta le strutture puntate da s1 e s2 per verificare se definiscono due
  269. array con le stesse dimensioni.
  270. In caso le dimensioni coincidano, il valore di ritorno e' 1 (per "true", le due
  271. strutture sono compatibili); in caso contrario il valore di ritorno e' 0 (per
  272. "false", ler due strutture sono incompatibili).
  273. Il valore di ritorno e' 0 anche nel caso in cui il confronto sia impossibile
  274. (parametri NULL) o qualche campo sia azzerato.
  275. ==============================================================================*/
  276.  
  277. static int AMD_strutture_compatibili( const AMD_ptr s1, const AMD_ptr s2 ) {
  278.     unsigned int st1 = AMD_stato_azzeramento_campi( s1 );
  279.     unsigned int st2 = AMD_stato_azzeramento_campi( s2 );
  280.  
  281.     if( AMD_UIntMenoUno!=st1 && AMD_UIntMenoUno!=st2 ) {
  282.         if( AMD_NoCampiZero==st1 && AMD_NoCampiZero==st2 ) {
  283.             if( s1->totDim==s2->totDim && s1->dimEl==s2->dimEl ) {
  284.                 size_t i;
  285.  
  286.                 for( i=0; i<s1->totDim; ++i )
  287.                     if( s1->qElXDim[i] != s2->qElXDim[i] )
  288.                         return 0;
  289.  
  290.                 return 1;
  291.             }
  292.         }
  293.     }
  294.  
  295.     return 0;
  296. }
  297.  
  298. /// ===> FUNZIONI DISPONIBILI PER L'UTENTE <====================================
  299.  
  300. /*==============================================================================
  301. Sostituisce i dati dell'array definito dalla struttura puntata dal parametro
  302. "copia" con quelli dell'array definito dalla struttura puntata dal parametro
  303. "originale".
  304. In caso la copia avvenga con successo, il valore di ritorno e' AMDErr_NoErr.
  305. In caso d'errore, il valore di ritorno e' un codice che definisce il problema
  306. nel quale e' incappata la funzione.
  307. ==============================================================================*/
  308.  
  309. int AMD_Copia( AMD_ptr copia, const AMD_ptr originale ) {
  310.     if( copia && originale ) {
  311.         if( AMD_strutture_compatibili(copia,originale) ) {
  312.             memcpy( AMD_InizioSpazioDati( copia ),
  313.                     AMD_InizioSpazioDati( originale ),
  314.                     AMD_DimensioniSpazioDati( originale ) );
  315.             return AMDErr_NoErr;
  316.         }
  317.  
  318.         return AMDErr_StruttureNonCompatibili;
  319.     }
  320.  
  321.     return AMDErr_PtrNULL;
  322. }
  323.  
  324. /*==============================================================================
  325. Restituisce la quantita' complessiva degli elementi contenuti nell'array.
  326. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  327. array valido.
  328. ==============================================================================*/
  329.  
  330. size_t AMD_QuantitaElementi( const AMD_ptr amd ) {
  331.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  332.         return AMD_calcola_quantita_elementi( amd->qElXDim, amd->totDim );
  333.     return 0;
  334. }
  335.  
  336. /*==============================================================================
  337. Restituisce la quantita' dei puntatori usati per rendere possibile l'impiego
  338. dell'array con l'operatore [].
  339. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  340. array valido.
  341. ==============================================================================*/
  342.  
  343. size_t AMD_QuantitaPuntatori( const AMD_ptr amd ) {
  344.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  345.         return AMD_calcola_quantita_puntatori( amd->qElXDim, amd->totDim, 1,0 );
  346.     return 0;
  347. }
  348.  
  349. /*==============================================================================
  350. Restituisce la quantita' di memoria complessivamente allocata, quella il
  351. puntatore alla quale e' memorizzato nel campo amd->d.
  352. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  353. array valido.
  354. ==============================================================================*/
  355.  
  356. size_t AMD_DimensioniMemoriaAllocata( const AMD_ptr amd ) {
  357.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  358.         return AMD_DimensioniSpazioPuntatori(amd)+AMD_DimensioniSpazioDati(amd);
  359.     return 0;
  360. }
  361.  
  362. /*==============================================================================
  363. Restituisce la quantita' di memoria che, nell'ambito di quella complessivamente
  364. allocata in amd->d, e' destinata all'immagazzinamento dei puntatori usati per
  365. rendere possibile l'impiego dell'array con l'operatore [].
  366. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  367. array valido.
  368. ==============================================================================*/
  369.  
  370. size_t AMD_DimensioniSpazioPuntatori( const AMD_ptr amd ) {
  371.    if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) ) {
  372.       size_t qp = AMD_calcola_quantita_puntatori(amd->qElXDim,amd->totDim,1,0);
  373.       return qp*AMD_SizeofPtr;
  374.    }
  375.  
  376.    return 0;
  377. }
  378.  
  379. /*==============================================================================
  380. Restituisce la quantita' di memoria che, nell'ambito di quella complessivamente
  381. allocata in amd->d, e' destinata all'immagazzinamento dei dati dell'array.
  382. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  383. array valido.
  384. ==============================================================================*/
  385.  
  386. size_t AMD_DimensioniSpazioDati( const AMD_ptr amd ) {
  387.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  388.         return AMD_QuantitaElementi(amd) * amd->dimEl;
  389.     return 0;
  390. }
  391.  
  392. /*==============================================================================
  393. Restituisce un puntatore al punto ove, nell'ambito della memoria
  394. complessivamente allocata in amd->d, ha inizio lo spazio destinato
  395. all'immagazzinamento dei dati dell'array.
  396. Un valore di ritorno NULL indica chiaramente una condizione inaccettabile per un
  397. array valido.
  398. ==============================================================================*/
  399.  
  400. void *AMD_InizioSpazioDati( const AMD_ptr amd ) {
  401.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  402.         return amd->d + AMD_DimensioniSpazioPuntatori(amd);
  403.     return NULL;
  404. }
  405.  
  406. /*==============================================================================
  407. Crea un array multidimensionale con le caratteristiche richieste tramite i
  408. parametri dimEl, totDim e i parametri in quantita' variabile successivi, il
  409. valore di ciascuno dei quali indica la profondita' di una dimensione, a partire
  410. da quella piu' "esterna". Alloca la memoria dinamica necessaria e compila
  411. opportunamente i campi della struttura puntata dal parametro amd.
  412. La struttura puntata da amd, in ingresso deve avere almeno i campi d e qElXDim
  413. azzerati (valore NULL).
  414. Il parametro dimEl, che non puo' essere 0, deve esplicitare la dimensione in
  415. byte d'ogni singolo elemento dell'array da creare.
  416. Il parametro totDim, che non puo' essere 0, deve esplicitare la quantita' dei
  417. parametri successivi.
  418. Il valore di essuno dei parametri successivi a totDim puo' essere 0.
  419. In caso di successo, la funzione restituisce AMDErr_NoErr e i campi della
  420. struttura puntata dal parametro amd sono correttamente compilati. L'array
  421. definito da detta struttura dev'essere distrutto dal chiamante, tramite la
  422. funzione AMD_Distruggi().
  423. In caso di errore, il valore di ritorno e' un codice che identifica il problema
  424. incontrato, la struttura puntata dal parametro amd non viene modificata e
  425. nessuna memoria viene allocata.
  426. ==============================================================================*/
  427.  
  428. int AMD_Crea( AMD_ptr amd, size_t dimEl, size_t totDim, ... ) {
  429.     int errore = AMDErr_NoErr;
  430.  
  431.     size_t *qElXDimTmp = calloc( totDim, sizeof(*qElXDimTmp) );
  432.  
  433.     if( qElXDimTmp ) {
  434.         size_t i;
  435.  
  436.         va_list arg_ptr;
  437.         va_start( arg_ptr, totDim );
  438.  
  439.         for( i=0; i<totDim; ++i )
  440.             qElXDimTmp[i] = va_arg( arg_ptr, size_t );
  441.  
  442.         va_end( arg_ptr );
  443.  
  444.         errore = AMD_crea_da_array_dimensioni( amd, dimEl, qElXDimTmp, totDim );
  445.  
  446.         free( qElXDimTmp ); qElXDimTmp = NULL;
  447.     }
  448.  
  449.     return errore;   // allocazione fallita
  450. }
  451.  
  452. /*==============================================================================
  453. Crea un duplicato dell'array multidimensionale definito dalla struttura puntata
  454. dal parametro "originale". La creazione del duplicato avviene con una chiamata a
  455. AMD_crea_da_array_dimensioni(). I dati dell'array originale vengono copiati nel
  456. nuovo array con una chiamata a AMD_Copia().
  457. In caso di successo, la funzione restituisce AMDErr_NoErr e la struttura puntata
  458. dal parametro "duplicato" definisce l'array duplicato appena creato. L'array
  459. definito da detta struttura dev'essere distrutto dal chiamante, tramite la
  460. funzione AMD_Distruggi().
  461. In caso di errore, il valore di ritorno e' un codice che identifica il problema
  462. incontrato, la struttura puntata dal parametro "duplicato" non viene modificata
  463. e nessuna memoria viene allocata.
  464. ==============================================================================*/
  465.  
  466. int AMD_Duplica( AMD_ptr duplicato, const AMD_ptr originale ) {
  467.    if( NULL == duplicato || NULL == originale ) return AMDErr_PtrNULL;
  468.  
  469.    if( AMD_NoCampiZero==AMD_stato_azzeramento_campi(originale) ) {
  470.       int errore = AMD_crea_da_array_dimensioni(
  471.          duplicato, originale->dimEl, originale->qElXDim, originale->totDim );
  472.  
  473.       if( AMDErr_NoErr==errore )
  474.          return AMD_Copia( duplicato, originale );
  475.  
  476.       return errore;
  477.    }
  478.  
  479.    return AMDErr_StrutturaNonValida;
  480. }
  481.  
  482. /*==============================================================================
  483. Distrugge l'array multidimensionale definito dalla struttura puntata dal
  484. parametro amd. La struttura puntata dal parametro amd deve derivare da una
  485. precedente chiamata a una delle due funzioni AMD_Crea() e AMD_Duplica().
  486. In caso di successo, la funzione restituisce AMDErr_NoErr, tutti i campi della
  487. struttura puntata dal parametro amd sono azzerati e tutta la memoria dinamica
  488. connessa all'array e' deallocata.
  489. In caso di errore, il valore di ritorno e' un codice che identifica il problema
  490. incontrato, la struttura puntata dal parametro amd non viene modificata, e
  491. nessuna memoria viene deallocata.
  492. ==============================================================================*/
  493.  
  494. int AMD_Distruggi( AMD_ptr amd ) {
  495.     unsigned int stato = AMD_stato_azzeramento_campi( amd );
  496.  
  497.     if( AMD_UIntMenoUno != stato ) {
  498.         if( AMD_NoCampiZero == stato ) {
  499.             if( amd->d )
  500.                 free( amd->d );
  501.  
  502.             if( amd->qElXDim )
  503.                 free( amd->qElXDim );
  504.  
  505.             memset( amd, 0, sizeof(*amd) );
  506.  
  507.             return AMDErr_NoErr;
  508.         }
  509.  
  510.         return AMDErr_StrutturaNonValida;
  511.     }
  512.  
  513.     return AMDErr_PtrNULL; // parametro NULL
  514. }
  515.  
  516. const char *AMD_DescrizioneErrore( int codice ) {
  517.     const char *kStrErr[AMD_MaxErr] = {
  518.         "nessun errore",
  519.         "puntatore NULL",
  520.         "allocazione di memoria fallita",
  521.         "la struttura pare contenere già dei dati",
  522.         "impossibile creare un array a zero dimensioni",
  523.         "nessuna delle dimensioni di un array può essere zero",
  524.         "le dimensioni degli elementi dell'array non possono essere zero",
  525.         "la struttura non è valida",
  526.         "le due strutture non sono tra loro compatibili"
  527.     };
  528.  
  529.     if( codice >= 0 && codice < AMD_MaxErr )
  530.         return kStrErr[codice];
  531.     else return "errore imprevisto";
  532. }



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
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 1:44
Lunedì, 12/08/2019
Non capisco il senso di questo codice. Cioè a parte il fatto che è divertente scriverlo che vantaggio ha rispetto a fare int*a= malloc(4*3*5*7) *(a+20) ?

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 19:46
Lunedì, 12/08/2019
Prima di risponderti dovrei capire cosa significa la formula che mi proponi, perché mi sfugge. Dal momento che mi sfugge, ho provato a inserirla in un programmino di prova per poi analizzare quel che ne veniva fuori, ma il compilatore mi ha mandato a stendere con un errore che dice: "invalid operands to binary * (have 'void *' and 'int *')". A parte l'errore, che magari hai sbagliato a battere la formula, cosa mi sto perdendo? Mi spieghi da dove nasce, cosa c'è dietro che mi sfugge?

E comunque, il mio codice sembra funzionare "a rate". Devo revisionarlo.


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
Ultimo (Member)
Guru


Messaggi: 877
Iscritto: 22/05/2010

Segnala al moderatore
Postato alle 23:48
Lunedì, 12/08/2019
Testo quotato

Postato originariamente da AldoBaldo:

Prima di risponderti dovrei capire cosa significa la formula che mi proponi, perché mi sfugge. Dal momento che mi sfugge, ho provato a inserirla in un programmino di prova per poi analizzare quel che ne veniva fuori, ma il compilatore mi ha mandato a stendere con un errore che dice: "invalid operands to binary * (have 'void *' and 'int *')". A parte l'errore, che magari hai sbagliato a battere la formula, cosa mi sto perdendo? Mi spieghi da dove nasce, cosa c'è dietro che mi sfugge?

E comunque, il mio codice sembra funzionare "a rate". Devo revisionarlo.



:k:



If ok Then GOTO Avanza else GOTO Inizia

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 0:08
Martedì, 13/08/2019
Testo quotato

Postato originariamente da AldoBaldo:
Prima di risponderti dovrei capire cosa significa la formula che mi proponi, perché mi sfugge. Dal momento che mi sfugge, ho provato a inserirla in un programmino di prova per poi analizzare quel che ne veniva fuori, ma il compilatore mi ha mandato a stendere con un errore che dice: "invalid operands to binary * (have 'void *' and 'int *')". A parte l'errore, che magari hai sbagliato a battere la formula, cosa mi sto perdendo? Mi spieghi da dove nasce, cosa c'è dietro che mi sfugge?

E comunque, il mio codice sembra funzionare "a rate". Devo revisionarlo.


int *a= malloc(3*4*5*2*sizeof(int)); vedilo come un  array [3][4][5][2]
int valCella=*(a+2*4*5*2+3*5*2+1) ; Equivale ad a[2][3][.... Scusa ma non ho voglia di fare il conto. Chiedo perdono

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 13:09
Martedì, 13/08/2019
A proposito del "funzionamento a rate", ho trovato l'inghippo e ho capito in cosa consiste l'errore: sta in AMD_imposta_ptr(). Ora devo trovare il modo per correggerlo -- so già dove devo arrivare, ma devo trovare la strada per arrivarci. Sono ottimista!

@TheDarkJuster
Ma che "perdono"! Mica hai obblighi, eh, è già tanto che tu abbia deciso di rispondermi, cosa che apprezzo. Ora mi metto lì e cerco di capire cosa mi stai dicendo (per ora ho solo preso atto del fatto che c'è un tuo intervento, poi ti dirò).


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
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 13:47
Martedì, 13/08/2019
int *a = malloc(3*4*5*2*sizeof(int));
vedilo come un  array [3][4][5][2]

int valCella = *(a+2*4*5*2+3*5*2+1);
Equivale ad a[2][3][....

@ TheDarkJuster
Allora... detta terra terra: non son certo d'aver capito ma credo di sì.

Parti con un puntatore ad int, che indica l'inizio di un blocco di memoria di 3*4*5*2*sizeof(int) byte. Può essere lo spazio nel quale memorizzare 3*4*5*2=120 valori di tipo int. Se sizeof(int) sono 4 byte, allora si tratta di 480 byte in tutto. Fin qui ci arrivo.

Con la seconda formula, se non ho frainteso, mi stai dicendo che posso individuare la posizione di una certa "cella" usando l'aritmetica dei puntatori, giusto? In quel modo si può "simulare" un array multidimensionale a partire dal puntatore a. Se è questo che mi volevi dire, è cosa che mi era già nota e senza dubbio funziona.

Quel che volevo ottenere io, però, è cosa un po' diversa: a me interessa ottenere un puntatore che posso impiegare come se fosse un vero array multidimensionale, senza usare esplicitamente su di esso l'aritmetica dei puntatori. Tipo...

Codice sorgente - presumibilmente C#

  1. // non ho un...
  2. int *a;
  3. // bensì un...
  4. int ****a4dPtr;
  5.  
  6. // a4d rappresenta il punto di inizio di un array a quattro
  7. // dimensioni, e posso accedere alle "celle" dell'array a
  8. // quattro dimensioni con [][][][], tipo...
  9.  
  10. int ****a4dPtr; // ovviamente, bisognera' poi allocarne lo spazio
  11.  
  12. a4dPtr[1][1][3][1] = -23; // -23 e' un valore a caso
  13.  
  14. // l'idea era ottenere dal mio array a quattro dimensioni allocato
  15. // in memoria dinamica lo stesso comportamento che avrei ottenuto
  16. // se avessi dichiarato...
  17.  
  18. int a4d[3][4][5][2];
  19.  
  20. a4d[1][1][3][1] = -23; // -23 e' un valore a caso



Mi perdo ancora qualcosa? Perché sto camminando un po' al limite delle mie possibilità di comprensione, temo.

Per quel che ne so (dopo avere letto in passato e sperimentato in questi giorni), per avere l'equivalente di un array multidimensionale allocato dinamicamente non basta allocare lo spazio-dati, ma serve anche allocare uno spazio aggiuntivo in testa al blocco che deve contenere i puntatori che fanno riferimento alle varie dimensioni, come in una specie di matriosca.

La libreria che sto cercando di mettere insieme (senza pretesa di farne qualcosa di "professionale") dovrebbe servire a "automatizzare" in qualche misura il procedimento di allocazione della memoria, predisposizione dei puntatori "di intestazione" e conservazione in una struttura dei dati relativi alle carratteristiche dell'array multidimensionale allocato.

Sto cercando di arrivare a qualcosa che mi permetta di fare...

Codice sorgente - presumibilmente C++

  1. #include "amd.h"
  2.  
  3. int main() {
  4.     AMD_struct amd = {0};
  5.    
  6.     int errore = AMD_Crea( &amd, sizeof(int), 4, 3, 4, 5, 2 );
  7.    
  8.     if( AMDErr_NoErr == errore ) {
  9.         int ****alias4d = amd.d;
  10.        
  11.         // ora alias4d puo' essere usato con alias4d[][][][]
  12.        
  13.         AMD_Distruggi( &amd );
  14.     }    
  15. }



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
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 23:43
Sabato, 17/08/2019
Ah! Se non sto prendendo l'ennesimo abbaglio clamoroso... CE L'HO FATTA!!!

Ora la mia libreria dovrebbe funzionare con array con qualsiasi quantità di dimensioni: 1D (vettori), 2D (matrici), 3D, 4D... Le prove le ho fatte fino a 4D, e sembra che ogni cosa sia al suo posto. Visti i miei limiti, mi sono spaccato il cervello in quattro per giorni, ma ho l'impressione che finalmente dia davvero array generici e (spero) funzionanti senza sorprese.

Ecco il codice. Se qualche anima buona volesse dare un'occhiata, in particolare alla funzione AMD_imposta_ptr(), sarebbe per me rassicurante (o "devastante", dipenderebbe da cosa mi dovesse dire).

File amd.h:

Codice sorgente - presumibilmente C++

  1. /*==============================================================================
  2.          A R R A Y   M U L T I D I M E N S I O N A L E   G E N E R I C O
  3.                   di Aldo Carpanelli - v1.0.1, 17 agosto 2019
  4.  
  5. Una libreria in C che, nelle intenzioni, dovrebbe rendere piu' agevole e spedito
  6. l'uso di matrici multidimensionali allocate dinamicamente, indipendentemente dal
  7. tipo dei dati trattati.
  8. ==============================================================================*/
  9.  
  10. #ifndef AMD_H_INCLUDED
  11. #define AMD_H_INCLUDED
  12.  
  13. #ifdef __cplusplus
  14. extern "C" {
  15. #endif
  16.  
  17. #include <stdlib.h>
  18.  
  19. typedef struct {
  20.     void *d;         // puntatore allo spazio occupato in memoria da
  21.                      // dati+puntatori agli elementi dell'array
  22.     size_t *qElXDim; // quantita' di elementi per ogni dimensione dell'array
  23.     size_t totDim;   // quantita' totale delle dimensioni dell'array
  24.     size_t dimEl;    // le dimensioni (in byte) di ogni elemento dell'array
  25. } AMD_struct;        // AMD: [A]rray [M]ulti[D]imensionale
  26.  
  27. typedef AMD_struct *AMD_ptr;
  28.  
  29. enum {
  30.     AMDErr_NoErr,
  31.     AMDErr_PtrNULL,
  32.     AMDErr_NoMem,
  33.     AMDErr_DatiGiaPresenti,
  34.     AMDErr_ZeroDimensioni,
  35.     AMDErr_DimensioneZero,
  36.     AMDErr_DimElZeroByte,
  37.     AMDErr_StrutturaNonValida,
  38.     AMDErr_StruttureNonCompatibili,
  39.     AMD_MaxErr
  40. };
  41.  
  42.  
  43. int AMD_Crea( AMD_ptr amd, size_t dimEl, size_t totDim, ... );
  44. int AMD_Duplica( AMD_ptr duplicato, const AMD_ptr originale );
  45. int AMD_Distruggi( AMD_ptr amd );
  46.  
  47. int AMD_Copia( AMD_ptr copia, const AMD_ptr originale );
  48.  
  49. size_t AMD_QuantitaElementi( const AMD_ptr amd );
  50. size_t AMD_QuantitaPuntatori( const AMD_ptr amd );
  51. size_t AMD_DimensioniMemoriaAllocata( const AMD_ptr amd );
  52. size_t AMD_DimensioniSpazioPuntatori( const AMD_ptr amd );
  53. size_t AMD_DimensioniSpazioDati( const AMD_ptr amd );
  54. void  *AMD_InizioSpazioDati( const AMD_ptr amd );
  55.  
  56. const char *AMD_DescrizioneErrore( int codice );
  57.  
  58. /*==============================================================================
  59.  
  60. CAMPI DELLA STRUTTURA AMD_struct
  61.  
  62.  d        d: [d]ati dell'array
  63.           Punta allo spazio in memoria occupato dall'array;
  64.           In realta', non si tratta di un semplice puntatore, bensi' di un
  65.           puntatore a indirezione multipla, il livello di indirezione del quale
  66.           dipende dalla quantita' delle dimensioni dell'array multidimensionale.
  67.           In C, questo puntatore si puo' tranquillamente assegnare a un
  68.           int*[*...], a un char*[*...], a un float*[*...] o a qualsiasi altro
  69.           puntatore a doppia, tripla, quadrupla... indirezione a qualsiasi tipo.
  70.           In C++ si puo' fare la stessa cosa, ma occorre procedere con un cast
  71.           esplicito.
  72.  
  73.           Nota: oltre allo spazio per "ospitare" i dati, la memoria puntata da d
  74.                 ha dimensioni sufficienti a contenere "in testa" anche i
  75.                 puntatori che servono per rendere utilizzabile l'operatore []
  76.                 con l'array multidimensionale.
  77.  
  78.  qElXDim  qElXDim: [q]uantita' degli [El]ementi [X] per ogni [Dim]ensione
  79.           dell'array multidimensionale.
  80.           E' un puntatore a una serie di valori di tipo size_t, ciascuno dei
  81.           quali definisce la "profondita'" della dimensione corrispondente alla
  82.           sua posizione nella serie. Ad esempio, se qElXDim punta alla serie di
  83.           valori 3,2,4, allora l'array e' tridimensionale, con profondita' della
  84.           dimensione x pari a 4, profondita' della dimensione y pari a 2 e
  85.           profondita' della dimensione z pari a 3, per un totale di 4*3*2=24
  86.           elementi nell'array.
  87.  
  88.  totDim   totDim: [tot]ale delle [Dim]ensioni dell'array
  89.           Indica la quantita' delle dimensioni dell'array, e deve corrispondere
  90.           alla quantita' dei valori presenti nella serie puntata da qElXDim.
  91.           Ad esempio, nel caso dell'array tridimensionale appena descritto,
  92.           totDim deve essere 3.
  93.  
  94.  dimEl    dimEl: [dim]ensioni degli [El]ementi dell'array
  95.           Le dimensioni, in byte, di ciascuno degli elementi dell'array
  96.           multidimensionale.
  97.           Ad esempio, se nel caso dell'array tridimensionale appena descritto
  98.           dimEl fosse 8 (8 byte per elemento), la dimensione complessiva dei
  99.           dati dell'intero array di 4*3*2=24 elementi sarebbe di 24*8=192 byte.
  100.  
  101. ==============================================================================*/
  102.  
  103. #ifdef __cplusplus
  104. }
  105. #endif
  106.  
  107. #endif // AMD_H_INCLUDED



File amd.c:

Codice sorgente - presumibilmente C++

  1. /*==============================================================================
  2.          A R R A Y   M U L T I D I M E N S I O N A L E   G E N E R I C O
  3.                   di Aldo Carpanelli - v1.0.1, 17 agosto 2019
  4.  
  5. Una libreria in C che, nelle intenzioni, dovrebbe rendere piu' agevole e spedito
  6. l'uso di matrici multidimensionali allocate dinamicamente, indipendentemente dal
  7. tipo dei dati trattati.
  8. ==============================================================================*/
  9.  
  10. #include <string.h>
  11. #include <stdarg.h>
  12.  
  13. #include "amd.h"
  14.  
  15. static const size_t AMD_SizeofPtr = sizeof(void*);
  16. static const unsigned int AMD_UIntMenoUno = (unsigned int)-1;
  17.  
  18. // costanti usate in AMD_StatoAzzeramentoCampi()
  19. static const unsigned int AMD_Bit_d          = 1U;  // I bit
  20. static const unsigned int AMD_Bit_qElXDim    = 2U;  // II bit
  21. static const unsigned int AMD_Bit_totDim     = 4U;  // III bit
  22. static const unsigned int AMD_Bit_dimEl      = 8U;  // IV bit
  23. static const unsigned int AMD_NoCampiZero    = 15U; // nessun campo azzerato
  24. static const unsigned int AMD_TuttiCampiZero = 0U;  // tutti campi azzerati
  25.  
  26. /// ===> FUNZIONI NON DISPONIBILI PER L'UTENTE <================================
  27.  
  28. /*==============================================================================
  29. Valuta la quantita' degli elementi contenuti nell'array multidimensionale,
  30. moltiplicando tra loro le dimensioni elencate nell'array dim.
  31. Non essendo consentito l'accesso "esterno" a questa funzione, non viene
  32. effettuata alcuna verifica della validita' dei parametri.
  33. ==============================================================================*/
  34.  
  35. static size_t AMD_calcola_quantita_elementi( size_t *dim, size_t totDim ) {
  36.     size_t i, qEl;
  37.  
  38.     for( qEl=1, i=0; i<totDim; ++i )
  39.         qEl *= dim[i];
  40.  
  41.     return qEl;
  42. }
  43.  
  44. /*==============================================================================
  45. Valuta la quantita' dei puntatori che occorrera' impostare per permettere
  46. all'array multidimensionale di "funzionare" correttamente con gli operatori [].
  47.  
  48. PARAMETRI
  49.  
  50.   dim       punta a un array di valori di tipo size_t, ciascuno dei quali
  51.             rappresenta la quantita' degli elementi presenti in una delle
  52.             dimensioni di un array multidimensionale
  53.   totDim    la quantita' dei valori contenuti nell'array dim
  54.   dimIn     indice in dim della dimensione dalla quale iniziare il conteggio
  55.             (NON e' zero based! l'indice alla prima dimensione e' 1, non 0!)
  56.   exQp      la quantita' dei puntatori rilevata valutando la dimensione
  57.             precedente (la funzione e' ricorsiva)
  58.  
  59. Non essendo consentito l'accesso "esterno" a questa funzione, non viene
  60. effettuata alcuna verifica della validita' dei parametri.
  61.  
  62. VALORE DI RITORNO
  63. Restituisce la quantita' dei puntatori occorrenti per implementare l'array
  64. multidimensionale corrispondente ai parametri.
  65. ==============================================================================*/
  66.  
  67. static size_t AMD_calcola_quantita_puntatori(
  68.     size_t *dim, size_t totDim, size_t dimIn, size_t exQp ) {
  69.     if( 1==totDim ) return 0; // con una sola dimensione, non servono
  70.                               // calcoli, ne' puntatori "ausiliari"
  71.  
  72.     if( dimIn<totDim ) {
  73.         size_t i, qp;
  74.  
  75.         for( qp=1, i=0; i<dimIn; ++i )
  76.             qp *= dim[i];
  77.  
  78.         return AMD_calcola_quantita_puntatori( dim, totDim, dimIn+1, exQp+qp );
  79.     }
  80.  
  81.     return exQp;
  82. }
  83.  
  84. /*==============================================================================
  85. Viene chiamata da AMD_imposta_ptr() e colloca, nelle ultime posizioni dello
  86. spazio riservato ai puntatori, della serie dei puntatori ai gruppi di dati che
  87. costituiscono l'ultima dimensione dell'array. La collocazione dei puntatori
  88. avviene arretrando nello spazio loro riservato, a partire dalla posizione
  89. immediatamente precedente al punto nel quale inizia lo spazio riservato ai dati.
  90.  
  91. PARAMETRI
  92.  
  93.   pDati     "pDati": puntatore ai dati
  94.             puntatore alla porzione del blocco di memoria allocato dalla
  95.             funzione statica AMD_crea_da_array_dimensioni() destinato a
  96.             contenere i dati dell'array
  97.  
  98.   qBlocchi  "qBlocchi": quantita' dei blocchi di dati
  99.             la quantita' degli elementi dell'array contenuti in ciascuno dei
  100.             gruppi di dati della sua ultima dimensione
  101.  
  102.   dimBlocco "dimBlocco": dimensione d'ognuno dei blocchi di dati
  103.             in byte, indica la quantita' di memoria occupata dagli elementi
  104.             dell'array contenuti in ciascuno dei qBlocchi blocchi di dati
  105. ==============================================================================*/
  106.  
  107. static void AMD_crea_indirezioni_blocchi_dati(
  108.     void *pDati, size_t qBlocchi, size_t dimBlocco ) {
  109.     void *srg = pDati + qBlocchi*dimBlocco;
  110.     void *dst = pDati;
  111.     size_t i;
  112.  
  113.     for( i=0; i<qBlocchi; ++i ) {
  114.         dst -= AMD_SizeofPtr;
  115.         srg -= dimBlocco;
  116.         memcpy( dst, &srg, AMD_SizeofPtr );
  117.     }
  118. }
  119.  
  120. /*==============================================================================
  121. Viene chiamata da AMD_imposta_ptr() e colloca, nello spazio riservato ai
  122. puntatori non ancora sfruttato da AMD_crea_indirezioni_blocchi_dati(), della
  123. serie dei puntatori a indirezione multipla occorrenti per permettere l'uso
  124. dell'array con l'operatore[].
  125.  
  126. PARAMETRI
  127.  
  128.   pPtrs     "pPtrs": puntatore ai puntatori
  129.             puntatore alla posizione dalla quale cominciare l'operazione di
  130.             individuazione delle indirezioni
  131.  
  132.   qElXDim   "qElXDim": quantita' degli elementi per dimensione
  133.             la quantita' degli elementi per ciascuna dimensione dell'array, a
  134.             partire da quella utile per l'operazione di indirezione in corso
  135.  
  136.   offset    "offset": scostamento rispetto al primo puntatore
  137.             indica quanti puntatori sono gia' stati collocati con la corretta
  138.             indirezione PRIMA di quelli che verranno ulteriormente aggiunti
  139.   iter      "iter": abbreviato per "iterazioni"
  140.             indica quante iterazioni devono ancora essere affrontate prima che
  141.             sia completato il processo di individuazione delle indirezioni
  142. ==============================================================================*/
  143.  
  144. static void AMD_completa_indirezioni( void *pPtrs, size_t *qElXDim,
  145.                                       size_t offset, size_t iter ) {
  146.     if( iter ) {
  147.         size_t o = offset*qElXDim[0];
  148.         size_t d1 = qElXDim[1];
  149.         size_t i;
  150.  
  151.         void *src = pPtrs + o*AMD_SizeofPtr;
  152.  
  153.         for( i=0; i<o; ++i ) {
  154.             memcpy( pPtrs, &src, AMD_SizeofPtr );
  155.             pPtrs += AMD_SizeofPtr;
  156.             src += d1*AMD_SizeofPtr;
  157.         }
  158.  
  159.         AMD_completa_indirezioni( pPtrs, qElXDim+1, o, iter-1 );
  160.     }
  161. }
  162.  
  163. /*==============================================================================
  164. Viene chiamata solo se l'array ha piu' di una dimensione (con totDim>1).
  165. Compila lo spazio riservato ai puntatori nell'ambito della memoria allocata per
  166. un array multidimensionale, cosi' da rendere successivamente possibile con esso
  167. l'impiego dell'operatore [].
  168.  
  169. PARAMETRI
  170.  
  171.   pPtrs     "pPtrs": puntatore ai puntatori
  172.             puntatore al blocco di memoria allocato dalla funzione statica
  173.             AMD_crea_da_array_dimensioni();
  174.             in uscita, in testa al blocco si trovera' la schiera dei puntatori
  175.             necessari a rendere utilizzabile la matrice multidimensionale con
  176.             gli operatori []
  177.  
  178.   qPtrs     "qPtrs": quantita' dei puntatori
  179.             la quantita' dei puntatori che devono essere collocati in testa al
  180.             blocco di memoria puntato da pPtrs
  181.  
  182.   qDati     "qDati": quantita' dei dati
  183.             la quantita' complessiva degli elementi presenti nell'intera matrice
  184.             multidimensionale; equivale al prodotto di tutte le dimensioni della
  185.             matrice stessa, come elencate in qElXDim
  186.  
  187.   dimEl     "dimEl": dimensioni dell'elemento
  188.             le dimensioni d'ognuno dei qDati elementi presenti nell'intera
  189.             matrice multidimensionale
  190.  
  191.   qElXDim   "qElXDim": quantita' di elementi per ogni dimensione
  192.             puntatore a un array di valori di tipo size_t, ciascuno dei quali
  193.             rappresenta la quantita' di elementi presenti in una determinata
  194.             dimensione dell'array multidimensionale; le dimensioni sono elencate
  195.             nell'array in ordine da quella piu' esterna (in posizione [0]) a
  196.             quella piu' interna (in posizione [totDim-1])
  197.  
  198.   totDim    "totDim": quantita' totale delle dimensioni
  199.             la quantita' totale delle dimensioni della matrice multidimensionale
  200.             l'array di size_t puntato da qElXDim ha totDim elementi
  201. ==============================================================================*/
  202.  
  203. static void AMD_imposta_ptr( void *pPtrs, size_t qPtrs,
  204.                              size_t qDati, size_t dimEl,
  205.                              size_t *qElXDim, size_t totDim ) {
  206.     void *pDati; // pDati: il punto nel quale iniziano i dati
  207.     size_t dimBlocco, qBlocchi; // vedi sotto
  208.  
  209.     // lo spazio dei dati comincia subito
  210.     // dopo lo spazio riservato ai puntatori
  211.     pDati = pPtrs + qPtrs*AMD_SizeofPtr;
  212.  
  213.     // ogni gruppo dei dati contenuti nell'ultima
  214.     // dimensione dell'array occupa dimBlocco byte
  215.     dimBlocco = qElXDim[totDim-1]*dimEl;
  216.  
  217.     // esistono qBlocchi blocchi di dati,
  218.     // ciascuno grande dimBlocco byte
  219.     qBlocchi = qDati/qElXDim[totDim-1];
  220.  
  221.     // per cominciare, posizioniamo i puntatori ai blocchi dei dati
  222.     // nella parte terminale dello spazio riservato ai puntatori
  223.     AMD_crea_indirezioni_blocchi_dati( pDati, qBlocchi, dimBlocco );
  224.  
  225.     // posizioniamo le indirezioni riferite alle dimensioni rimanenti
  226.     AMD_completa_indirezioni( pPtrs, qElXDim, 1, totDim-2 );
  227. }
  228.  
  229. /*==============================================================================
  230. Crea un array multidimensionale con le caratteristiche richieste tramite i
  231. parametri qElXdim, totDim e dimEl, allocando la memoria dinamica necessaria e
  232. compilando opportunamente i campi della struttura puntata dal parametro amd.
  233. La struttura puntata da amd, in ingresso deve avere almeno i campi d e qElXDim
  234. azzerati (valore NULL).
  235. Il parametro qElXDim non puo' essere NULL, ne' puo' essere 0 alcuno dei valori
  236. contenuti nell'array da esso puntato.
  237. Il parametro totDim, che non puo' essere 0, deve esplicitare la quantita' dei
  238. valori contenuti nell'array puntato da qElXDim.
  239. Il parametro totDim, che non puo' essere 0, deve esplicitare la dimensione in
  240. byte d'ogni singolo elemento dell'array da creare.
  241. In caso di successo, la funzione restituisce AMDErr_NoErr e i campi della
  242. struttura puntata dal parametro amd sono correttamente compilati. L'array
  243. definito da detta struttura dev'essere distrutto dal chiamante, tramite la
  244. funzione AMD_Distruggi().
  245. In caso di errore, il valore di ritorno e' un codice che identifica il problema
  246. incontrato, la struttura puntata dal parametro amd non viene modificata e
  247. nessuna memoria viene allocata.
  248. ==============================================================================*/
  249.  
  250. static int AMD_crea_da_array_dimensioni(
  251.     AMD_ptr amd, size_t dimEl, size_t *qElXDim, size_t totDim ) {
  252.     void *dTmp;
  253.     size_t *qElXDimTmp;
  254.     size_t qDati;   // quantita' di elementi nell'array
  255.     size_t qPtrs;   // quantita' di puntatori
  256.     size_t memDati; // quantita' di memoria occupata dai dati (in bytes)
  257.     size_t memPtrs; // quantita' di memoria occupata dai puntatori (in bytes)
  258.  
  259.     if( !amd )
  260.         return AMDErr_PtrNULL;         // parametri NULL
  261.     if( !dimEl )
  262.         return AMDErr_DimElZeroByte;   // array di elementi da 0 byte?
  263.     if( !totDim )
  264.         return AMDErr_ZeroDimensioni;  // array "zero dimensionale"?
  265.     if( amd->d || amd->qElXDim )
  266.         return AMDErr_DatiGiaPresenti; // la struttura m contiene gia' dati?
  267.  
  268.     if( !(qDati=AMD_calcola_quantita_elementi(qElXDim,totDim)) )
  269.         return AMDErr_DimensioneZero; // una delle dimensioni ha 0 elementi
  270.     memDati = qDati*dimEl;
  271.  
  272.     qPtrs = AMD_calcola_quantita_puntatori( qElXDim, totDim, 1, 0 );
  273.     memPtrs = qPtrs*AMD_SizeofPtr;
  274.  
  275.     dTmp = malloc( memPtrs+memDati );
  276.  
  277.     if( dTmp ) {
  278.         qElXDimTmp = calloc( totDim, sizeof(*qElXDimTmp) );
  279.  
  280.         if( qElXDimTmp ) {
  281.             memset( dTmp, 0, memPtrs+memDati );
  282.  
  283.             if( 1<totDim ) // solo se l'array e' multidimensionale
  284.                 AMD_imposta_ptr( dTmp, qPtrs, qDati, dimEl, qElXDim, totDim );
  285.  
  286.             memcpy( qElXDimTmp, qElXDim, totDim*sizeof(*qElXDimTmp) );
  287.  
  288.             amd->d       = dTmp;
  289.             amd->qElXDim = qElXDimTmp;
  290.             amd->totDim  = totDim;
  291.             amd->dimEl   = dimEl;
  292.  
  293.             return AMDErr_NoErr;
  294.         }
  295.  
  296.         free( dTmp );
  297.     }
  298.  
  299.     return AMDErr_NoMem;   // allocazione fallita
  300. }
  301.  
  302. /*==============================================================================
  303. Verifica quali campi della struttura puntata da amd sono o non sono azzerati.
  304. Nel valore di ritorno, i bit (a partire dal meno significativo) sono impostati
  305. se il campo di amd corrispondente non e' azzerato, non impostati se il campo di
  306. amd corrispondente e' azzerato.
  307.  
  308.   Nota: se tutti i campi sono azzerati, st e' AMD_TuttiCampiZero (cioe' 0)
  309.         se nessun campo e' azzerato, st e' AMD_NoCampiZero (cioe' 15)
  310.  
  311. Se il puntatore amd e' NULL, il valore di ritorno e' AMD_UIntMenoUno.
  312. ==============================================================================*/
  313.  
  314. static unsigned int AMD_stato_azzeramento_campi( const AMD_ptr amd ) {
  315.     if( NULL != amd ) {
  316.         unsigned int stato = AMD_TuttiCampiZero;
  317.  
  318.         // il I bit corrisponde al campo d
  319.         stato |= AMD_Bit_d * (NULL!=amd->d);
  320.         // il II bit corrisponde al campo qElXDim
  321.         stato |= AMD_Bit_qElXDim * (NULL!=amd->qElXDim);
  322.         // il III bit corrisponde al campo totDim
  323.         stato |= AMD_Bit_totDim * (0!=amd->totDim);
  324.         // il IV bit corrisponde al campo dimEl
  325.         stato |= AMD_Bit_dimEl * (0!=amd->dimEl);
  326.  
  327.         return stato;
  328.     }
  329.  
  330.     return AMD_UIntMenoUno; // solo se amd e' NULL
  331. }
  332.  
  333. /*==============================================================================
  334. Confronta le strutture puntate da s1 e s2 per verificare se definiscono due
  335. array con le stesse dimensioni.
  336. In caso le dimensioni coincidano, il valore di ritorno e' 1 (per "true", le due
  337. strutture sono compatibili); in caso contrario il valore di ritorno e' 0 (per
  338. "false", ler due strutture sono incompatibili).
  339. Il valore di ritorno e' 0 anche nel caso in cui il confronto sia impossibile
  340. (parametri NULL) o qualche campo sia azzerato.
  341. ==============================================================================*/
  342.  
  343. static int AMD_strutture_compatibili( const AMD_ptr s1, const AMD_ptr s2 ) {
  344.     unsigned int st1 = AMD_stato_azzeramento_campi( s1 );
  345.     unsigned int st2 = AMD_stato_azzeramento_campi( s2 );
  346.  
  347.     if( AMD_UIntMenoUno!=st1 && AMD_UIntMenoUno!=st2 ) {
  348.         if( AMD_NoCampiZero==st1 && AMD_NoCampiZero==st2 ) {
  349.             if( s1->totDim==s2->totDim && s1->dimEl==s2->dimEl ) {
  350.                 size_t i;
  351.  
  352.                 for( i=0; i<s1->totDim; ++i )
  353.                     if( s1->qElXDim[i] != s2->qElXDim[i] )
  354.                         return 0;
  355.  
  356.                 return 1;
  357.             }
  358.         }
  359.     }
  360.  
  361.     return 0;
  362. }
  363.  
  364. /// ===> FUNZIONI DISPONIBILI PER L'UTENTE <====================================
  365.  
  366. /*==============================================================================
  367. Sostituisce i dati dell'array definito dalla struttura puntata dal parametro
  368. "copia" con quelli dell'array definito dalla struttura puntata dal parametro
  369. "originale".
  370. In caso la copia avvenga con successo, il valore di ritorno e' AMDErr_NoErr.
  371. In caso d'errore, il valore di ritorno e' un codice che definisce il problema
  372. nel quale e' incappata la funzione.
  373. ==============================================================================*/
  374.  
  375. int AMD_Copia( AMD_ptr copia, const AMD_ptr originale ) {
  376.     if( copia && originale ) {
  377.         if( AMD_strutture_compatibili(copia,originale) ) {
  378.             memcpy( AMD_InizioSpazioDati( copia ),
  379.                     AMD_InizioSpazioDati( originale ),
  380.                     AMD_DimensioniSpazioDati( originale ) );
  381.             return AMDErr_NoErr;
  382.         }
  383.  
  384.         return AMDErr_StruttureNonCompatibili;
  385.     }
  386.  
  387.     return AMDErr_PtrNULL;
  388. }
  389.  
  390. /*==============================================================================
  391. Restituisce la quantita' complessiva degli elementi contenuti nell'array.
  392. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  393. array valido.
  394. ==============================================================================*/
  395.  
  396. size_t AMD_QuantitaElementi( const AMD_ptr amd ) {
  397.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  398.         return AMD_calcola_quantita_elementi( amd->qElXDim, amd->totDim );
  399.     return 0;
  400. }
  401.  
  402. /*==============================================================================
  403. Restituisce la quantita' dei puntatori usati per rendere possibile l'impiego
  404. dell'array con l'operatore [].
  405. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  406. array valido.
  407. ==============================================================================*/
  408.  
  409. size_t AMD_QuantitaPuntatori( const AMD_ptr amd ) {
  410.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  411.         return AMD_calcola_quantita_puntatori( amd->qElXDim, amd->totDim, 1,0 );
  412.     return 0;
  413. }
  414.  
  415. /*==============================================================================
  416. Restituisce la quantita' di memoria complessivamente allocata, quella il
  417. puntatore alla quale e' memorizzato nel campo amd->d.
  418. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  419. array valido.
  420. ==============================================================================*/
  421.  
  422. size_t AMD_DimensioniMemoriaAllocata( const AMD_ptr amd ) {
  423.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  424.         return AMD_DimensioniSpazioPuntatori(amd)+AMD_DimensioniSpazioDati(amd);
  425.     return 0;
  426. }
  427.  
  428. /*==============================================================================
  429. Restituisce la quantita' di memoria che, nell'ambito di quella complessivamente
  430. allocata in amd->d, e' destinata all'immagazzinamento dei puntatori usati per
  431. rendere possibile l'impiego dell'array con l'operatore [].
  432. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  433. array valido.
  434. ==============================================================================*/
  435.  
  436. size_t AMD_DimensioniSpazioPuntatori( const AMD_ptr amd ) {
  437.    if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) ) {
  438.       size_t qp = AMD_calcola_quantita_puntatori(amd->qElXDim,amd->totDim,1,0);
  439.       return qp*AMD_SizeofPtr;
  440.    }
  441.  
  442.    return 0;
  443. }
  444.  
  445. /*==============================================================================
  446. Restituisce la quantita' di memoria che, nell'ambito di quella complessivamente
  447. allocata in amd->d, e' destinata all'immagazzinamento dei dati dell'array.
  448. Un valore di ritorno 0 indica chiaramente una condizione inaccettabile per un
  449. array valido.
  450. ==============================================================================*/
  451.  
  452. size_t AMD_DimensioniSpazioDati( const AMD_ptr amd ) {
  453.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  454.         return AMD_QuantitaElementi(amd) * amd->dimEl;
  455.     return 0;
  456. }
  457.  
  458. /*==============================================================================
  459. Restituisce un puntatore al punto ove, nell'ambito della memoria
  460. complessivamente allocata in amd->d, ha inizio lo spazio destinato
  461. all'immagazzinamento dei dati dell'array.
  462. Un valore di ritorno NULL indica chiaramente una condizione inaccettabile per un
  463. array valido.
  464. ==============================================================================*/
  465.  
  466. void *AMD_InizioSpazioDati( const AMD_ptr amd ) {
  467.     if( AMD_NoCampiZero == AMD_stato_azzeramento_campi(amd) )
  468.         return amd->d + AMD_DimensioniSpazioPuntatori(amd);
  469.     return NULL;
  470. }
  471.  
  472. /*==============================================================================
  473. Crea un array multidimensionale con le caratteristiche richieste tramite i
  474. parametri dimEl, totDim e i parametri in quantita' variabile successivi, il
  475. valore di ciascuno dei quali indica la profondita' di una dimensione, a partire
  476. da quella piu' "esterna". Alloca la memoria dinamica necessaria e compila
  477. opportunamente i campi della struttura puntata dal parametro amd.
  478. La struttura puntata da amd, in ingresso deve avere almeno i campi d e qElXDim
  479. azzerati (valore NULL).
  480. Il parametro dimEl, che non puo' essere 0, deve esplicitare la dimensione in
  481. byte d'ogni singolo elemento dell'array da creare.
  482. Il parametro totDim, che non puo' essere 0, deve esplicitare la quantita' dei
  483. parametri successivi.
  484. Il valore di essuno dei parametri successivi a totDim puo' essere 0.
  485. In caso di successo, la funzione restituisce AMDErr_NoErr e i campi della
  486. struttura puntata dal parametro amd sono correttamente compilati. L'array
  487. definito da detta struttura dev'essere distrutto dal chiamante, tramite la
  488. funzione AMD_Distruggi().
  489. In caso di errore, il valore di ritorno e' un codice che identifica il problema
  490. incontrato, la struttura puntata dal parametro amd non viene modificata e
  491. nessuna memoria viene allocata.
  492. ==============================================================================*/
  493.  
  494. int AMD_Crea( AMD_ptr amd, size_t dimEl, size_t totDim, ... ) {
  495.     int errore = AMDErr_NoErr;
  496.  
  497.     size_t *qElXDimTmp = calloc( totDim, sizeof(*qElXDimTmp) );
  498.  
  499.     if( qElXDimTmp ) {
  500.         size_t i;
  501.  
  502.         va_list arg_ptr;
  503.         va_start( arg_ptr, totDim );
  504.  
  505.         for( i=0; i<totDim; ++i )
  506.             qElXDimTmp[i] = va_arg( arg_ptr, size_t );
  507.  
  508.         va_end( arg_ptr );
  509.  
  510.         errore = AMD_crea_da_array_dimensioni( amd, dimEl, qElXDimTmp, totDim );
  511.  
  512.         free( qElXDimTmp ); qElXDimTmp = NULL;
  513.     }
  514.  
  515.     return errore;   // allocazione fallita
  516. }
  517.  
  518. /*==============================================================================
  519. Crea un duplicato dell'array multidimensionale definito dalla struttura puntata
  520. dal parametro "originale". La creazione del duplicato avviene con una chiamata a
  521. AMD_crea_da_array_dimensioni(). I dati dell'array originale vengono copiati nel
  522. nuovo array con una chiamata a AMD_Copia().
  523. In caso di successo, la funzione restituisce AMDErr_NoErr e la struttura puntata
  524. dal parametro "duplicato" definisce l'array duplicato appena creato. L'array
  525. definito da detta struttura dev'essere distrutto dal chiamante, tramite la
  526. funzione AMD_Distruggi().
  527. In caso di errore, il valore di ritorno e' un codice che identifica il problema
  528. incontrato, la struttura puntata dal parametro "duplicato" non viene modificata
  529. e nessuna memoria viene allocata.
  530. ==============================================================================*/
  531.  
  532. int AMD_Duplica( AMD_ptr duplicato, const AMD_ptr originale ) {
  533.    if( NULL == duplicato || NULL == originale ) return AMDErr_PtrNULL;
  534.  
  535.    if( AMD_NoCampiZero==AMD_stato_azzeramento_campi(originale) ) {
  536.       int errore = AMD_crea_da_array_dimensioni(
  537.          duplicato, originale->dimEl, originale->qElXDim, originale->totDim );
  538.  
  539.       if( AMDErr_NoErr==errore )
  540.          return AMD_Copia( duplicato, originale );
  541.  
  542.       return errore;
  543.    }
  544.  
  545.    return AMDErr_StrutturaNonValida;
  546. }
  547.  
  548. /*==============================================================================
  549. Distrugge l'array multidimensionale definito dalla struttura puntata dal
  550. parametro amd. La struttura puntata dal parametro amd deve derivare da una
  551. precedente chiamata a una delle due funzioni AMD_Crea() e AMD_Duplica().
  552. In caso di successo, la funzione restituisce AMDErr_NoErr, tutti i campi della
  553. struttura puntata dal parametro amd sono azzerati e tutta la memoria dinamica
  554. connessa all'array e' deallocata.
  555. In caso di errore, il valore di ritorno e' un codice che identifica il problema
  556. incontrato, la struttura puntata dal parametro amd non viene modificata, e
  557. nessuna memoria viene deallocata.
  558. ==============================================================================*/
  559.  
  560. int AMD_Distruggi( AMD_ptr amd ) {
  561.     unsigned int stato = AMD_stato_azzeramento_campi( amd );
  562.  
  563.     if( AMD_UIntMenoUno != stato ) {
  564.         if( AMD_NoCampiZero == stato ) {
  565.             if( amd->d )
  566.                 free( amd->d );
  567.  
  568.             if( amd->qElXDim )
  569.                 free( amd->qElXDim );
  570.  
  571.             memset( amd, 0, sizeof(*amd) );
  572.  
  573.             return AMDErr_NoErr;
  574.         }
  575.  
  576.         return AMDErr_StrutturaNonValida;
  577.     }
  578.  
  579.     return AMDErr_PtrNULL; // parametro NULL
  580. }
  581.  
  582. const char *AMD_DescrizioneErrore( int codice ) {
  583.     const char *kStrErr[AMD_MaxErr] = {
  584.         "nessun errore",
  585.         "puntatore NULL",
  586.         "allocazione di memoria fallita",
  587.         "la struttura pare contenere già dei dati",
  588.         "impossibile creare un array a zero dimensioni",
  589.         "nessuna delle dimensioni di un array può essere zero",
  590.         "le dimensioni degli elementi dell'array non possono essere zero",
  591.         "la struttura non è valida",
  592.         "le due strutture non sono tra loro compatibili"
  593.     };
  594.  
  595.     if( codice >= 0 && codice < AMD_MaxErr )
  596.         return kStrErr[codice];
  597.     else return "errore imprevisto";
  598. }



I test che ho fatto sono questi:

file main.c:

Codice sorgente - presumibilmente C++

  1. #include "test.h"
  2. #include "c_menu.h"
  3.  
  4. int main() {
  5.     do {
  6.         // NOTA: c_menu_va() e' una funzione di una libreria che non sto a
  7.         //       mettere qui (l'include e' quel "c_menu.h"); comunque sia, non
  8.         //       fa altro che presentare un menu e assicurarsi che la scelta
  9.         //       effettuata sia una scelta valida.
  10.        
  11.         int scelta = c_menu_va("SCELTA TEST",5,"Esci","1D","2D","3D","4D");
  12.  
  13.         switch( scelta ) {
  14.             case 1:
  15.             case 2:
  16.             case 3:
  17.             case 4:
  18.                 test( scelta );
  19.                 break;
  20.  
  21.             default: return 0;
  22.         }
  23.     } while( 1 );
  24. }



file test.h:

Codice sorgente - presumibilmente C++

  1. #ifndef TEST_H_INCLUDED
  2. #define TEST_H_INCLUDED
  3.  
  4. #include <stdio.h>
  5.  
  6. #include "amd.h"
  7.  
  8. typedef int TipoTest;
  9.  
  10. void test( size_t qDim );
  11.  
  12. #endif // TEST_H_INCLUDED



file test.c:

Codice sorgente - presumibilmente C++

  1. #include "test.h"
  2.  
  3. #define QMAX_DIM    4
  4.  
  5. // in caso si cambiasse TipoTest, occorrerebbe modificare le stringhe
  6. // di formato usare dalle varie chiamate a printf(); e' comodo quindi
  7. // raggruppare qui tutte le stringhe di formato necessarie
  8. const char *kStrFormato4D = {" [%u][%u][%u][%u] = %04d\n"};
  9. const char *kStrFormato3D = {" [%u][%u][%u] = %03d\n"};
  10. const char *kStrFormato2D = {" [%u][%u] = %02d\n"};
  11. const char *kStrFormato1D = {" [%u] = %01d\n"};
  12.  
  13. void chiedi_dimensioni( size_t *dim, size_t qDim ) {
  14.     const char *dimStr[QMAX_DIM] = { "prima", "seconda", "terza", "quarta" };
  15.     const char id[QMAX_DIM] = { 'x', 'y', 'z', 't' };
  16.     int tmp[QMAX_DIM] = {0};
  17.     size_t i;
  18.  
  19.     for( i=0; i<qDim; ++i ) {
  20.         int dati_letti, nl;
  21.  
  22.         printf( "Profondita' della %s dimensione (%c, 1-10): ",
  23.                 dimStr[i], id[i] );
  24.  
  25.         dati_letti = scanf( "%d", tmp+i );
  26.         nl = '\n'==getchar();
  27.  
  28.         if( (1!=dati_letti) || !nl || (tmp[i]<1||tmp[i]>10) ) {
  29.             if( !nl ) while( '\n'!=getchar() );
  30.             --i;
  31.             continue;
  32.         }
  33.     }
  34.  
  35.     for( i=0; i<QMAX_DIM; ++i )
  36.         dim[i] = tmp[i];
  37.  
  38.     puts("");
  39. }
  40.  
  41. void test( size_t qDim ) {
  42.     size_t dim[QMAX_DIM] = {0};
  43.  
  44.     chiedi_dimensioni( dim, qDim );
  45.  
  46.     switch( qDim ) {
  47.         case 1: test_1d(dim); break;
  48.         case 2: test_2d(dim); break;
  49.         case 3: test_3d(dim); break;
  50.         case 4: test_4d(dim); break;
  51.         default: ;
  52.     }
  53. }
  54.  
  55. void mostra_a4d( const AMD_ptr amd ) {
  56.     // si sarebbe potuto passare direttamente l'alias a4d dal test_4d, ma così
  57.     // si hanno tutte le dimensioni "inglobate" in un'unica AMD_struct
  58.     TipoTest ****a4d = amd->d;
  59.     size_t c[4];
  60.  
  61.     for( c[0]=0; c[0]<amd->qElXDim[0]; ++c[0] )
  62.         for( c[1]=0; c[1]<amd->qElXDim[1]; ++c[1] )
  63.             for( c[2]=0; c[2]<amd->qElXDim[2]; ++c[2] )
  64.                 for( c[3]=0; c[3]<amd->qElXDim[3]; ++c[3] )
  65.                     printf( kStrFormato4D,
  66.                             c[0],c[1],c[2],c[3], a4d[c[0]][c[1]][c[2]][c[3]] );
  67.  
  68.     printf( "\n In totale, %u elementi.\n\n", AMD_QuantitaElementi(amd) );
  69. }
  70.  
  71. void test_4d( const size_t *dim ) {
  72.     AMD_struct amd = {0}; // e' consigliabile azzerare sempre la struttura
  73.  
  74.     int errore = AMD_Crea( &amd, sizeof(TipoTest), 4, dim[3], dim[2], dim[1], dim[0] );
  75.  
  76.     if( AMDErr_NoErr == errore ) {
  77.         TipoTest ****a4D = amd.d; // in C++ richiede un cast
  78.         size_t t, p, r, c;
  79.  
  80.         // scrive dei dati
  81.         for( t=0; t<dim[3]; ++t )
  82.             for( p=0; p<dim[2]; ++p )
  83.                 for( r=0; r<dim[1]; ++r )
  84.                     for( c=0; c<dim[0]; ++c )
  85.                         a4D[t][p][r][c] = t*1000+p*100+r*10+c;
  86.  
  87.         mostra_a4d( &amd );
  88.  
  89.         errore = AMD_Distruggi( &amd );
  90.     }
  91.  
  92.     if( AMDErr_NoErr != errore )
  93.         printf( "Errore test 4d: %s\n\n", AMD_DescrizioneErrore(errore) );
  94. }
  95.  
  96. void mostra_a3d( const AMD_ptr amd ) {
  97.     // si sarebbe potuto passare direttamente l'alias a3d dal test_3d, ma così
  98.     // si hanno tutte le dimensioni "inglobate" in un'unica AMD_struct
  99.     TipoTest ***a3d = amd->d;
  100.     size_t c[3];
  101.  
  102.     for( c[0]=0; c[0]<amd->qElXDim[0]; ++c[0] )
  103.         for( c[1]=0; c[1]<amd->qElXDim[1]; ++c[1] )
  104.             for( c[2]=0; c[2]<amd->qElXDim[2]; ++c[2] )
  105.                 printf( kStrFormato3D,
  106.                         c[0],c[1],c[2], a3d[c[0]][c[1]][c[2]] );
  107.  
  108.     printf( "\n In totale, %u elementi.\n\n", AMD_QuantitaElementi(amd) );
  109. }
  110.  
  111. void test_3d( const size_t *dim ) {
  112.     AMD_struct amd = {0}; // e' consigliabile azzerare sempre la struttura
  113.  
  114.     int errore = AMD_Crea( &amd, sizeof(TipoTest), 3, dim[2], dim[1], dim[0] );
  115.  
  116.     if( AMDErr_NoErr == errore ) {
  117.         TipoTest ***a3D = amd.d; // in C++ richiede un cast
  118.         size_t p, r, c;
  119.  
  120.         // scrive dei dati
  121.         for( p=0; p<dim[2]; ++p )
  122.             for( r=0; r<dim[1]; ++r )
  123.                 for( c=0; c<dim[0]; ++c )
  124.                     a3D[p][r][c] = p*100+r*10+c;
  125.  
  126.         mostra_a3d( &amd );
  127.  
  128.         errore = AMD_Distruggi( &amd );
  129.     }
  130.  
  131.     if( AMDErr_NoErr != errore )
  132.         printf( "Errore test 3d: %s\n\n", AMD_DescrizioneErrore(errore) );
  133. }
  134.  
  135. void mostra_a2d( const AMD_ptr amd ) {
  136.     // si sarebbe potuto passare direttamente l'alias a2d dal test_2d, ma così
  137.     // si hanno tutte le dimensioni "inglobate" in un'unica AMD_struct
  138.     TipoTest **a2d = amd->d;
  139.     size_t c[2];
  140.  
  141.     for( c[0]=0; c[0]<amd->qElXDim[0]; ++c[0] )
  142.         for( c[1]=0; c[1]<amd->qElXDim[1]; ++c[1] )
  143.             printf( kStrFormato2D,
  144.                     c[0],c[1], a2d[c[0]][c[1]] );
  145.  
  146.     printf( "\n In totale, %u elementi.\n\n", AMD_QuantitaElementi(amd) );
  147. }
  148.  
  149. void test_2d( const size_t *dim ) {
  150.     AMD_struct amd = {0}; // e' consigliabile azzerare sempre la struttura
  151.  
  152.     int errore = AMD_Crea( &amd, sizeof(TipoTest), 2, dim[1], dim[0] );
  153.  
  154.     if( AMDErr_NoErr == errore ) {
  155.         TipoTest **a2D = amd.d; // in C++ richiede un cast
  156.         size_t r, c;
  157.  
  158.         // scrive dei dati
  159.         for( r=0; r<dim[1]; ++r )
  160.             for( c=0; c<dim[0]; ++c )
  161.                 a2D[r][c] = r*10+c;
  162.  
  163.         mostra_a2d( &amd );
  164.  
  165.         errore = AMD_Distruggi( &amd );
  166.     }
  167.  
  168.     if( AMDErr_NoErr != errore )
  169.         printf( "Errore test 2d: %s\n\n", AMD_DescrizioneErrore(errore) );
  170. }
  171.  
  172. void mostra_a1d( const AMD_ptr amd ) {
  173.     // si sarebbe potuto passare direttamente l'alias a1d dal test_1d, ma così
  174.     // si hanno tutte le dimensioni "inglobate" in un'unica AMD_struct
  175.     TipoTest *a1d = amd->d;
  176.     size_t c[1];
  177.  
  178.     for( c[0]=0; c[0]<amd->qElXDim[0]; ++c[0] )
  179.         printf( kStrFormato1D,
  180.                 c[0], a1d[c[0]] );
  181.  
  182.     printf( "\n In totale, %u elementi.\n\n", AMD_QuantitaElementi(amd) );
  183. }
  184.  
  185. void test_1d( const size_t *dim ) {
  186.     AMD_struct amd = {0}; // e' consigliabile azzerare sempre la struttura
  187.  
  188.     int errore = AMD_Crea( &amd, sizeof(TipoTest), 1, dim[0] );
  189.  
  190.     if( AMDErr_NoErr == errore ) {
  191.         TipoTest *a1D = amd.d; // in C++ richiede un cast
  192.         size_t x;
  193.  
  194.         // scrive dei dati
  195.         for( x=0; x<dim[0]; ++x )
  196.             a1D[x] = x;
  197.  
  198.         mostra_a1d( &amd );
  199.  
  200.         errore = AMD_Distruggi( &amd );
  201.     }
  202.  
  203.     if( AMDErr_NoErr != errore )
  204.         printf( "Errore test 1d: %s\n\n", AMD_DescrizioneErrore(errore) );
  205. }


Ultima modifica effettuata da AldoBaldo il 17/08/2019 alle 23:47


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