Newsgroup: it.comp.lang.c
Titolo: I puntatotori ad array di int.

Salve a tutti,
sono approdato da poco al C da java (pensa te che salto!), e mi sono subito
accorto che č un altro mondo. Io perň sono adattabile (!?), e quindi vado
avanti imperterrito. Mi scuso da subito se, avendo imparato quel poco che so
smanettando sul codice, senza una guida introduttiva o un esperto accanto,
userň spesso termini imprecisi... cercherň comunque di rendere il piů chiaro
possibile ciň che sto cercando di dire!
Veniamo a noi: mi pare di aver capito che in C esistono i "puntatotori ad
array [n] di [tipo]" (semplifichiamo intanto considerando che il tipo sia
int, tanto non cambia nulla). In pratica se scrivo:
int pippo[n][m];
o
int **pluto
non sto scrivendo la stessa cosa, principalemnte per due motivi:
1) pippo e pluto non sono puntatori allo stesso tipo di dato: in particolare
il primo punta ad array[m] di int, il secondo a puntatore a int, che benchč
equivalenti per molte operazioni, per molte altre non lo sono. Ad esempio se
incremento di uno pluto, avanzo di 4 byte (la dimensione di un puntatore),
mentre se incremento di 1 pippo avanzo di m*4 byte, cioč la dimensione di
una array[m] di int.
2) nel primo caso viene allocata la memoria, mentre nel secondo ho solo
definito un puntatore. A questa "differenza" avrei potuto perň porre
rimensio scrivendo:
int (*pippo)[m]
definendo cosě un puntatore ad array [m] di int senza allocare al memoria.
Giusto fin qui?
Bane, la mia domanda semplice (almeno spero) č: con che sintassi si puň, se
si puň, specificare "puntatore ad array [m] di int" come tipo ritornato da
una finzione, oppure per un cast? Un esempio del primo caso per chiarire:
*** miafunzione(void)
{
    int pippo[100][100] ;
    int i, j;
    for (i=0;i<100;i++)
        for (j=0;j<100;j++)
            pippo[i][j] = i*j;
    retunr pippo;
}
Cosa ci metto al posto di *** ? int** ovviamente non va per i motivi sopra
scritti. Per analogia con:
int (*pippo)[m]
mi verrebbe da scrivere int (*)[m], o *[m], ma non va. Allora? Ho cercato in
giro e chiesto a qualche amico (non troppo esperto), ma non ho trovato
soluzione... volete dirmi che in C il tipo "puntatore ad array[m] di int"
esiste ma non esiste una sintassi per usarlo se non in una definizione? C'č
un motivo per ciň?
Grazie
Giacomo
P.S. Soluzione alternative so che ne esistono: passare il puntatore
all'array fra i parametri, usare le struct, appiattire l'array
bidimensionale [m][n] in una monodimensionale [n*m], ecc... ma a me
interesserebbe sapere, se c'č, il modo di fare quel che ho chisto senza
trucchi. Se poi non c'č, mi piacerebbe comunque sapere se č una svista
banale (non credo!) o esiste un motivo profondo che nč detta
l'impossibilitŕ...

 esiste ma non esiste una sintassi per usarlo se non in una definizione?>
Esiste,esiste.
Stai facendo parecchia confusione, anche nella definizione del tuo problema.
Ma non ti preocupare perchè storicamente chi si avvicina al C/C++ incontra
un po' di difficoltà con i puntatori e (soprattutto) con i puntatori ad
arrays o ad altri puntatori.
L'argomento è troppo vasto per rispondere qui.
Ti consiglio di studiare l'argomento sull'ottimo "Linguaggio C seconda
edizione" di Kernigham e Ritchie al capitolo 5.
Ciao, Fabio.
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

 un motivo per ciň?
Come vedi esiste, ma probabilmente e` perfettamente inutile (o almeno, 
non ne vedo l'utilita`).
Visti tutti i tuoi dubbi (leciti), ti consiglio di leggere *tutte* le 
FAQ di comp.lang.c (cerca con Google) relative ad array e puntatori. Si 
tratta di un documento di dimensione notevole, ma contiene tutte le 
risposte alle tue domande. L'argomento e` troppo ampio per essere 
affrontato in questa sede.

 esempio 1
Intendo in questo modo:
int (*p)[M] = pippo + 1;
Ovvero sommare ma senza modificare pippo (il che e` impossibile).

 affrontato in questa sede.
Senz'altro lo farň, appena avrň il tempo (a proposito, dove sono le faq?).
Solo che avendo una certa urgenza avevo l'esigneza di circoscrivere il
problema specifico, e una richiesta diretta era l'unico modo.
Ti ringrazio molto.
Giacomo

 Non ho capito qualcosa?
guardando il codice che hai postato direi che sono diverse le
cose che non hai capito. E, scusa la franchezza, la prima
cosa che dovresti capire e' che il C non puoi impararlo "a tentativi".
Bisogna che ti procuri un manuale e te lo studi.
Per quanto riguarda la domanda sullo scope, la faccenda e' molto
semplice.
1) Non c'e' un garbage collector in C.
2) Al compilatore non importa se una zona di memoria e' puntata o meno
da una variabile.
3) Bisogna che capisci bene la differenza tra allocare qualcosa
staticamente o dinamicamente.
Esempi:
int *Pippo()
{
   int x[10];
   return x;
}
int *y;
y=Pippo();
y[5]=22;
e' sbagliata perche' l'array allocato staticamente dentro la funzione
cessa di esistere quando la funzione finisce. Non viene allocato
realmente quando tu chiami la funzione Pippo, ma il compilatore
sa che a run-time dovra' riservare una certa quantita' di memoria per x.
Quando Pippo termina quella zona di memoria potrebbe essere riusata per
variabili di altre funzioni. Quindi potrebbe funzionare, ma prima o poi
ti causera' inenarrabili casini.
int *Pippo(int quanti)
{
   int *x;
   x = calloc(quanti,sizeof(int));
   return x;
}
int *y;
y=Pippo(555);
y[5]=22;
questa e' giusta. Il vettore x viene allocato dinamicamente in una 
diversa zona di memoria. La "variabile" x cessa di esistere, ma non
viene liberata automaticamente la zona di memoria puntata da x. 
Importante: non e' che non viene liberata perche' io passo fuori x,
non viene liberata perche' per liberare memoria allocata con malloc o 
calloc hai bisogno di invocare la funzione free(). Al compilatore non
importa nulla se perdi il puntatore ad una zona di memoria allocata,
rendendola di fatto inutilizzabile e non-liberabile: sono problemi tuoi.
Se io scrivo
int *y;
y = Pippo(50);
ho allocato un array di 50 interi e ci posso accedere, per esempio
con y[5]=11;
Se io scrivo
Pippo(11);
senza assegnare il puntatore ritornato ho appena perso l'accesso ad
un vettore di 11 interi che non potro' piu' utilizzare o liberare.
ciao,
g.

 staticamente o dinamicamente.
[Cut]
Ok, quello che scrivi è molto chiaro (almeno mi sembra) e te ne ringrazio.
Ti chiedo allora una cosa: anche se la dimensione di un array la si consoce
a compile-time, potrebbe essere utile usare il malloc (o calloc, se ho
capito bene la differenza sta nel fatto che il primo non inizializza a 0 la
memoria) per essere garantiti che quella memoria è riservata? In pratica,
epr tornare al mio esempio, scrivere:
*** miafunzione(void)
{
    int (*pippo)[100] ;
    pippo = (***)malloc(100*100*sizeof(int));
    int i, j;
    for (i=0;i<100;i++)
        for (j=0;j<100;j++)
            pippo[i][j] = i*j;
    return pippo;
}
andrebbe bene, nel senso che la memoria allocata per pippo sta lì e la posso
usare fintato che non la libero esplicitamente con free()?
Rimane il problema di cosa mettere al posto di quei maledetti tre asterischi
(***) per indicare "puntatore ad array[100] di int". La sintassi suggerita
da Enrico:
int (*miafunzione(void))[100]
non sembra funzionare... (e comunque, come la adatterei per il cast? Forse:
"pippo = (*malloc(100*100*sizeof(int))[100]" ?)
Grazie
Giacomo

 }
non va bene. Se vuoi passarla fuori bisogna che pippo sia
interamente allocata in modo dinamico.
Cosi' funziona: dichiari un array di puntatori (che potra' essere
riferito come un puntatore al primo puntatore), e poi allochi
un array per ogni puntatore. I calloc si possono anche sostituire
con dei malloc.
#include<stdio.h>
#include<stdlib.h>
int **miafunzione(void)
{
   int **pippo;
   int i,j;
   pippo = calloc(100,sizeof(int *));
   for (i=0; i<100; i++) pippo[i]=calloc(100,sizeof(int));
   for (i=0; i<100; i++)
     for (j=0; j<100; j++) pippo[i][j]=i*j;
   return pippo;
}
oppure volendo
int **miafunzione(int N, int M)
{
   int **pippo;
   int i,j;
   pippo = calloc(N,sizeof(int *));
   for (i=0; i<N; i++) pippo[i]=calloc(M,sizeof(int));
   for (i=0; i<N; i++)
     for (j=0; j<M; j++) pippo[i][j]=i*j;
   return pippo;
}
int main()
{
   int **A;
   A = miafunzione();  // oppure A=miafunzione(100,100);
   A[1][2]=222;
   printf("%d %d %d\n",A[11][7],A[7][13],A[1][2]);
   return 0;
}
Ciao,
g.

 Averne il tempo!
il K&R nuova edizione italiana sono 282 pagine con appendici.
Senza contare le appendici sono 195.
imho vale la pena :)
-- 
Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it.
    - Brian W. Kernighan

 imho vale la pena :)
Ci proverò, ma per esperienza personale pochi manuali valgono una
discussione costruttiva con eprsone esperte...
Ciao
Giacomo

 interamente allocata in modo dinamico.
Non capisco. La mia memoria è interamente allocata in modo dinamico: un solo
malloc da 40000 byte (se "facciamo finta" per semplcità e rapidità di
scrittura che un int sia 4 bytes).
Per come la interpreto io, con il mio metodo alloco 40000 bytes di memoria
(contigui) e mi tengo un puntatore al primo di essi (X). Il puntatore è di
tipo "puntatore ad array[100] di int", quindi se scrivo pippo[1] lui sa che,
rispetto al puntatore deve muoversi avanti di 400 bytes. In pratica non ho i
puntatori espliciti ad ogni riga della matrice, ma li posso ricostruire "al
volo" nel senso che pippo[i] viene interpretata come l'operazione: punta
alla poszione di pippo (X) + i volte la dimensione del tipo di dato di cui
pippo è puntatore (array[100] di int, ciè 400 bytes).
Nel tuo caso, invece di fare un solo malloc, ne faccio prima uno con il
quale alloco 400 bytes (se consideriamo che 4 bytes sia anche la diemensione
dei puntatori); questi 400 bytes li "riempio" con 100 indirizzi di memoria a
100 blocchi (ognuno di dimensione 400 bytes), allocati con malloc. In questo
caso pippo[i] si traduce non con l'operaizone di prima, ma con "vai a
prendere l'indirizzo nella posizone i-esima del vettore pippo".
Ora, il discorso appena fatto può avere mille e mille errori o imprecisioni,
ma non capsico perchè tu dica che nel primo caso non ho allocato
dinamicamente tutta la memoria...
Ciao
Giacomo

 found '{' expecting ';'"
Qui c'e` qualcosa che non va. Il prototipo di miafunzione l'ho ricavato 
tramite il programma cundecl (dato che anche a me non era venuto in 
mente subito):
[~]$ cundecl
declare miafunzione as function that expects (void) returning pointer to 
array[100] of int;
int (*miafunzione(void))[100];
Il programma che ho scritto e` il seguente:
/* demo.c */
int (*miafunzione(void))[100]
{
     int pippo[100][100];
     return pippo;
     /* Questo e` sbagliato per quanto detto altrove,
      * ma sintatticamente corretto. */
}
int main(void)
{
     int (*a)[100];
     a = miafunzione();
     return 0;
}
Compilando con gcc si ha:
[/tmp]$ gcc -Wall -ansi -pedantic -o demo demo.c
demo.c: In function `miafunzione':
demo.c:5: warning: function returns address of local variable
Nessun errore di sintassi, solo un (corretto) warning dovuto al fatto di 
restituire un puntatore a qualcosa che non esitera` piu`.
O sfugge qualcosa anche a me, oppure hai invocato il compilatore in modo 
erroneo (prova a usare la modalita` ANSI C), altrimenti non so che 
pensare...