Il s'agit d'un modèle lorsque vous traitez avec des tableaux et des fonctions; c'est juste un peu difficile à voir au premier abord.
Lorsque vous traitez avec des tableaux, il est utile de rappeler ce qui suit: lorsqu'un tableau de l'expression apparaît dans la plupart des contextes, le type de l'expression est implicitement converti à partir "N-élément de tableau de T" à "pointeur de T", et sa valeur est définie pour pointer vers le premier élément dans le tableau. Les exceptions à cette règle lorsque la rangée expression apparaît comme un opérande de l' &
ou sizeof
opérateurs, ou quand c'est un littéral de chaîne utilisé comme un initialiseur dans une déclaration.
Ainsi, lorsque vous appelez une fonction avec un tableau d'expression comme un argument, la fonction reçoit un pointeur, pas un tableau:
int arr[10];
...
foo(arr);
...
void foo(int *arr) { ... }
C'est pourquoi vous n'avez pas utiliser l' &
de l'opérateur pour les arguments correspondant à "%s" scanf()
:
char str[STRING_LENGTH];
...
scanf("%s", str);
En raison de la conversion implicite, scanf()
reçoit un char *
valeur qui pointe vers le début de l' str
tableau. Cela est vrai pour toute fonction appelée avec un tableau d'expression comme un argument (à peu près tout de l' str*
fonctions, *scanf
et *printf
des fonctions, etc.).
Dans la pratique, vous n'aurez probablement jamais appeler une fonction avec un tableau de l'expression à l'aide de l' &
de l'opérateur, comme dans:
int arr[N];
...
foo(&arr);
void foo(int (*p)[N]) {...}
Ce code n'est pas très commun; vous devez connaître la taille du tableau dans la déclaration de la fonction, et la fonction ne fonctionne qu'avec des pointeurs vers des tableaux de tailles (un pointeur vers un tableau de 10 éléments de T est un type différent d'un pointeur sur un 11-élément de tableau de T).
Lorsqu'un tableau de l'expression apparaît comme un opérande de l' &
de l'opérateur, le type de l'expression qui en résulte est "pointeur de N-élément de tableau de T", ou T (*)[N]
, ce qui est différent à partir d'un tableau de pointeurs (T *[N]
) et un pointeur vers le type de base (T *
).
Lorsque vous traitez avec les fonctions et les pointeurs, la règle à retenir est la suivante: si vous souhaitez modifier la valeur d'un argument et qui reflètent le code appelant, vous devez passer un pointeur vers la chose que vous voulez modifier. Encore une fois, les tableaux de jeter un peu de bâtons dans les travaux, mais nous allons traiter le cas de la première.
Rappelez-vous que C passe tous les arguments d'une fonction par valeur, le paramètre formel reçoit une copie de la valeur dans le paramètre réel, et toute modification du paramètre formel ne sont pas reflétées dans le paramètre réel. L'exemple le plus connu est une fonction d'échange:
void swap(int x, int y) { int tmp = x; x = y; y = x; }
...
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);
Vous obtenez le résultat suivant:
avant de swap: a = 1, b = 2
après swap: a = 1, b = 2
Les paramètres formels x
et y
sont des objets distincts à partir d' a
et b
, de sorte que les modifications à l' x
et y
ne sont pas reflétés dans a
et b
. Puisque nous voulons modifier les valeurs de a
et b
, il nous faut passer des pointeurs de la fonction d'échange:
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);
Maintenant, votre sortie sera
avant de swap: a = 1, b = 2
après swap: a = 2, b = 1
Notez que, dans la fonction de permutation, on ne change pas les valeurs de x
et y
, mais les valeurs de ce que l' x
et y
point de. L'écriture d' *x
est différente de l'écriture à l' x
; nous ne sommes pas la mise à jour de la valeur en x
lui-même, nous obtenons un emplacement de x
et mise à jour de la valeur de cet emplacement.
Cela est d'autant plus vrai si l'on souhaite modifier une valeur de pointeur; si nous écrire
int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);
ensuite, nous allons modifier la valeur du paramètre d'entrée stream
, pas de quoi stream
de points à, la modification stream
n'a pas d'effet sur la valeur de in
; dans l'ordre pour que cela fonctionne, il nous faut passer un pointeur vers le pointeur:
int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);
Encore une fois, les tableaux de jeter un peu de bâtons dans les œuvres. Lorsque vous passez un tableau de l'expression d'une fonction, ce que la fonction reçoit un pointeur. En raison de la façon dont des indices de tableaux est défini, vous pouvez utiliser un indice de l'opérateur sur un pointeur de la même façon, vous pouvez l'utiliser sur un tableau:
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;}
Notez que les objets d'ensemble ne peut pas être affectée; c'est à dire, vous ne pouvez pas faire quelque chose comme
int a[10], b[10];
...
a = b;
donc, vous voulez être prudent lorsque vous traitez avec des pointeurs vers des tableaux; quelque chose comme
void (int (*foo)[N])
{
...
*foo = ...;
}
ne fonctionne pas.