Newsgroup: it.comp.os.linux.development
Titolo: memoria dinamica in C

Non sono riuscito ad allocare dinamicamente memoria per un array di
stringhe da 1024 caratteri caduna (vorrei avere char var[n][1024], dove n
è da definire a runtime)
Qualcuno mi potrebbe scrivere come dichiarare la variabile, come
c/mallocare spazio, e come strcpyarci sopra ?
Grazie


Scritto al volo (e quindi da provare)
char
	**myArray;
int 
	rows=10,cols=1024+1,i;
myArray = (char**)malloc(sizeof(char*)*rows);
for (i=0;i!=rows;i++)
	myArray[i]=(char*)malloc(sizeof(char)*cols);
Ciao,
-- 
Ludovico Basili
ludovico_basili(at)
alliedtelesyn.com

>char var[n][1024],
Quelli sono 1024 array di n caratteri, non n array di 1024 caratteri..

 
Ti sbagli char var[n][1024] rappresenta un array di n elementi dove ogni elemento puo' 
contenere 1024 caratteri...!!!
Cioe' e' una matrice di n righe e 1024 colonne... :-)
bye bye
Luciano

 	myArray[i]=(char*)malloc(sizeof(char)*cols);
Niente cast, sono solo controproducenti.
-- 
Saluti,
    Mardy
http://castellina.org/interlingua

 Quelli sono 1024 array di n caratteri, non n array di 1024 caratteri..
No, e' un array di n array da 1024 char.
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 	myArray[i]=(char*)malloc(sizeof(char)*cols);
ottimizzabile in:
char **myarray;
myarray = malloc(sizeof(char*) * rows);
for (i = 0; i < rows; i++)
{
    myarray[i] = malloc(cols);   


 Niente cast, sono solo controproducenti.
non diciamo fesserie
-- 
 < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
     Don't stand, REACT!      version 0.0.19. C, C++ and ASM developers
                              and beta testers are welcome!


Ma a cosa serve usare i puntatori in myarray se cols e' costante?
Si tratta di una matrice. Io farei cosi':
char *myarray;
myarray=(char *) malloc(sizeof(char*) * rows * cols);
E poi si indirizzo i vari elementi con myarray[r*cols+ c] o, se preferite
(ma qui potrei sbagliare) myarray[r][c].
Alessandro.

 ottimizzabile in:
[snip]
Funzionante piu` che ottimizzato :D
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Dicono che  il cane sia  il miglior  amico dell'uomo. Secondo me  non e`
vero. Quanti dei vostri amici avete fatto castrare, recentemente?

 non diciamo fesserie
Dov'e` la fesseria?
Scommettiamo  che su  questo codice  il compilatore  non avra`  nulla da
dire?
int main(void) {
        int *p;
        p = (int *)malloc("foobar");
}
Omettendo il cast,  invece, si lamentera` del fatto  che stai assegnando
un int  ad un puntatore  (permettendoti di rilevare gli  errori: mancata
inclusione di stdlib, uso errato di malloc).
Il   cast  serve   scavalcare  le   normali  regole   di  promozioni   e
potenzialmente viola le regole di tipizzazione del linguaggio. IMNSHO va
usato solo quando e` realmente necessario.
Visto che fin dal C89 e` prevista la conversione implicita da 'void *' a
'T  *' e  viceversa non  si  puo` neppure  tirare fuori  la scusa  della
compatibilita` con i vecchi compilatori.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Sono un mirabile incrocio tra Tarzan e Giacomo Leopardi.
In me convivono tutte le doti intelluttuali di Tarzan e
tutta la prestanza fisica di Giacomo Leopardi.
A. Borsani


A parte la patologia del caso, mi sembra strano. (Provero' ;-)
Non capisco perche' il cast dovrebbe coinvolgere il  prototipo della
funzione, e non solo il valore restituito da questa.
Inoltre, nel caso non venga incluso automaticamente dal compilatore l'header
contenete il prototipo, malloc dovrebbe risultare non dichiarata; in caso
contrario, risulterebbe avere il parametro errato.
In alcuni casi il compilatore in mancanza di prototipo fa delle assunzioni
riguardo ai prototipi delle funzioni non dichiarate e restituisce solo un
warning, ma comuque ci avverte che c'e' qualcosa che non va.
Alessandro.

 warning, ma comuque ci avverte che c'e' qualcosa che non va.
No. In realta`  dipende dal  livello di warning  settato. Il compilatore
_deve_ segnalare  l'assegnazione tra  tipo incompatibili, mentre  non e`
tenuto a segnalare  prototipi mancanti visto che secondo  lo standard e`
lecito  omettere il  prototipo (lecito  non significa  che sia  una cosa
buona).
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
"Ci sono le balle , le megaballe e le statistiche".
 Mark Twain

  errori: mancata inclusione di stdlib, uso errato di malloc).
ah, se presupponiamo di non sapere cosa si stia facendo, sono d'accordo


 non diciamo fesserie
Assicurati di conoscere bene gli argomenti.
Chiunque programmi seriamente in C sa benissimo che
l'uso dei cast e' controproducente e va evitato.
Si e' discusso di questo migliaia di volte in iclc.
Il programmatore ha troppa fiducia in se stesso, per
credere di sapere sempre esattamente che cosa stia
facendo.  Gli errori nascono dalla distrazione e 
usare il cast non aiuta ad essere meno distratti.
Addirittura, i buoni Kernighan & Ritchie si sono
sbagliati nella loro II edizione di "The C Programming 
Language", ed e' subito seguito l'errata corrige:
"142: The remark about casting the return value 
of malloc ("the proper method is to declare ... 
then explicitly coerce") needs to be rewritten. 
The example is correct and works, but the advice 
is debatable in the context of the 1988-1989 ANSI/ISO 
standards. It's not necessary (given that coercion of 
void * to ALMOSTANYTYPE * is automatic), and possibly 
harmful if malloc, or a proxy for it, fails to be declared 
as returning void *. The explicit cast can cover up an 
unintended error. On the other hand, pre-ANSI, the cast 
was necessary, and it is in C++ also".


 se preferite (ma qui potrei sbagliare) myarray[r][c].
Sbagliato.
A parte che il cast sul valore del ritorno di malloc
non va usato, come gia' detto, tu allochi memoria
per rows * col moltiplicato la lunghezza, in byte, di
un puntatore a carattere.  Non ha senso.
Dovresti scrivere:
myarray = malloc(rows * cols);
ma in questo modo precludi di poter utilizzare la 
scrittura myarray[r][c].
Puoi solo scrivere myarray[r*cols + c] e non so 
fino a che punto convenga.
Per usare questa notazione devi allocare la matrice
cosi' come ho scritto nel mio esempio.
Per matrice si intende un array bidimensionale e
quindi e' giusto che venga allocata e usata in 
quanto tale.


quanto tale.
Ho capito.
Mi permetto allora di modificare la tua versione con una piccola
ottimizzazione:
char **myarray;
myarray = malloc(sizeof(char*) * rows);
myarray[0] = malloc(cols * rows);
for (i = 1; i < rows; i++)
{
    myarray[i] = myarray[i-1] + cols;
}
Ciao
Alessandro.


Evidentemente avevo studiato sull'edizione sbaliata ;-)
Alessandro.

 ottimizzazione:
Vedi sopra.
A mio avviso, non c'e' alcuna ottimizzazione.


 Evidentemente avevo studiato sull'edizione sbaliata ;-)
Se hai studiato sulla prima, si'.
La prima edizione e' pre-ANSI e molto lontana, sia dall'attuale
standard del linguaggio (C99), che dal precedente (C89).


 standard del linguaggio (C99), che dal precedente (C89).
Infatti, il casting sul valore di ritorno non e' piu' necessario
con l'introduzione, nell'ANSI C, dei puntatori generici.
E' bastata una sfogliata di APUE per darti ragione in pieno.
Ad ogni modo, in moltissimo codice in circolazione, anche 
di alto livello, ad esempio
http://www.netlib.org/clapack
trovi ancora l'utilizzo del char* come puntatore generico, 
a posto del void*.
Perche' questo codice sia non sfrutti le features dell'ANSI C, 
non lo so, e sara' interessante approfondirlo.
Ciao,
-- 
Ludovico Basili
ludovic...@alliedtelesyn.com

 un vettore a una sola dimensione.
In alternativa, si potrebbe avere sia il vantaggio di una
allocazione in un singolo vettore, sia la leggibilita' della
notazione x[][] con qualcosa del genere:
char**myArray;
myArray = malloc(rows);
int i;
*myArray = malloc(rows*cols);
for (i=1;i!=rows;i++)
	myArray[i]=myArray[i-1]+cols;
Allocando una sola volta, c'e', ed, in tal caso, e' significativo
un aumento di performance (al variare di rows) ?



L'ottimizzazione consiteva nel fatto che chiami la malloc solo due volte
anziche rows+1 volte.
Alessandro.


E io che ho detto?-P
Alessandro.

non lo so, e sara' interessante approfondirlo.
Beh, una spiegazione plausibile e' che vogliano avere la certezza che
il programma funzioni si *ogni* implementazione del C esistente,
quindi sono obbligati a scrivere codice pre-ANSI :)
Tipo Postfix, che dovendo sostituire sendmail su ogni possibile
sistema non puo' dare per scontato l'esistenza del C 89 ovunque.
-- 
Mox
"Trust the programmer."
"Don't prevent the programmer from doing what needs to be done."
"Keep the language small and simple."
"Provide only one way to do an operation."

standard del linguaggio (C99), che dal precedente (C89).
Per Andrea: Beh, non e' detto :)  Visto che si sta parlando di cast
sul valore di ritorno della malloc anche se Test avesse studiato sulla
seconda edizione trovava questo "errore".
Per Test: il K&R e' uscito prima dello standard C89 e purtroppo ci
sono delle piccole diversita': eccoti le correzioni da apportare
http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html
...
e gia' che siamo in tema fatti 2 risate:
http://www.lysator.liu.se/c/schildt.html



Scusa, ma ho ricevuto il tuo messaggio dopo che io avevo risposto. 
Deve esserci qualche problema con le date.


 E io che ho detto?-P
Scusa, ma il tuo messaggio mi e' arrivato dopo che avevo risposto.
Devo avere noie col campo Date dell'header.

 
Secondo me e' piu' importante proteggersi dal refactoring del codice
che dalla prima stesura. Quado si scrive un programma si dovrebbero 
testare le cose pezzo a pezzo, e errori del genere saltano subito fuori
(o non vengono mai fatti :-)
  L'errore piu' preoccupante in progetti appena un po' piu' grossi e':
short *p;
  ...
p = malloc(cnt * sizeof(short));
se un anno dopo cambio "short" in "int" solo nella dichiarazione, il 
programma compilera' senza problemi, ma se non hai fortuna senza malloc 
debugger non ti tiri piu' fuori.
Se invece usi:
p = (short*) malloc(cnt * sizeof(short));
il compilatore, almeno, ti avvisa.
(d'accordo, sarebbe meglio usare un typedef ...)
Inoltre penso che sia molto piu' importante fare in modo il codice sia 
semplicemente portabile a C++ (anche se non sono un gran sostenitore del 
linguaggio), dove la promozione di void* non viene accettata.
  Odio i cast e la neccessita' di farli, ma ormai questo e' C, non 
smalltalk.
Marko

 E io che ho detto?-P
Scusa, ma mi era sfuggita l'ultima parte.
Ciao,
-- 
Ludovico Basili
ludovico_basili(at)
alliedtelesyn.com

 debugger non ti tiri piu' fuori.
short *p;
p = malloc(cnt * sizeof *p);
E' cosi' che si risolve il tuo problema, non usando il cast.


 il programma funzioni si *ogni* implementazione del C esistente,
Non credo sia per questo.  
Il C e' un linguaggio che e' stato visto e rivisto molte volte,
c'e' molto codice pre-ANSI, in giro, per il quale il cast sul
valore di malloc() e' necessario ed e' un'abitudine ormai 
consolidata.  E' difficile disabituarsi, anche se bisognerebbe
farlo.


 seconda edizione trovava questo "errore".
L'errata corrige sulla seconda edizione l'ho riportato
in un altro mio messaggio.  Il fatto e' che anche nella
prima edizione c'e' questo riferimento, ma non c'e' 
alcuna correzione in proposito.


 notazione x[][] con qualcosa del genere:
Lo ripeto: non c'e' alcun vantaggio nell'allocare un singolo
vettore, non c'e' alcun miglioramento della leggibilita',
non c'e' alcun aumento di prestazioni.  
Non complicate le cose semplici.
Usare un array bidimensionale va benissimo.


 anziche rows+1 volte.
Chiami la malloc() 1 sola volta per allocare M*N oggetti, anziche'
chiamare la malloc() M volte, per allocarne N.
Non la vedo una grande ottimizzazione e, comunque, anche se vi
fosse un minimo risparmio di tempo, non credo sia un fattore per
il quale valga la pena di convertire il codice.


 
urk, hai ragione.


Si ma un po' di meno (anche se poco) :-)
Alessandro.

 Non complicate le cose semplici.
Su questo hai ragione, ma e' comunque interessante approfondire questo
aspetto. Se, da una parte, la tua struttura potrebbe essere piu'
immediata in un gran numero di casi, avere un singolo
array potrebbe essere molto proficuo in tutte in quelle situazioni 
in cui ho bisogno di un accesso sia indicizzato (attraverso myArray)
che sequenziale (attraverso *myArray), ai dati.
A proposito, non risulta poi piu' semplice effettuare la free, se 
ho un unico vettore ? In questo caso, non ho bisogno di un ciclo for.


 ragionevole giustificazione.
Ti sbagli.  Nessuno parla di eccezioni "speciali".
Un array e' un'insieme di elementi disposti in memoria in modo
contiguo.  Ora, un array di array e' semplicemente un array i
cui elementi, a loro volta, sono array e quindi, per la regola
in base alla quale gli elementi sono disposti in modo contiguo,
gli array "elementi" sono disposti in modo contiguo.  
La matrice dell'esempio e' semplicemente un vettore di righe e
le righe sono disposte l'una di seguito all'altra, in memoria,
se viene allocata in modo statico.
Se, invece, viene allocata in modo dinamico, quello che si ha
non e' un array di array, ma un array di puntatori. 
Ogni puntatore "punta" a una zona di memoria diversa (ognuna
anche molto distante dall'altra).


 ho un unico vettore ? In questo caso, non ho bisogno di un ciclo for.
No, se conosci il C, non hai di questi problemi.


ho un unico vettore ? In questo caso, non ho bisogno di un ciclo for.
Non che ti cambi molto... avere un unico enorme array su cui simuli
una matrice pero' ti crea problemi quando devi fare una realloc.
http://www.eskimo.com/~scs/C-faq/q6.16.html
Le 2 soluzioni hanno praticamente lo stesso costo se riesci a tenere
tutto il blocco nella stessa pagina, o cumunque tutte le pagine che ti
servono in memoria. Hai dei cali di prestazioni se inizi a caricare
delle pagine nuove da disco.
Sono i casi sfigati che simuli negli esercizi di Sistemi Operativi per
valutare le politiche di riscrittura della cache :)
Ovviare a questo problema non e' facile e soprattutto non e'
direttamente alla tua portata (la paginazione e' un sistema
trasparente all'utente). L'unico accorgimento che puoi tenere su array
di enormi dimensioni e leggerlo in modo sequenziale, ovvero prima la
posizione di memoria n, poi n+1 e cosi' via... in pratica leggere per
righe e non per colonne cosi' eviti il caso sfigato.


 ottimizzazioni sul codice a monte (come D. Knuth insegna).
Non intendevo effettuare delle ottimizzazioni, bensi' mostrare il 
fatto che una struttura di questo tipo si presta ad essere letta sia 
sequenzialmente, sia in maniera indicizzata.
Alcune routines matematiche, ad esempio, sfruttano questa ambivalenza:
http://www.ulib.org/webRoot/Books/Numerical_Recipes/bookcpdf/c1-2.pdf


 p = (short*) malloc(cnt * sizeof(short));
no, dovresti usare:
p = malloc(cnt * sizeof(*p));
o ancora meglio:
p = calloc(cnt, sizeof(*p));
-- 
 < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
     Don't stand, REACT!      version 0.0.19. C, C++ and ASM developers
                              and beta testers are welcome!

 sequenzialmente, sia in maniera indicizzata.
Ci sono mille modi diversi di allocare questo tipo di dati, in C.
Questo e' sotto gli occhi di tutti.  Il problema e' se una 
rappresentazione e' realmente migliore di un'altra.
I miei interventi nascono in relazione a quello di test, in cui,
la sua/tua soluzione, viene proposta come un'"ottimizzazione".
Da parte mia, ho concluso ;)


 Ti sbagli.  Nessuno parla di eccezioni "speciali".
Il semplice fatto che un array di array sia allocabile *solo* staticamente
mi sembra un caso "particolare".
Non c'e' alcuna differenza tra l'array di array ed il mio vettore di
lunghezza rows*cols, a parte il fatto che la prima e' accessibile anche
mediante [row][col] e la seconda solo con [row*cols+col].
Semanticamnete sono la stessa cosa ma sintatticamente vengono trattati
diversamente!
Alessandro.


Se conosci un po' di matematica e aritmetica dei puntatori non hai problemi
neanche con [row*cols+col] :-)
Alessandro.

 problemi neanche con [row*cols+col] :-)
Vedi sopra, non ce n'e' bisogno nella stragrande maggioranza dei
casi.


 diversamente!
Forse hai perso il filo del discorso.
Tu hai postato un messaggio in cui affermavi:
"myarray[][4]={'1','2','3','4'},{'1','2','3','4'},{'1','2','3','4'}};
i valori le stringhe "1234" sarebbero state memorizzate su locazioni di
memoria consecutive, che sembra essere vero, ma e' solo accidentale."
Io ti ho risposto, facendoti notare che la disposizione delle
sequenze di caratteri (che tu chiami stringhe, ma che propriamente
stringhe non sono) non e' affatto accidentale.  Gli array sono,
come gia' detto, strutture dati statiche, in cui gli elementi
sono disposti l'uno di seguito all'altro, quindi e' lecito 
aspettarsi, anche in questo caso, che le varie sequenze siano 
memorizzate l'una di seguito all'altra.
Detto questo, tu ribatti con:
"Continuo a non capire la differenza tra array di array e 
 array di puntatori."
Se non hai capito questa differenza, non hai capito la differenza
tra array e puntatore che, in C, e' fondamentale.
Un array di array e' profondamente diverso da un array di
puntatori perche' array e puntatori sono profondamente 
diversi.



Su questo sono daccordo.
Ma non credo che il compilatore nelle sue ottimizzazioni giunga a ridurre il
numero delle chiamate della malloc come nel caso proposto da me e Ludovico.
Alessandro.

 tra array e puntatore che, in C, e' fondamentale.
E' vero, infatti fino a ieri ero convinto che gli array non esistessero
(cioe' che esistessero solo come le aree di memoria puntate dai puntatori).
Adesso so che esistono e non ne capisco il senso, mi sembrano una soluzione
poco pulita che turba l'armonia del linguaggio C per come lo conoscevo, ma
che vuoi, dopo averne fatto a meno per tanti anni... :-)
Alessandro.

 da me e Ludovico.
Assolutamente no.  Il compilatore non ottimizza in questo senso.


 soluzione poco pulita che turba l'armonia del linguaggio C 
Gli array sono strutture dati, quindi il loro senso e' chiaro,
servono a memorizzare dati.  Non preoccuparti per il C, non
ne viene turbato ;)


  }
perfetto, grazie, ora ho capito come fare quello che interessa a me:
/*
 * allocazione dinamica di una array bidimensionale
 */
#include <stdio.h>
#include <stdlib.h>
static void myalloca(double ***vet, int righe, int colonne);
int main()
{
	double **vet1=NULL;
	double **vet2=NULL;
	int righe=2, colonne=3;
	int n,l;
	printf("primo\n");
	vet1 =    calloc(righe          , sizeof(double *)); /* righe */
	vet1[0] = calloc(righe * colonne, sizeof(double  )); /* righe x colonne */
	for(n = 1; n < righe; n++)
	{
		vet1[n] = vet1[0] + n * colonne;
	}
	for(n=0; n<righe; n++)
	{	
		for(l=0;l<colonne; l++)
		{	
			printf("%p ",vet1[n]+l);
		}
		printf("\n");
		for(l=0;l<colonne; l++)
		{	
			printf("%f ",vet1[n][l]);
		}
		printf("\n");
	}
 
	printf("secondo\n");
	myalloca(&vet2, righe, colonne);
	for(n=0; n<righe; n++)
	{	
		for(l=0;l<colonne; l++)
		{	
			printf("%p ",vet2[n]+l);
		}
		printf("\n");
		for(l=0;l<colonne; l++)
		{	
			printf("%f ",vet2[n][l]);
		}
		printf("\n");
	}
 
	free(vet1[0]);
	free(vet1);
	free(vet2[0]);
	free(vet2);
	return 0;
}
void myalloca(double ***vet2, int righe, int colonne)
{
	int n;
	(*vet2) =    calloc(righe          , sizeof(double *)); /* nrows */
	(*vet2)[0] = calloc(righe * colonne, sizeof(double  )); /* nrows x ncolumns */
	for(n = 1; n < righe; n++)
	{
		(*vet2)[n] = (*vet2)[0] + n * colonne;
	}
}
grazie ancora.
(avevo problemi ad allocare la matrice in una funzione, fuori dal
main...)
-- 
Pa.Ped, Como
http://www.fastflow.it/~paolop
VOTE AGAINST SPAM! 
http://www.politik-digital.de/spam/it/
Contro i brevetti software: 
http://petition.eurolinux.org/index_html