Newsgroup: it.comp.lang.c
Titolo: Significato di [] nelle funzioni

Salve a tutti, mi spiegate cosa significa una dichiarazione del tipo:
void func(int array[]);
Seguendo il mio libro di testo questa funzione richiede alla chiamata un
vettore passato per riferimento in quanto nella lista degli argomenti è
stato dichiarato  un vettore di dimensione variabile. Ma non né sono sicuro.
Ciao.

 stato dichiarato  un vettore di dimensione variabile.
?????
Ma perché parli di vettore a dimensione variabile?
Come penso tu abbia già capito i vettori sono delle variabili strutturate un
po' particolari in quanto su di esse non è definito l'operatore di
assegnamento e soprattutto nelle espressioni, ad esclusione di tre casi,
decadono nell'indirizzo di memoria del primo elemento.
Prima di procedere partiamo da un semplice esempio:
void func(int* a, int b)
     {
      *a = 10;
       b = 10;
       }
int main(void)
     {
     int a = 10;
     func(&a, a);
     }
In questo esempio è chiaro capire in che modo viene effettuato il passaggio,
pertanto passiamo ai vettori:
void func(int array1[]);
int main(void)
        {
         int array[10];
         func(array);
         }
Concentriamoci sull'istruzione di chiamata alla funzione: come già detto in
precedenza i vettori decadono nell'indirizzo di memoria del loro primo
elemento e nell'esempio array decade in un (int*), ovvero un puntatore a
variabile intera.
Pertanto quello che viene passato alla funzione è solamente l'indirizzo di
memoria del primo elemento - non del vettore - pertanto il rispettivo
parametro formale dev'essere un contenitore adeguato a contenere tale
valore, quindi array1 sarà una variabile di tipo puntatore a int.
Penso di conoscere il libro di testo, non è forse quello che dice: "un
parametro formale dichiarato con le [] non è variabile di tipo puntatore ma
solamente un reference ad un qualsiasi vettore unidimensionale di dimensione
n".
Se è così vuol dire che abbiamo studiato sullo stesso libro che è un
guazzabuglio di fregnaccie.
Tornando al discorso originale ti posso dire che il parametro int array1[]
non richiede necessariamente un vettore, ma può essere una qualsiasi
espressione in grado di restuire un (int*).
Quindi, per quanto si utilizzi un vettore, all'atto di chiamata della
funzione quello che viene passato è sempre e solo l'indirizzo di una
variabile di tipo semplice.
Comunque valuta alcuni vantaggi:
void func(int array[], int num);
/* altro codice */
int array[10];
int array1[12];
int array2[16];
func(array, 10);
func(array1, 12);
func(array2, 16);
Questo tipo di funzione è in grado di operare con variabili strutturate
sostanzialemente di 3 tipi diversi - int [10] - int [12] - int [16] - in
quanto in tutte le chiamate quello che viene passato a func è sempre
l'indirizzo di memoria di una variabile intera. Quindi, approfittando di
questo, si può aggiungere un secondo parametro in modo tale da sapere su
quanti elementi si potrà operare.
E' obbligatorio passare solamente l'indirizzo di memoria del primo?
Certamente no:
 func(array + 1, 9);
In questo modo la funzione opererà solamente sui restanti nove elementi del
vettore.
Giunti a questo punto, si può ancora parlare di passaggio per riferimento di
un vettore? No.
Se proprio tu volessi passare un vettore per riferimento potresti modificare
func in modo tale da avere:
void func(int(*array1)[10], int num)
/* altro codice */
int array[10];
int array1[12];
int array2[16];
func(&array, 10) /* giusto */
func(array, 10); /* errore*/
func(&array1, 12); /*errore */
func(&array2, 16); /* errore */
Come puoi ben vedere sparisce anche la necessità di un secondo parametro
atto a contenere il numero di elementi.
Nella prima chiamata a funz array non decade nell'indirizzo di memoria del
suo primo elemento ma conserva il suo significato di variabile strutturata
in modo tale che l'operatore & restituisca l'indirizzo di memoria di una
variabile di tipo int[10].
Comunque, rispetto all precedente prototipo di funz, questa può funzionare
solamente con variabili array dello stesso tipo e purtroppo il C non offre
un operatore simile allo smart-pointer per le strutture in grado di
dereferenziare e selezionare in sul colpo vettore ed elemento, cosa che
viene lasciata di conseguenza al programmatore. Esempio:
     (*array1) [0] = 10;
Pertanto preferisco passare un vettore non per valore - in quanto non è
permesso - e neppure per riferimento ma semplicemente passando l'indirizzo
del  suo primo elemento.
Spero di averti chiarito le idee.
 Ciao.

  Ciao.
Ho dato l'esame di c tranquillamente ma quello che hai detto mi ha messo un
casino in testa pazzesco O_o
Ciao
Claudio

 Claudio
Ciao.

 wrote in message
news:CB2p8.92611$1S3.2...@twister1.libero.it...


 (di dimensione definita a posteriori) a variabili del tipo specificato.
Questo è un vettore di puntatori:
int* array[10];
e su questo non ci piove.
Questo:
int(*array) [10];
è una variabile di tipo puntatore a vettore di 10 int.
Per quanto riguarda i parametri formali:
void func(int array[]);
void func1(int* array);
/* qualche esempio di chiamata */
int a = 10, array[10];
func(&a); /*Funziona, eppure a è solo variabile intera e
non un vettore:-) */
func(array); /* funziona ancora */
func(array + 1); /* funziona */
func(&array[0]); /* funziona */
func(&array); /* errore */
func1(&a); /*Funziona */
func1(array); /* funziona ancora */
func1(array + 1); /* funziona */
func1(&array[0]); /* funziona */
func1(&array); /* errore */
Questo per dire che nella dichiarazione dei parametri formali l'utilizzo di
[] o * è la medesima cosa. In entrambi i casi, alla chiamata della funzione,
verrà creata una variabile di tipo puntatore a int,  di nome array.
Altri esempi:
int array[10];
int array2[11];
int* ptr = array; /* corretto */
int* ptr1 = array1; /* corretto */
int(*ptr2)[10] = &array; /* corretto */
int(*ptr3)[10] = array; /* errore */
int(*ptr4)[10] = array1; /* errore */
Inoltre quelli che tu hai definito "km di orba" sono una semplicissima
riduzione di quello che puoi leggere da parte di autorevoli autori, come
Bruce Eckel, o semplicemente da un helping in linea come quello incluso con
i compilatori della borland.
Ed aggiungo che se non credi a quello che ho scritto basta che tu provi a
fare un bel copia-incolla verso il tuo compiler, in modo tale da potermi
segnalare in modo concreto - e non con mezzi riferimenti - le fregnaccie che
posso aver detto.
Ciao.

 posso aver detto.
Non ho mai detto che tu abbia detto fregnacce, ho detto solo che a parer mio
hai complicato la storia molto più di quanto meritasse.
Ciao
Claudio

 ci piove, però non sei chiaro se scrivi che [] e * sono la stessa cosa.
Nella dichiarazione di parametri formali scrivere:
void func(int array[]);
o
void func(int* array);
è la medesima cosa in quanto le parentesi [] vengono considerate dal
compilatore solo come una sintassi alternativa al *. Ripeto solo nella
dichiarazione dei parametri formali.
Se proprio tu non fidassi, prova a verificare la seguente funzione:
void funzione(int array[])
     {
     int array1[10];
     array1++; /* errore */
     array++; /* corretto*/
     }
 array[] non è un vettore in questo caso.
E' ovvio, e lo ripeto, che dichiarare due variabili :
       int* ptr; /* una variabile di tipo puntatore */
       int array[10]; /* una variabile di tipo array di 10 int*/
sono due cose estremamente diverse.
L'unica cosa che non devi dimenticare è che il nome di un vettore, tranne
nel caso in cui sia utilizzato con & o sizeof, decade nel puntatore al suo
primo elemento.
Pertanto un'espressione del tipo:
int array[10];
int* ptr = array;
è assolutamente valida in quanto alla variabile ptr si assegna un valore di
tipo (int*), che nel nostro caso risulterà l'indirizzo di memoria del primo
elemento.
Quindi se in una chiamata di funzione scrivessi
    func(array);
dove array è un vettore di elementi di tipo int, quello che passo alla
funzione è un (int*).
Ciao.

ci piove, però non sei chiaro se scrivi che [] e * sono la stessa cosa.
Sono diversi ma nel contempo molto simili.
Un array e' l'indirizzo di un'area di memoria (non modificabile)
abbastanza grande da contenere N elementi (dove N va' indicato al
momento della dichiarazione dell'array).
Tu potresti fare la stessa cosa usando un puntatore e a tutti gli
effetti noteresti solo 2 differenze:
1)
- sizeof(puntatore) = dimensione del puntatore all'array in char
- sizeof(array non decaduto) = dimensione in byte dell'area di memoria
puntata dall'array.
2) l'indirizzo di memoria corrispondente all'array non e' modificabile
(mentre per il puntatore generalmente non e' vero).
Un array decade sempre a puntatore al primo elemento tranne in 3 casi
(cut&paste da un messaggio di Andrea Laforgia tanto per la cronaca):
- quando e' argomento di sizeof
- quando e' argomento di & (operatore address-of)
- quando e' un literal string di inizializzazione di un
vettore.
A parte queste differenze tu puoi usare un array come se fosse un
puntatore e un puntatore come se fosse un array (con la stessa
identica sintassi):
char vettore[10];
char * puntatore = malloc(10);
Tu puoi hai che:
- *(vettore+2) == vettore[2]
- *(puntatore+2) == puntatore[2]
Ovviamente non pui fare: 
vettore += 1 
perche' non puoi modificare l'indirizzo di memoria di vettore, mentre
e' perfettamente lecito:
puntatore += 1
Nota: Non e' corretto dire che un vettore non e' un puntatore a
variabili dello stesso tipo come dici tu, ma e' l'indirizzo di memoria
di uno spazio sufficientemente grande da contenere queste variabili.
Leggiti il K&R a proposito della differenza tra array e puntatori :)
-- 
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."