Newsgroup: it.comp.lang.c
Titolo: Metodo generico per l'allocazione dinamica di matrici

Come da oggetto sto cercando di scrivere un metodo di utilizzo comune per
l'allocazione dinamica della memoria per matrici di tipi differenti.
void *AllocaMatrix(unsigned int righe, unsigned int colonne, size_t size)
{
 unsigned register int  i;
 unsigned char          **matP;
 matP = (unsigned char **) malloc(righe*sizeof(unsigned char *));
 *matP = (unsigned char *) malloc(righe*colonne*size);
 for(i=1; i < righe; i++)
  matP[i] = (unsigned char *) (*matP + i*colonne*size);
 return matP;
}
Ho omesso volontariamente i controlli sui puntatori ritornati (!= NULL) per
lasciare solo la parte che mi preme chiarire.
E' giusto utilizzare sizeof(unsigned char*) per l'allocazione dell'array di
puntatori? La dimensione occupata da un puntatore è sempre 1 byte
indipendentemente dal tipo puntato?
Grazie per i chiarimenti
Bye
John

 indipendentemente dal tipo puntato?
La dimensione di un puntatore non č 1 byte, almeno da quando i computer 
sono in grado di indirizzare piů di 256 byte di memoria :-)
Oggi nei sistemi a 32bit sizeof(unsigned char*) ti restituisce 4, come 
se tu facessi sizeof(long *) o sizeof(very_big_structure *).

 se tu facessi sizeof(long *) o sizeof(very_big_structure *).
Vabbè quindi per rispondere al mio quesito iniziale va bene lasciare
unsigned char *?
Grazie
Bye
John

 unsigned char *?
Credo di no.
Anzi proprio no.
Quando allochi memoria per una struttura di tipo array (matrice), la 
sizeof(...) da usare nella malloc deve calcolare la dimensione in byte 
del "tipo di elementi" dell'array, e non "del puntatore" da restituire.
Esempio: vuoi allocare memoria per un array di N elementi int?
int *p;
p = malloc(N * sizeof(int));
Memoria per un array di N righe e M colonne di unsigned long int?
unsigned long int *p;
p = malloc(N*M*sizeof(unsigned long int));
Come vedi, a sizeof non passo il PUNTATORE AL TIPO CHE MI OCCORRE, ma il 
tipo di dati di cui sarà costituito l'array.
Perchè effettivamente un array di 200 elementi int dovrà richiedere 
200*2 bytes (se supponiamo che int occupi 2 byte).
Se vuoi un array di 50 elementi di unsigned long int dovrai dire a 
malloc di allocarti 50*4 bytes (se unsigned long int occupa 4 bytes).
Facendo a modo tuo, invece, allochi sempre N*4, perchè sizeof(tipo *) 
restituirà sempre 4, perchè un puntatore a tipo (qualunque sia tipo) è 
grande _sempre_ 4 bytes (sulle macchine che lavorano a 32 bit).
E' il principio che è sbagliato, quindi occupi più memoria di quanta te 
ne serva, e continuando a ragionare in quel modo potresti anche 
commettere errori nell'utilizzare poi da codice la memoria allocata.
-- 
Quando noi ignoranti eravamo di più, tutto era più bello (A. Celentano).
  ___   _   ___ _  _______   _______ ___
|   \ /_\ | _ \ |/ / _ ) \ / /_   _| __|
| |) / _ \|   / ' <| _ \\ V /  | | | _|
|___/_/ \_\_|_\_|\_\___/ |_|   |_| |___|

Credo tu non abbia ben capito il caso che ho presentato io:
io sto parlando della prima malloc quella che deve allocare memoria per
l'array di puntatori.
Nella seconda sono d'accordo con te ma come vedi io moltiplico già il numero
di elementi per "size" che è un'argomento della mia funzione.
Bye
John

Pardon... non avevo capito che tu intendessi allocare esattamente un 
array di puntatori.
Comunque, allocare n*sizeof(char *) oppure n*sizeof(unsigned long *) č 
lo stesso.
Se proprio vuoi restare in campo neutro (e rendere il codice un po' piů 
leggibile) fai una malloc(n*sizeof(void *)).
Credo che cosě possa andare meglio...
-- 
Quando noi ignoranti eravamo di piů, tutto era piů bello (A. Celentano).


 di un tipo in un'altro di un'altro tipo senza perdere alcuna informazione.
Mi pare che, da standard, non sia obbligatorio che le lunghezze di 
puntatori di diverso tipo siano uguali, ma che effettivamente il cast 
dovrebbe tentare di fare tutto il possibile per non perdere 
informazione. Tuttavia sto andando ad impressioni, potrei sbagliarmi, 
lascio che le persone piu' esperte di me dicano la loro...
-- 
Mat/tia Belletti - Undergraduate student @ 
cs.unibo.it
ICQ: 33292311    - email: 
mbel...@cs.unibo.it
IRC: RedGlow     - site(s): 
http://mbellett.web.cs.unibo.it/
Jabber: RedGlow  - Linux registered user 299762 @ machine 213003

 leggibile) fai una malloc(n*sizeof(void *)).
Grazie, proverò così! In realtà ci avevo già pensato ma mi ero lasciato
ingannare dal fatto che non si può fare il sizeof(void)... in realtà qui è
un void * quindi dovrebbe andare!
Qualche altra conferma da parte dei guru? vado sul sicuro con sizeof(void *)
o ci sono casi in cui i puntatori occupano più spazio in memoria?
Grazie
Bye
John

Ciao,
hai pensato anche al fatto che dovrai liberare la memoria (magari non ti
serve)?

 serve)?
In realtà non ci avevo ancora pensato ma quali pensi possano essere i
problemi?
Bye
John

 un void * quindi dovrebbe andare!
Non solo "dovrebbe andare": in teoria è l'unico modo corretto di farlo.
Lo standard garantisce che un puntatore a qualsiasi tipo si possa
convertire in void* e che un void* si poossa convertire in un puntatore a
qualsiasi tipo, il tutto senza perdere informazioni. La conversione
diretta fra puntatori di tipo generico, invece, non è garantito che
funzioni.
In pratica, se fai così:
   int i;
   int* pi = &i;
   void* p = pi;
   pi = p;
.. sei sicuro che alla fine pi contenga l'indirizzo di i.
Se invece fai così:
   int i;
   int* pi = &i;
   TipoPippo* p = (TipoPippo*)pi;
   pi = (int*)p;
.. non è garantito che la cosa funzioni: alla fine pi potrebbe avere un
valore non valido, o comunque diverso dall'indirizzo della variabile i.
<RANT>
In pratica, anche il secondo esempio funziona su tutti i compilatori e i
sistemi operativi che io abbia visto finora. Però, in vent'anni di
programmazione, mi sono ritrovato più volte a giocarmi sabati e domeniche
per degli "in pratica" che cinque o sei anni prima erano validi... Alzi la
mano chi ha più di trent'anni e non ha mai avuto guai con il fatto che
qualcuno, pochi anni prima, aveva detto che, "in pratica, short e int sono
la stessa roba". Mentre chi lavora su sistemi lillipuziani tipo DOS o
processori embedded, maledice spesso i rampanti linuxisti o windowisti che
pensano che "in pratica, long e int sono la stessa roba".
</RANT>
Nota anche gli antiestetici cast nelle ultime due righe del 2º esempio,
che con i void* si possono evitare, perché convertire un puntatore
qualsiasi a void* o viceversa non genera mai warning.
--
Cingar
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 problemi?
Che dovrai prima o poi scrivere una funzione di questo tipo:
void FreeMatrix(void * matrice, unsigned int righe, unsigned int colonne);
Il problema è: al momento in cui dovrà chiamarla, il tuo programma saprà
dove andare a prendere i numeri da passare nei parametri "righe" e
"colonne"? Senza quei valori, è impossibile fare le free() nell'ordine
giusto per disfare le malloc() fatte precentemente.
Se hai una sola matrice, non c'è problema (ma, a quel punto, che ti serve
tutto questo ambaradan?). Ma se ne hai più d'una, sarà meglio che ti poni
il problema di come accoppiare ogni puntatore "matrice" con i dati
necessari per liberarla (ma anche, in generale, per usarla).
Potresti trasformare la tua matrice da un semplice puntatore ai dati a una
struct che contiene, oltre al puntatore, le "misure" necessarie.


 sistemi operativi che io abbia visto finora.
Basta andare poco lontato, su Sparc ad esempio, per assistere a
catastrofi :)
x86 puo` accedere a qualunque locazione di memoria, gli Sparc hanno dei
requisiti di allineamento piu` stringenti.
Ad esempio:
char a[5];
int *b;
b = (int *)(a + 1);
su x86 funziona senza problemi (al limite c'e` una piccola perdita di
prestazioni), su sparc genera un segfault perche` gli int *devono*
essere allineati alla word.
Quanto ai void *, quello che lo standard assicura e` che sia possibile
fare un assegnamento da T* a void* e viceversa senza problemi. Non
garantisce che sia lecito fare una cosa del genere:
T *p1;
void *p2;
P *p3;
p2 = p1;
p3 = p2;
...giusto nel caso qualcuno stia pensando di usare i void* per fare
incavolare gli sparc 8-)
Luca
-- 
Home: 
http://kronoz.cjb.net
"L'ottimista pensa che questo sia il migliore dei mondi possibili. 
 Il pessimista sa che e` vero" -- J. Robert Oppenheimer

...

CONFERmo per esperienza personale! ho provato a fare una cosa del
genere nella mia tesi:
int *p_int=....
char *p_char=(cha*) p_int
RISULTATO?  BUS ERROR su *questa*  istruzione!