C'è uno schema quando si tratta di matrici e funzioni; all'inizio è solo un po 'difficile.
Quando si ha a che fare con le matrici, è utile ricordare quanto segue: quando un'espressione di matrice appare nella maggior parte dei contesti, il tipo di espressione viene implicitamente convertito da "matrice di elementi N di T" a "puntatore a T" e il suo valore è impostato per puntare al primo elemento dell'array. Le eccezioni a questa regola sono quando l'espressione di matrice appare come un operando dell'operatore &o sizeof, oppure quando si utilizza un letterale stringa come inizializzatore in una dichiarazione.
Pertanto, quando si chiama una funzione con un'espressione di matrice come argomento, la funzione riceverà un puntatore, non una matrice:
int arr[10];
...
foo(arr);
...
void foo(int *arr) { ... }
Ecco perché non usi l' &operatore per argomenti corrispondenti a "% s" in scanf():
char str[STRING_LENGTH];
...
scanf("%s", str);
A causa della conversione implicita, scanf()riceve un char *valore che punta all'inizio strdell'array. Questo vale per qualsiasi funzione chiamata con un'espressione matrice come argomento (praticamente qualsiasi delle str*funzioni, *scanfe *printffunzioni, ecc).
In pratica, probabilmente non chiamerai mai una funzione con un'espressione array usando l' &operatore, come in:
int arr[N];
...
foo(&arr);
void foo(int (*p)[N]) {...}
Tale codice non è molto comune; devi conoscere la dimensione dell'array nella dichiarazione della funzione e la funzione funziona solo con i puntatori ad array di dimensioni specifiche (un puntatore a un array a 10 elementi di T è un tipo diverso rispetto a un puntatore a un array a 11 elementi di T).
Quando un'espressione di matrice appare come un operando &all'operatore, il tipo dell'espressione risultante è "puntatore alla matrice di elementi N di T" o T (*)[N], che è diverso da una matrice di puntatori ( T *[N]) e un puntatore al tipo di base ( T *).
Quando si ha a che fare con funzioni e puntatori, la regola da ricordare è: se si desidera modificare il valore di un argomento e farlo riflettere nel codice chiamante, è necessario passare un puntatore all'oggetto che si desidera modificare. Ancora una volta, gli array gettano un po 'di chiave inglese nelle opere, ma ci occuperemo prima dei casi normali.
Ricorda che C passa tutti gli argomenti delle funzioni in base al valore; il parametro formale riceve una copia del valore nel parametro effettivo e qualsiasi modifica al parametro formale non si riflette nel parametro effettivo. L'esempio comune è una funzione di scambio:
void swap(int x, int y) { int tmp = x; x = y; y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);
Otterrai il seguente output:
prima dello scambio: a = 1, b = 2
dopo lo scambio: a = 1, b = 2
I parametri formali xe ysono oggetti distinti da ae b, perciò la modifica xe ynon si riflettono ae b. Dato che vogliamo modificare i valori di ae b, dobbiamo passare i puntatori ad essi alla funzione di scambio:
void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);
Ora il tuo output sarà
prima dello scambio: a = 1, b = 2
dopo lo scambio: a = 2, b = 1
Si noti che, nella funzione di scambio, non cambiamo i valori di xe y, ma i valori di cosa xe y puntiamo a . Scrivere su *xè diverso dallo scrivere su x; non stiamo aggiornando il valore in xsé, otteniamo una posizione da xe aggiorniamo il valore in quella posizione.
Questo è altrettanto vero se vogliamo modificare un valore di puntatore; se scriviamo
int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);
quindi stiamo modificando il valore del parametro di input stream, non quello a cui stream punta , quindi la modifica streamnon ha alcun effetto sul valore di in; affinché questo funzioni, dobbiamo passare un puntatore al puntatore:
int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);
Ancora una volta, gli array gettano un po 'di chiave inglese nelle opere. Quando si passa un'espressione di matrice a una funzione, ciò che la funzione riceve è un puntatore. A causa della modalità di definizione della sottoscrizione di array, è possibile utilizzare un operatore di sottoscrizione su un puntatore nello stesso modo in cui è possibile utilizzarlo su un array:
int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}
Si noti che gli oggetti array non possono essere assegnati; cioè, non puoi fare qualcosa del genere
int a[10], b[10];
...
a = b;
quindi vuoi stare attento quando hai a che fare con i puntatori alle matrici; qualcosa di simile a
void (int (*foo)[N])
{
...
*foo = ...;
}
non funzionerà.