Mentre stai solo imparando C, ti consiglio di provare davvero a capire prima le differenze tra array e puntatori anziché le cose comuni .
Nell'area dei parametri e delle matrici, ci sono alcune regole confuse che dovrebbero essere chiare prima di continuare. Innanzitutto, ciò che dichiari in un elenco di parametri viene considerato speciale. Ci sono situazioni in cui le cose non hanno senso come parametro di funzione in C. Queste sono
- Funziona come parametri
- Matrici come parametri
Matrici come parametri
Il secondo forse non è immediatamente chiaro. Ma diventa chiaro se si considera che la dimensione di una dimensione di matrice fa parte del tipo in C (e una matrice la cui dimensione di dimensione non viene fornita ha un tipo incompleto). Quindi, se si crea una funzione che accetta un array per valore (riceve una copia), potrebbe farlo solo per una dimensione! Inoltre, le matrici possono diventare grandi e C cerca di essere il più veloce possibile.
In C, per questi motivi, i valori di matrice non esistono. Se vuoi ottenere il valore di un array, quello che ottieni invece è un puntatore al primo elemento di quell'array. E qui in realtà giace la soluzione. Invece di disegnare un parametro di array non valido in anticipo, un compilatore C trasformerà il tipo del rispettivo parametro in un puntatore. Ricorda questo, è molto importante. Il parametro non sarà un array, ma sarà invece un puntatore al rispettivo tipo di elemento.
Ora, se si tenta di passare un array, ciò che viene passato è invece un puntatore al primo elemento degli array.
Escursione: funziona come parametro
Per il completamento, e poiché penso che questo ti aiuterà a capire meglio la questione, esaminiamo quale sia lo stato delle cose quando provi ad avere una funzione come parametro. Anzi, per prima cosa non avrà alcun senso. Come può un parametro essere una funzione? Eh, vogliamo una variabile in quel posto, ovviamente! Quindi, ciò che il compilatore fa quando ciò accade è, ancora una volta, trasformare la funzione in un puntatore a funzione . Tentare di passare una funzione passerà invece un puntatore a quella rispettiva funzione. Quindi, i seguenti sono gli stessi (analogo all'esempio dell'array):
void f(void g(void));
void f(void (*g)(void));
Si noti che *g
sono necessarie le parentesi . Altrimenti, specifica una funzione di ritorno void*
, anziché un puntatore a una funzione di ritorno void
.
Torna agli array
Ora, all'inizio ho detto che le matrici possono avere un tipo incompleto, cosa che accade se non si specifica ancora una dimensione. Dato che abbiamo già capito che un parametro array non esiste ma invece qualsiasi parametro array è un puntatore, le dimensioni dell'array non contano. Ciò significa che il compilatore tradurrà tutto quanto segue e tutti sono la stessa cosa:
int main(int c, char **argv);
int main(int c, char *argv[]);
int main(int c, char *argv[1]);
int main(int c, char *argv[42]);
Certo, non ha molto senso essere in grado di mettere qualsiasi dimensione in esso, ed è appena buttato via. Per questo motivo, C99 ha trovato un nuovo significato per quei numeri e consente ad altre cose di apparire tra parentesi:
// says: argv is a non-null pointer pointing to at least 5 char*'s
// allows CPU to pre-load some memory.
int main(int c, char *argv[static 5]);
// says: argv is a constant pointer pointing to a char*
int main(int c, char *argv[const]);
// says the same as the previous one
int main(int c, char ** const argv);
Le ultime due righe dicono che non sarai in grado di cambiare "argv" all'interno della funzione - è diventato un puntatore const. Tuttavia, solo pochi compilatori C supportano quelle funzionalità C99. Ma queste caratteristiche chiariscono che la "matrice" non è in realtà una. È un puntatore.
Un avvertimento
Nota che tutto ciò che ho detto sopra è vero solo quando hai un array come parametro di una funzione. Se si lavora con array locali, un array non sarà un puntatore. Si comporterà come un puntatore, perché come spiegato in precedenza un array verrà convertito in un puntatore quando viene letto il suo valore. Ma non deve essere confuso con i puntatori.
Un esempio classico è il seguente:
char c[10];
char **c = &c; // does not work.
typedef char array[10];
array *pc = &c; // *does* work.
// same without typedef. Parens needed, because [...] has
// higher precedence than '*'. Analogous to the function example above.
char (*array)[10] = &c;