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 str
dell'array. Questo vale per qualsiasi funzione chiamata con un'espressione matrice come argomento (praticamente qualsiasi delle str*
funzioni, *scanf
e *printf
funzioni, 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 x
e y
sono oggetti distinti da a
e b
, perciò la modifica x
e y
non si riflettono a
e b
. Dato che vogliamo modificare i valori di a
e 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 x
e y
, ma i valori di cosa x
e y
puntiamo a . Scrivere su *x
è diverso dallo scrivere su x
; non stiamo aggiornando il valore in x
sé, otteniamo una posizione da x
e 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 stream
non 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à.