Pour un tableau de int, c'est le type int(*)[]. Une déclaration est de la forme: int tab[] = {42, 43, 44}; int (*p_sur_tab)[] = &tab; Cette forme a l'avantage de ne pas spécifier une taille fixe des tableaux. C'est plus souple, notamment dans pour les paramètres des fonctions. En revanche, cela interdit d'écrire quelque chose comme p_sur_tab++ puisqu'on ne connait pas la taille de l'objet pointé et on ne peut pas effectuer le décalage mémoire nécessaire. On perd donc les possibilités d'arithmétique sur pointeur.
Pointeurs sur les tableaux Next: Liste chaînée Up: Présentation de la notion Previous: Présentation de la notion Contents On va voir qu'un même pointeur pourra être associé à des tableaux de profil différent à condition qu'ils soient de même rang. PROGRAM Ptr_tab IMPLICIT NONE integer, dimension (3), target:: t1 = 1 integer, dimension (5), target:: t2 = 2 integer, dimension (:), pointer:: p1, p2 p1 => t1 p2 => t2 p1(2:3) = p2(4:5) print*, t1, t2, p1, p2 p1 => t1(1:2) p1 = 3 END PROGRAM Ptr_tab signifie que est associé à et est associé à est une affectation de la section du tableau à la section du tableau donne t1=p1 = 1 2 2 et t2=p2 = 2 2 2 2 2 signifie que est asscocié à la section et que l'instruction p1 =3 modifie uniquement cette section (très fort) donne t1=p1 = 3 3 2 et t2=p2 = 2 2 2 2 2 Mazen Saad 2002-12-12
Les types de ptr ne peut évidemment pas être compatible avec le type de ptr2. J'aurais pensé qu'un tableau d'entiers est de type pointeur sur entier, Ce n'est pas. Tableaux se désintègre aux pointeurs dans de nombreuses circonstances courantes, mais ce ne sont pas les mêmes. cela signifierait donc qu'un pointeur vers un tableau d'entiers est de type double pointeur vers un entier. Non, ce n'est pas le cas. pourquoi ptr2 ne fonctionne-t-il pas comme prévu? ptr2 est un pointeur qui contient l'adresse du tableau p. Déréférencer cela avec *ptr2 donnerait le premier élément de p. Le déréférencement à nouveau utiliserait le premier élément dans p comme adresse, et donnez la valeur à cette adresse. C'est pourquoi vous devriez lire les avertissements de votre compilateur. Même sans les drapeaux -Wall et -Wextra (que vous devez toujours utiliser) ce code émet cet avertissement: k. c:6:16: warning: initialization of 'int **' from incompatible pointer type 'int (*)[3]' [-Wincompatible-pointer-types] ^ Là, vous l'avez en texte brut.
Cela a déjà été dit de manière implicite dans la partie précédente en affirmant que l'argument tableau de printf() était automatiquement converti en l'adresse de son premier élément. Les arguments sont passés par copie aux fonctions, en langage C. Ainsi, passer le tableau lui-même en paramètre reviendrait à le copier en entier sur la pile d'appel. Au mieux, votre pauvre pile prend une baffe dans sa face; au pire vous lui planter carrément un couteau dans le dos. On contourne le problème en passant en argument un pointeur vers le premier élément du tableau et c'est la que la conversion implicite ressort du chapeau. C'est d'ailleurs le seul cas où int* et int[] sont équivalents: lors de la déclaration d'un paramètre d'une fonction. Les deux notations sont alors permises et équivalentes. Par exemple, le code suivant ne génèrera pas de d'erreur de conflicting types: void equi_1(int tab[]); void equi_1(int * pt) printf("%d\n", *pt);} void equi_2(int* tab[]); // au lieu de faire un tableau de int, // on fait un tableau de int* void equi_2(int* *pt) // par analogie, on fait un pointeur sur un int* printf("%d\n", **pt);} 4 – Tableaux multidimensionnels Il n'existe pas de tableaux multidimensionnels en C.
Cela ne signifie absolument pas que la zone mémoire référencée par cette adresse est valide, bien au contraire, mais plutôt que cette adresse est valide. Il est donc garantit que cette adresse ne sera pas le pointeur NULL par exemple, ni toute autre valeur spéciale qu'un pointeur ne peut pas stocker. Il sera donc possible de faire des calculs d'arithmétique des pointeurs avec cette adresse, même si elle ne devra jamais être déréférencée, sous peine de voir le programme planter. On prendra garde à certaines subtilités. Les conversions implicites sont une facilité introduite par le compilateur, mais en réalité, les tableaux ne sont pas des pointeurs, ce sont des variables comme les autres, à ceci près: leur type est convertible en pointeur sur le type de leurs éléments. Il en résulte parfois quelques ambiguïtés lorsqu'on manipule les adresses des tableaux. En particulier, on a l'égalité suivante: &tableau == tableau en raison du fait que l'adresse du tableau est la même que celle de son premier élément.
Cette adresse de base est l'adresse du début du tableau, c'est donc à la fois l'adresse du tableau et l'adresse de son premier élément. Ce lien apparaît au niveau du langage dans les conversions implicites de tableaux en pointeurs, et dans le passage des tableaux en paramètre des fonctions. Conversions des tableaux en pointeurs [ modifier | modifier le wikicode] Afin de pouvoir utiliser l'arithmétique des pointeurs pour manipuler les éléments des tableaux, le C++ effectue les conversions implicites suivantes lorsque nécessaire: tableau vers pointeur d'élément; pointeur d'élément vers tableau. Cela permet de considérer les expressions suivantes comme équivalentes: identificateur[n] et: *(identificateur + n) si identificateur est soit un identificateur de tableau, soit celui d'un pointeur. Exemple 4-11. Accès aux éléments d'un tableau par pointeurs [ modifier | modifier le wikicode] int tableau[100]; int *pi=tableau; tableau[3]=5; /* Le 4ème élément est initialisé à 5 */ *(tableau+2)=4; /* Le 3ème élément est initialisé à 4 */ pi[5]=1; /* Le 6ème élément est initialisé à 1 */ Le langage C++ impose que l'adresse suivant le dernier élément d'un tableau doit toujours être valide.
14; p++;} return EXIT_SUCCES;} Dans le slide suivant, on étend un peu ce code en le commentant pas à pas. On va aussi utiliser des boucles for, plus concises que le while. Parcours de tableau par indice pointeur /** * Parcours de tableau par indice pointeur */ #define NB 10 float tab[NB]; // tab est de type "tableau de 10 double" float *p=NULL; // Un premier parcours du tableau par "indice pointeur" for(p=tab; p < tab + NB; p = p+1) { *p = 3. 14;} printf("Voici les valeurs dans le tableau:\n"); for(p=tab; p < tab + NB; p++) { printf("%f", *p);} printf("Donnez les%d valeurs du tableau:\n"; NB); // un parcours par indice pointeur pour un scanf? no pb! scanf("%f", p);} // affichons cette fois ci avec les numéros de cases, une case par ligne printf("case%d vaut:%. 1f\n", p-tab, *p);} (... à part gagner des points à l'examen... ) Eh bien... Tout d'abord, il s'agit d'une syntaxe très idiomatique en langage C (et C++), en ce qu'elle dénote au coeur du code la proximité permise par le C avec la mémoire de la machine.