Lors de la programmation en C (ou C++), il existe trois manières différentes de spécifier le paramètre dans une fonction qui prend un tableau.
Voici un exemple (mise en œuvre std::accumulate
De C++ en C) qui vous montre ce que je veux dire.
Je peux l'écrire comme ceci:
int accumulate(int n, int *array)
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}
Cela peut également être écrit à cela (ce qui signifie la même chose):
int accumulate(int n, int array[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}
Je peux aussi l'écrire comme ceci:
int accumulate(int n, int (*array)[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += (*array)[i];
}
return sum;
}
Toutes ces options sont très similaires et génèrent le même code exécutable, mais ils ont une légère différence qui est la manière dont l'appelant passe les arguments.
Voici comment les deux premières options sont appelées:
int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), a));
return 0;
}
C'est ainsi que l'option Thrid est appelée:
int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
return 0;
}
Notez que la troisième option nécessite l'utilisateur de spécifier explicitement l'adresse de a
avec &a
. Les deux premières options n'exigent pas cela car les tableaux sont implicitement convertis en pointeurs sur le même type de C.
J'ai toujours préféré la troisième approche.
C'est pourquoi:
Il est plus cohérent avec la manière dont les autres types sont passés par des pointeurs.
int draw_point(struct point *p);
int main()
{
struct point p = {3, 4};
draw_point(&p); // Here is the 'address of' operator required.
}
Il permet d'utiliser des macros comme ARRAY_LENGTH
Pour obtenir la quantité d'éléments dans la matrice.
#include <stdio.h>
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))
void this_works(int (*array)[10])
{
/* This works! */
printf("%d\n", ARRAY_LENGTH(*array));
}
void this_is_invalid_and_dangerous(int array[10])
{
/* This does NOT work because `array` is actually a pointer. */
printf("%d\n", ARRAY_LENGTH(array));
}
Le seul avantage que je vois avec int array[]
(Et int *array
) Est-ce que vous obtenez d'écrire array[X]
Au lieu de (*array)[X]
Lorsque vous souhaitez saisir un index.
quels sont vos pensées professionnelles à ce sujet? Quelle approche pensez-vous est meilleure et pourquoi? Avez-vous déjà mélangé les deux? Si oui quand choisissez-vous quoi?
Comme je l'ai dit, j'ai toujours préféré utiliser int (*array)[N]
mais je vois que les deux autres approches sont assez communes.
En pratique, vous verrez
int accumulate( int n, int *array)
le plus souvent. C'est le plus flexible (il peut gérer des tableaux de différentes tailles) et reflète le plus étroitement ce qui se passe sous le capot.
Vous ne verrez pas
int accumulate( int (*array)[N] )
comme souvent, car il suppose une taille de matrice spécifique (la taille DOI être spécifiée).
Si votre compilateur prend en charge la syntaxe de réseau de longueur variable, vous pourriez faire
int accumulate( size_t n, int (*array)[n] )
mais je ne sais pas à quel point c'est commun.
En C, lorsque la notation de la matrice est utilisée pour un paramètre de fonction, elle est automatiquement transformée en une déclaration de pointeur, alors déclarant le paramètre que int * array et INT Array [] sont équivalents. J'ai tendance à utiliser la seconde car il est plus clair que la fonction s'attend à un tableau comme un argument.
Déclarant paramètre de fonction comme int ((* tableau) [] n'est pas équivalent à deux précédents, il est transformé en int ** et il doit être utilisé lorsque la valeur du paramètre lui-même pourrait être modifié dans la fonction, c'est-à-dire la réaffectation de la matrice.
Vous dites qu'il y a 3 façons de C et C++, mais C++ fait un quatrième disponible:
template<std::size_t n>
void arrayFunction(std::array<int,n> &array)
{ ...}
Cela présente plusieurs avantages sur les solutions que vous suggérez:
La première déclaration vous permet également d'écrire la fonction différemment:
int accumulate(int n, int *array)
{
int sum = 0;
while (n-- > 0) sum += *array++;
return sum;
}
donc, vous n'avez pas besoin de la variable i.
Tout ce qui est idiomatique à la base de code doit être préféré, suivi de ce qui est le plus facile à comprendre, suivi à une certaine distance de ce qui est le plus performant. La deuxième déclaration est la plus facile à comprendre.