FAQ CConsultez toutes les FAQ
Nombre d'auteurs : 35, nombre de questions : 194, dernière mise à jour : 18 février 2018 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de www.developpez.com et de l'expérience personnelle des auteurs.
Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .
Sur ce, je vous souhaite une bonne lecture.
- Que signifie 'int t[] = {10, 20};' ?
- Que signifie 'int t[10] = {10, 20};' ?
- Soit t un tableau. Quelle est la différence entre t, &t et &(t[0]) ?
- Soit t un tableau. Que signifie *(t + 3) ?
- Quel est le rôle de l'opérateur [] ?
- Comment déclarer et utiliser un tableau « à plusieurs dimensions » ?
- Que signifie 'int (*p)[4];' ?
- Comment déclarer et utiliser un tableau de pointeurs de fonctions ?
- Comment passer un tableau en paramètre à une fonction ?
- Comment copier un tableau ?
int t[] = {10, 20}; crée un tableau de deux éléments initialisé avec les valeurs t[0] = 10 et t[1] = 20. Cette écriture est donc strictement équivalente à : int t[2] = {10, 20};.
int t[10] = {10, 20}; crée un tableau de 10 éléments initialisé avec les valeurs t[0] = 10, t[1] = 20 et t[2] à t[9] à 0. Notez bien que la mise à 0 des éléments non initialisés d'une variable locale tableau n'a lieu que lorsqu'un élément au moins a été initialisé.
t représente l'objet tableau, &t l'adresse de ce tableau et &(t[0]) l'adresse du premier élément du tableau. Ces trois expressions sont donc très différentes et n'ont à priori aucun point commun. Toutefois, &t et &(t[0]) représentent la même adresse, même si elles n'ont pas le même type (pour rappel, les adresses sont typées en C). t tout court quant à lui, lorsqu'il n'est pas utilisé dans sizeof ou avec l'opérateur & (« adresse de »), est toujours converti par le compilateur en &(t[0]). D'autres conversions de ce genre existent également (avec plus ou moins de conditions pour avoir lieu) et elles sont nombreuses. Ce sont ce qu'on appelle les conversions implicites.
La chose la plus importante à retenir est donc qu'une expression de type tableau (comme notre t ci-dessus, qui est de type int [10]), sauf lorsqu'elle est utilisée en unique argument de sizeof ou de l'opérateur & (« adresse de »), est toujours convertie par le compilateur en un pointeur vers son premier élément. Sinon il reste un tableau.
Pour comprendre le sens de cette expression, il faut au moins savoir deux choses :
- les adresses sont typées en C. Ajouter 1 à un pointeur revient à se déplacer en mémoire de la taille de la donnée pointée et non de 1 byte ;
- le nom d'un tableau (t), sauf lorsqu'il apparaît dans un sizeof ou à droite de l'opérateur & (« adresse de »), représente toujours un pointeur vers son premier élément (c'est-à-dire &(t[0])).
Le petit programme suivant devrait rendre les choses plus claires.
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <stdio.h> int main(void) { int t[] = {10, 20, 30, 40}; int * p = t; /* p pointe sur t[0] donc *p équivaut à t[0]. */ printf("t[0] = %d\n", *p); /* p pointe sur t[0] donc p + 1 pointe sur t[1]. *(p + 1) équivaut donc à t[1]. */ printf("t[1] = %d\n", *(p + 1)); /* p pointe sur t[0] donc p + 2 pointe sur t[2]. *(p + 2) équivaut donc à t[2]. */ printf("t[2] = %d\n", *(p + 2)); /* p pointe sur t[0] donc p + 3 pointe sur t[3]. *(p + 3) équivaut donc à t[3]. */ printf("t[3] = %d\n", *(p + 3)); return 0; } |
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <stdio.h> int main(void) { int t[] = {10, 20, 30, 40}; printf("t[0] = %d\n", *t); printf("t[1] = %d\n", *(t + 1)); printf("t[2] = %d\n", *(t + 2)); printf("t[3] = %d\n", *(t + 3)); return 0; } |
Cet opérateur permet d'accéder à un élément d'un tableau. Il requiert deux opérandes : un de type pointeur et l'autre de type entier. L'expression X[Y] est équivalente à *((X) + (Y)). Autrement dit, si p possède un type pointeur, alors les expressions p[1], 1[p] et *(p + 1) sont strictement équivalentes, tout comme p[-1], (-1)[p] et *(p - 1), etc.
En langage C, on ne classe pas les tableaux selon leurs dimensions, un tableau « à plusieurs dimensions » n'est d'ailleurs en C qu'un tableau dont les éléments sont eux aussi des tableaux. Il n'y a donc pas des règles spéciales pour ces tableaux « à plusieurs dimensions ». Voici un exemple de programme manipulant un tableau dont les éléments sont des tableaux.
Code c : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include <stdio.h> int main(void) { int t[10][4]; /* t est un tableau de 10 éléments ou */ /* chaque élément est un tableau de 4 entiers */ size_t j, i; /* Parcourons les éléments du tableau (t[0] a t[9]) */ for(j = 0; j < sizeof(t) / sizeof(t[0]); j++) { /* Pour chaque élément t[j] du tableau, initialisons */ /* les éléments de t[j] (t[j][0] a t[j][3]) */ for(i = 0; i < sizeof(t[j]) / sizeof(t[j][0]); i++) { t[j][i] = j; /* Puis affichons t[j][i] */ printf("%d\t", t[j][i]); } printf("\n"); } return 0; } |
int (*p)[4]; crée une variable p telle que (*p) est un tableau de 4 entiers. p est donc un pointeur vers un tableau de 4 entiers. Il est de type int (*)[4]. On ne peut pas utiliser un tel nom de type pour déclarer une variable par exemple, mais on peut par contre l'utiliser dans un cast ou un sizeof. Le programme suivant donne un exemple d'utilisation d'un pointeur vers tableau.
Code c : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <stdio.h> int main(void) { int t[10][4]; int (*p)[4] = t; /* p pointe sur t[0]. *p <=> t[0]. */; ( *p )[0] = 0; /* t[0][0] = 0 */ ( *p )[1] = 0; /* t[0][1] = 1 */ ( *(p + 1) )[0] = 1; /* t[1][0] = 1 */ ( *(p + 1) )[1] = 1; /* t[1][1] = 1 */ printf("t[0][0] = %d\n", t[0][0]); printf("t[0][1] = %d\n", t[0][1]); printf("t[1][0] = %d\n", t[1][0]); printf("t[1][1] = %d\n", t[1][1]); return 0; } |
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <stdio.h> /* Définition d'un type fonction */ typedef int F(void); /* Voici deux fonctions de type F */ int f1(void); int f2(void); /* Maintenant la fonction principale */ int main(void) { F * t[2]; t[0] = f1; t[1] = f2; printf("t[0]() = %d\n", t[0]()); printf("t[1]() = %d\n", t[1]()); return 0; } int f1(void) { return 1; } int f2(void) { return 2; } |
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <stdio.h> typedef int F(void); int f1(void); int f2(void); F * t[] = {f1, f2}; int main(void) { printf("t[0]() = %d\n", t[0]()); printf("t[1]() = %d\n", t[1]()); return 0; } int f1(void) { return 1; } int f2(void) { return 2; } |
Lorsqu'un tableau figure en paramètre d'une fonction, il est automatiquement converti en son adresse (plus précisément en l'adresse de son premier élément). Un tableau n'est donc jamais copié par une fonction. La méthode généralement utilisée pour passer un tableau à une fonction c'est de passer un pointeur vers son premier élément et sa taille (si nécessaire) comme paramètres.
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <stdio.h> void initialiser_tab(int * ptr, size_t n_elements) { size_t i; for(i = 0; i < n_elements; i++) ptr[i] = (int)i; } int main(void) { int t[10]; size_t i, n_elements = sizeof(t) / sizeof(t[0]); /* t peut également s'écrire &(t[0]) */ initialiser_tab(t, n_elements); for(i = 0; i < n_elements; i++) printf("%d\n", t[i]); return 0; } |
Code C : | Sélectionner tout |
1 2 3 | void initialiser_tab(int * ptr, size_t n_elements) void initialiser_tab(int ptr[], size_t n_elements) void initialiser_tab(int ptr[10], size_t n_elements) /* Le 10 ne sert absolument à rien */ |
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <stdio.h> /* initialiser_tab_2 : initialise un tableau de N éléments ou */ /* chaque élément est un tableau de M entiers . */ void initialiser_tab_2(int * ptr, size_t N, size_t M) { /* ptr = &(t[0][0]) d'ou : */ /* - ptr[i] <=> t[0][i] */ /* - ptr[M * j] <=> t[j][0] */ /* - ptr[M * j + i] <=> t[j][i] */ size_t j, i; for(j = 0; j < N; j++) { for(i = 0; i < M; i++) { ptr[M * j + i] = (int)j; } } } int main(void) { int t[10][4]; size_t j, i; size_t N = sizeof(t) / sizeof(t[0]), M = sizeof(t[0]) / sizeof(t[0][0]); /* &(t[0][0]) peut également s'écrire t[0] ou encore (int *)t */ initialiser_tab_2(&(t[0][0]), N, M); for(j = 0; j < N; j++) { for(i = 0; i < M; i++) printf("%d\t", t[j][i]); printf("\n"); } return 0; } |
Pour copier un tableau, on a deux solutions. La première consiste à copier chaque case du tableau numéro 1 dans la case correspondante du tableau numéro 2. Mais cette manière est parfois complexe et risque d'être lente.
La deuxième possibilité est d'utiliser la fonction memcpy(). Elle admet trois paramètres, le premier étant le tableau de destination et le deuxième le tableau source. Enfin, le troisième est le nombre d'octets à copier. Par exemple, pour copier le tableau Tab1 dans le tableau Tab2, il suffit de faire :
Code C : | Sélectionner tout |
1 2 3 4 5 | #include <string.h> int Tab1[10], Tab2[10]; memcpy(Tab2, Tab1, sizeof Tab2); |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.