Oppure

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

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

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

/*==============================================================================
Alloca dinamicamente spazio in memoria per una matrice di qr*qc elementi di
dimensioni dim_el byte ciascuno. L'area della memoria allocata riservata ai dati
viene inizializzata azzerandola.
In caso di successo, restituisce un void* che deve essere assegnato ad un
puntatore a doppia indirezione di tipo corrispondente al tipo di dati che si
intende immagazzinare nella matrice appena creata.
La matrice puo' essere regolarmente impiegata con i classici operatori di
indicizzazione (matrice[riga][colonna]).
La memoria allocata deve essere liberata dal chiamante tramite free().
In caso di errore restituisce NULL e nessuna memoria risulta allocata.

PARAMETRI

    qr      quantita' di righe nella matrice
    qc      quantita' di colonne nella matrice
    dim_el  dimensioni (in byte) di un elemento della matrice

VALORE DI RITORNO

    un puntatore generico allo spazio di memoria allocato dinamicamente e
    in grado di contenere la matrice

ESEMPIO

int main() {
    const size_t qr = 6;
    const size_t qc = 4;

    // crea una matrice di 6x4 elementi in
    // grado di contenere valori di tipo int
    int **m = crea_matrice( qr, qc, sizeof(int) );

    if( m ) {
        size_t r, c;

        // popola la matrice
        for( r=0; r<qr; ++r )
            for( c=0; c<qc; ++c )
                m[r][c] = 10*r+c;

        // mostra il contenuto della matrice
        for( r=0; r<qr; ++r )
            for( c=0; c<qc; ++c )
                printf( "%d%c", m[r][c], c!=qc-1?' ':'\n' );

        // libera la memoria allocata
        free( m );
        m = NULL;
    }
    
    return 0;
}

==============================================================================*/

void *crea_matrice( size_t qr, size_t qc, size_t dim_el ) {
    static const size_t dim_ptr = sizeof( void* );
    void *m = calloc( qr*dim_ptr + qr*qc*dim_el, 1 );

    if( m ) {
        size_t pp = (size_t)m;       /* pp: puntatore a puntatore    */
        size_t pr = pp + qr*dim_ptr; /* pr: puntatore a una "riga"   */

        while( qr-- ) {
            *((size_t*)pp) = pr; /* colloca il puntatore ad una      **
                                 ** riga nella posizione opportuna   */
            pr += qc*dim_el;     /* rileva il valore del puntatore   **
                                 ** alla riga successiva             */
            pp += dim_ptr;       /* avanza pp alla posizione del     **
                                 ** puntatore alla riga successiva   */
        }
    }

    return m;
}



* il filone di discussione originale:
pierotofy.it/pages/extras/forum/2/1066990-[risolto_passare_matrice_dinamica_a_routine_in_c/
Ultima modifica effettuata da AldoBaldo 12/02/21 7:49
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
12/02/21 9:23
Carlo
Come al solito, non sono in grado di rispondere ai tuoi quesiti.
Il mio gcc in MinGW, non segnala errori, warning o note, il programma fa quanto promesso.

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

nell'introduzione hai cercato di spiegarlo, ma una costante o variabile di tipo size_t, non realizzo cosa produca in pratica e finquando non lo capisco non posso pasticciare con il tuo codice. 8-|
in programmazione tutto è permesso
12/02/21 17:35
AldoBaldo
Stando a quanto lessi millenni fa, il tipo size_t non è altro che un tipo di dato destinato a contenere un valore intero senza segno con capacità sufficiente a rappresentare una qualsiasi quantità di memoria compresa tra il minimo e il massimo ammissibili dal sistema. Da ciò penso di poter dedurre che qualsiasi indirizzo di memoria (che, in definitiva, non è altro che un numero) possa essere convertito in un valore numerico che può essere inserito in una variabile di tipo size_t.

Ai fini pratici dell'esempio, qr e qc puoi tranquillamente sostituirli con int, se preferisci, così come r e c. Li ho usati solo per impostare le dimensioni della matrice e per avere a disposizione due contatori -- qr sta per "quantità righe" e qc per "quantità colonne", laddove r ("riga";) e c ("colonna";) sostituiscono i classici i e j.
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
12/02/21 17:58
Carlo
Ho sostituito il size_t con unsigned int e le mie modifiche continuavano a non funzionare, ma ora non più distratto da una cosa che non capivo, l'errore era mio e banale...
Tutto funziona regolarmente anche con size_t.

Una bella funzione per allocare dinamicamente matrici bidimensionali con tutti i tipi di dato.
Ultima modifica effettuata da Carlo 12/02/21 18:00
in programmazione tutto è permesso