Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Una cosa che mi capita di usare piuttosto spesso nei miei programmini in C sono le matrici bidimensionali, quelle sul genere di matrice[nRighe][nColonne], per intendersi. Per varie ragioni trovo a volte utile allocarle dinamicamente, ed è un compito che dopo un po' diventa noioso. Per questo ho pensato di provare a mettere insieme una funzione da poter copia-e-incollare ogni qualvolta mi dovesse servire. Dovendo fare in modo che sia adattabile a qualsiasi tipo di dati, ho pensato di fare in modo che restituisca un void**, così:
for( r=0; r<n_righe;++r )// per ogni riga della matrice...
free( m[r]);// libera in blocco tutte le colonne sulla riga
free( m );// libera l'array dei puntatori alle righe
*matrice =NULL;// annulla il puntatore alla matrice
}
}
}
L'idea pare funzionare, anche se mi aspetto che qualcuno più pratico di me possa indicarmi qualche errore.
La questione che vorrei porre, però, non riguarda gli (eventuali) errori, bensì la ragione per la quale il compilatore (mingw) mi impone di effettuare il cast di tipo da void** a esempio_t** e viceversa. So che quel cast sarebbe obbligatorio (almeno tanto quanto è deprecato) nel caso di un programma in C++, ma il mio esempio è un programmino in C... in C, un puntatore a doppia indirezione di tipo void** non dovrebbe essere liberamente "intercambiabile" con un puntatore a doppia indirezione di qualsiasi altro tipo anche senza fare il cast? void** non è utilizzabile come puntatore generico almeno quanto il void* restituito (per dire) da calloc() che può essere assegnato a un puntatore di qualsiasi tipo senza cast?
Codice sorgente - presumibilmente C/C++
int *ptrNum = calloc( 1, sizeof(*ptrNum) ); // da void* a int* senza cast!
Dov'è la falla nel mio ragionamento? Cosa sbaglio?
Ultima modifica effettuata da AldoBaldo il 07/04/2017 alle 19:02
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.
Ponendo che la funzione che hai scritto sia corretta (non ho tempo per controllarla):
Il tipo void ** non è equivalente a void *: sono entrambi puntatori, ma il primo è del tipo "puntatore ad un puntatore (che a sua volta punta a void)", mentre il secondo è del tipo "puntatore a void".
Questo vuol dire che per il tipo void ** si applica quanto statuito nelle sezioni 6.6 e 6.8 del Reference manual del linguaggio C inserito nel testo di Kernighan-Ritchie (seconda edizione, appendice A), ovvero non è possibile un cast implicito ed inoltre a seconda dell'implementazione potrebbero non essere possibili alcuni cast espliciti.
Ok avevo letto troppo velocemente, in effetti con i puntatori multipli il discorso cambia e Template dice giusto (infatti mi pareva strano che calloc nel tuo codice funzionasse e altrove no).
Dovrebbe essere proprio come dici tu, prova a mettere tutto in un
Codice sorgente - presumibilmente C/C++
#ifdef __cplusplus
#endif
Ho provato: ne deriva questo...
||=== Build: Debug in Matrice (compiler: GNU GCC Compiler) ===|
C:\Program Files\CodeBlocks\MinGW\bin\..\lib\gcc\mingw32\4.9.2\..\..\..\libmingw32.a(main.o):main.c.text.startup+0xa7)||undefined reference to `WinMain@16'|
||error: ld returned 1 exit status|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 2 second(s)) ===|
...dal che deduco che il programma venga effettivamente compilato come C e non come C++.
Ora provo a "sondare" la questione della doppia indirezione, poi "ritorno".
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.
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.
Ho letto l'intera pagina sulla questione del void** e direi che fa strame della mia funzione crea_matrice(). Dovrò pensare a qualcos'altro. Grazie a Template per avermi ricondotto sulla "retta via", tirandomi coi piedi per terra. Però non mi arrendo... ancora!
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.
Una soluzione banale potrebbe essere quella di "legare" ogni particolare funzione crea_matrice a un determinato tipo, in modo esplicito, magari apponendo il nome del tipo al nome della funzione. Con una soluzione del genere basta copiare e incollare la funzione d'esempio e effettuare una sostituzione di tutte le sottostringhe del codice che identificano il tipo in questione. Con un tipo chiamato TIPO_ES, ad esempio...
Codice sorgente - presumibilmente C++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
typedefstruct struct_TIPO_ES {// TIPO_ES = tipo esempio
TIPO_ES **m =*matrice;// per praticita' di lettura
if( m !=NULL){// se la matrice esiste...
uint32_t r;// contatore delle righe
for( r=0; r<qRighe;++r )// per ogni riga della matrice...
free( m[r]);// libera in blocco tutte le colonne sulla riga
free( m );// libera l'array dei puntatori alle righe
*matrice =NULL;// annulla il puntatore alla matrice
}
}
}
In questo modo non serve neanche comunicare alla funzione le dimensioni del tipo dei dati, perché può ricavarle da sola tramite sizeof. Inoltre non rimane traccia di cast di alcun genere, che non è certo un male. Suggerimenti?
P.S. Se solo il C avesse contezza dell'overload di funzioni... magari in qualche sua incarnazione più recente di quella che conosco io (ormai almeno ventennale) si può usare l'overload o è roba solo per il C++ com'era "ai miei tempi"?
Ultima modifica effettuata da AldoBaldo il 07/04/2017 alle 22:40
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.
()
Newbie
Messaggi: Iscritto:
Postato alle 23:06
Venerdì, 07/04/2017
Scusa la mia ignoranza, ma un qualcosa tipo
Codice sorgente - presumibilmente C++
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
Codice sorgente - presumibilmente C++
#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]);
return0;
}
Il problema potrebbe nascere con le stringhe
Ultima modifica effettuata da il 07/04/2017 alle 23:07