Oppure

Loading
07/04/17 21:06
Scusa la mia ignoranza, ma un qualcosa tipo

void* crea( int Size_Tipo_in_Byte, int Col, int Rig )
{
    void *r = NULL;
    r = malloc( Size_Tipo_in_Byte*Col*Rig );
    return r;
}

Cioè avendo la dimensione di un singolo elemento e righe/Colonne, ti allochi la dimensione necessaria per il tutto, poi nel mai utilizzi il puntatore come un vettore

#define RIGHE 3
#define COLONNE 2
int main(){

    int R, C;
    char *p ;
    int  *m = NULL;
    int i =0 ;
    p = crea(sizeof(char),RIGHE,COLONNE);

    strcpy( p, "ProvaMat" );

    for(R=0;R<RIGHE;R++ )
        for(C=0;C<COLONNE;C++ )
    printf( "%c", p[(R*COLONNE)+C] );

    printf( "---\n\n\n" );
   m=crea(sizeof(int),RIGHE,COLONNE);

       for(R=0;R<RIGHE;R++ )
        for(C=0;C<COLONNE;C++ )
            m[(R*COLONNE) + C] = i++; 

    for(R=0;R<RIGHE;R++ )
        for(C=0;C<COLONNE;C++ )
    printf( "%d", m[(R*COLONNE)+C] );

    return 0;
}

Il problema potrebbe nascere con le stringhe

Ultima modifica effettuata da 07/04/17 21:07
07/04/17 21:26
AldoBaldo
Sì, quello è un approccio che son solito usare (e funziona). Questa volta però avevo in mente di fare qualcosa di utilizzabile nella forma matrice[][], che in certe circostanze è più "comodo" perché appare più esplicito.
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.
07/04/17 21:50
Template
Probabilmente pensandoci arriverai a moltissimi possibili algoritmi... ma di fatto, credo che la soluzione migliore rimanga il casting esplicito.
aaa
07/04/17 22:16
AldoBaldo
Però nella pagina di Stack Overflow che mi hai segnalato non sono pochi coloro che mettono in guardia dalla possibilità di "falle" nell'effettuare cast di puntatori a doppia indirezione void**. Personalmente ho sempre pensato che un puntatore fosse solo un numero che indica una posizione in memoria, secondo le "dimensioni" di indirizzamento del sistema in uso (nel mio caso, 32 bit). Dunque, se il ragionamento regge, una puntatore a doppia indirezione è un numero che dice dove andare a guardare in memoria per trovare un altro numero che dice dove trovare in memoria un certo dato. Un po' intricata come espressione, ma CREDO realistica. Questo parrebbe lasciare intendere che fare un cast a un puntatore non crei chissà quali sfaceli. Epperò su Stack Overflow, se ho bene inteso, un tale osserva che gli sfaceli possono derivare dall'eventuale ricorso malaccorto all'aritmetica sui puntatori, il che mi sembra effettivamente plausibile. Che grana!
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.
08/04/17 5:47
Template
Si, l'uso dei puntatori non è sempre banale e privo di rischi... ma soppesando vantaggi e svantaggi, un po' di rischio potrebbe essere preferibile ad algoritmi molto più complessi (leggi: molto più soggetti a bug ed errori).
aaa
08/04/17 8:03
Il problema fondamentale di chi usa (male) i puntatori è proprio il fatto che sottovaluta (o non sa) che dietro c'è una "aritmetica dei puntatori" che governa tante operazioni e che, al contrario, il compilatore lo tiene sempre in considerazione.
08/04/17 15:51
AldoBaldo
Ho deciso che, per la sua semplicità, userò la soluzione che ho indicato nel codice incluso nel commento delle 22:35 del 7/4. Grazie a tutti quelli che mi hanno dedicato il loro tempo. In particolare a chi mi ha messo la "pulce nell'orecchio" sulla questione della doppia indirezione su void, della quale non sapevo NULLA. Ora, se non altro, so di non sapere (e non è cosa da poco, perché mi evita il rischio di fare delle stupidaggini troppo grandi).
Ultima modifica effettuata da AldoBaldo 08/04/17 15:53
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.
08/04/17 16:03
lumo
Potresti rendere un po' meno copia-incolla quella soluzione usando le macro
#define DECLARE_MATRIX(type)
type **crea_matrice_##type ( uint32_t qRighe, uint32_t qColonne ) {
    // alloca i puntatori alle righe, tutti NULL
    type **matrice = calloc( qRighe, sizeof(type*) );
 
    if( matrice != NULL ) { // se l'allocazione e' riuscita...
        uint32_t r; // contatore
 
        for( r=0; r<qRighe; ++r ) { // per ogni riga
            // alloca in blocco tutte le colonne sulla riga
            matrice[r] = calloc( qColonne, sizeof(*matrice[r])*qColonne );
 
            if( matrice[r] == NULL ) { // se l'allocazione NON e' riuscita...
                distruggi_matrice_##type ( &matrice, r );
                break;
            }
        }
    }
 
    return matrice; // NULL in caso d'errore
}


Ho omesso il \ a fine riga per pigrizia ma senza non funzionerebbe.
Sotto quella dovresti mettere anche distruggi_matrice_##type

Così ogni volta che ti serve una matrice di quel tipo fai:

DECLARE_MATRIX(char)


nello scope globale, e poi puoi utilizzare le funzioni crea_matrice_char e distruggi_matrice_char. Ha l'ovvio svantaggio che per tipi complessi devi usare un typedef, inoltre io lo trovo un po' difficile da leggere.
Del resto il C è più a suo agio quando si sta vicini alla macchina, per la programmazione ad alto livello mostra un po' gli anni.

Intendi così...

void **crea_matrice( size_t dim_el, uint32_t n_righe, uint32_t n_colonne );

... o così?

void **crea_matrice( size_t dim_el, size_t n_righe, size_t n_colonne );


La seconda, infatti è anche il tipo che accettano malloc e calloc. Quando si ha a che fare con una grandezza riferita alla memoria indirizzabile si usa sempre size_t per far capire che è quello l'intento.
aaa