Télécharger la présentation
Publié parMicheline Maillard Modifié depuis plus de 10 années
1
Les Pointeurs et les Tableaux Statiques et Tableaux Dynamiques
2
Tableaux Statiques et Tableaux Dynamiques
Les tableaux statiques nécessitent de maximiser lors de l'écriture du programme la dimension des tableaux. Il serait plus utile de ne réserver, pour chaque exécution, que la taille nécessaire à l'application en cours. Déclaration d’un tableau statique #define composante float composante tab[dim]; composante*tab; tab=(composante *)malloc(taille*sizeof(composante)); free(tab); tab=NULL; Déclaration d’un tableau dynamique (si on a besoin du tableau) Si le tableau redevient inutile.
3
Tableaux Statiques et Tableaux Dynamiques
Si on a l'une ou l'autre des déclarations on peut écrire: float t[100]; float *t = (float*)malloc(10*sizeof(float)); On doit connaître la dimension d'un tableau dynamique (taille) avant sa première utilisation. t[0] ou *t t[i] ou *(t+i)
4
Tableaux Statiques et Tableaux Dynamiques
Remarque 1. La similitude entre un tableau et un pointeur est grande, notamment dans la partie exécutable des fonctions. Mais il subsiste des différences, surtout dans les déclarations. Il ne faut pas oublier que les déclarations: introduisent p comme une variable pointeur et t comme une constante pointeur. Ainsi, les expressions p = t et p++ sont légitimes, mais t = p et t++ sont illégales, car elles tentent de modifier une non variable (un nom de tableau n'est pas une lvalue). int *p, t[100];
5
Tableaux Statiques et Tableaux Dynamiques
Remarque 2. Dans ce mème esprit, rappelons la difference qu'il peut y avoir entre les deux déclarations suivantes : s est l'adresse d'un tableau de caractères char s[ ] = "Bonsoir"; et char *t = "Bonsoir";
6
Tableaux Statiques et Tableaux Dynamiques
Remarque 2. tandis que t est l'adresse d'un tableau de caractère(s)
7
Tableaux Statiques et Tableaux Dynamiques
On pourra référencer ces caractères par: Cependant, dans le premier cas le compilateur a alloué un vrai tableau de 8 caractères, et y a copié la chaîne donnée. Dans le second cas, la chaîne a été rangée avec les autres constantes littérales et le compilateur n'a alloué qu'une variable de type pointeur dans laquelle il a rangé l'adresse de cette constante. Par suite, s n'est pas une variable mais *s, s[i] et *(s + i) en sont, tandis que t est une variable mais *t, t[i] et *(t + i) n'en sont pas. s[i], *(s + i) t[i], *(t + i)
8
Tableaux Statiques et Tableaux Dynamiques
Exemple classique : La fonction strcpy(dest, srce) copie la chaîne de caractères srce dans l'espace pointé par dest. char *strcpy(char *dest, char *srce) { char *d = dest, *s = srce; while ((*d++ = *s++) != '\0'); return dest; }
9
Tableaux Statiques et Tableaux Dynamiques
Example: utilisation de la fonction strcpy La longueur de t <= de celle de s #include <stdio.h> char *strcpy(char *dest, char *srce); void main() { char s[ ] = "AAAAAAA"; char *t = "Bonjour"; puts (strcpy(s,t)); } char *strcpy(char *dest, char *srce) { char *d = dest, *s = srce; while ((*d++ = *s++) != '\0'); return dest; Bonjour
10
Tableaux Statiques et Tableaux Dynamiques
Example: utilisation de la fonction strcpy La longueur de t > de celle de s #include <stdio.h> char *strcpy(char *dest, char *srce); void main() { char s[ ] = "AAAA"; char *t = "Bonjour"; puts (strcpy(s,t)); } char *strcpy(char *dest, char *srce) { char *d = dest, *s = srce; while ((*d++ = *s++) != '\0'); return dest; Erreur! #include <stdio.h> #include <string.h> #include <stdlib.h> char *strcpy(char *dest, char *srce); void main() { char *t = "Bonjour"; int len=strlen(t); char *s=(char *)malloc((len+1)*sizeof(char)); puts (strcpy(s,t)); } Bonjour
11
Tableaux Statiques et Tableaux Dynamiques
L'équivalence entre les tableaux et les pointeurs permet de réaliser des tableaux dynamiques, c'est-à-dire des tableaux dont la taille n'est pas connue au moment de la compilation mais uniquement lors de l'exécution, lorsque le tableau commence à exister. Pour cela il suffit de: remplacer la déclaration du tableau par celle d'un pointeur; allouer l'espace à l'exécution, avant toute utilisation du tableau, par un appel de malloc ou calloc; dans le cas d'un tableau local, libérer l'espace à la fin de l'utilisation.
12
Tableaux Statiques et Tableaux Dynamiques
Programmation avec un tableau statique Faire un programme à afficher le triangle de Pascal (Rappelons que les coeficients de la neme ligne du triangle de Pascal sont définis récursivement à partir de ceux de la n-1eme ligne). #include <stdio.h> /3 #include <stdlib.h> #define N_MAX 50 void Blaise(int n); Le prototype de la fonction
13
Tableaux Statiques et Tableaux Dynamiques
Programmation avec un tableau statique void main() /3 { int n; do { printf("Entrer n="); scanf("%d",&n); }while(n<=0 || n > N_MAX); Blaise(n); } Entrer n=3 1 La fonction main, appelante la fonction Blaise
14
Tableaux Statiques et Tableaux Dynamiques
Programmation avec un tableau statique void Blaise(int n) /3 { int j, p, i; int tab[N_MAX + 1]; /* N_MAX est une constante connue à la compilation */ for (j = 0; j <= n; j++) { tab[0] = tab[j] = 1; for (p = j - 1; p > 0; p--) tab[p] += tab[p - 1]; /* exploitation de tab ; par exemple, afichage : */ for (i = 0; i <= j; i++) printf("%5d", tab[i]); printf("\n"); } La définition de la fonction Blaise
15
Tableaux Statiques et Tableaux Dynamiques
Programmation avec un tableau dynamique Faire le même programme #include <stdio.h> /3 #include <stdlib.h> void Blaise(int n); Le prototype de la fonction
16
Tableaux Statiques et Tableaux Dynamiques
Programmation avec un tableau dynamique void main() /3 { int n; printf("Entrer n="); scanf("%d",&n); Blaise(n); } Entrer n=3 1 La fonction main, appelante la fonction Blaise
17
Tableaux Statiques et Tableaux Dynamiques
Programmation avec un tableau dynamique void Blaise(int n) { /3 int j, p, i; int *tab; /* ici, pas besoin de constante connue à la compilation */ tab =(int *) malloc((n + 1) * sizeof(int)); if (tab == NULL) exit(1); for (j = 0; j <= n; j++) { *(tab+0) = *(tab+j) = 1; for (p = j - 1; p > 0; p--) *(tab+p) += *( tab+p-1); /* exploitation de tab ; par exemple, afichage : */ for (i = 0; i <= j; i++) printf("%5d", *(tab+i)); printf("\n"); } free(tab); tab=NULL; /* à ne pas oublier ( tab est une variable locale) */ La réservation dynamique de la mémoire La définition de la fonction Blaise
18
Tableaux Dynamiques Unidimensionnels
Exemple 1 Réserver de la mémoire pour un tableau de n nombres entiers. Remplir le tableau en dialogue. Modifier la taille de la mémoire préalablement alloué pour qu’on puisse ajouter la somme des éléments entrés. Afficher le tableau au début et après l’ajout de la somme. La réservation initialle de la mémoire #include <stdio.h> /3 #include <stdlib.h> void main() { int *p,*q,n,s; printf("Entrer n="); scanf("%d",&n); p=(int*)malloc(n*sizeof(int)); if(p == NULL) { printf("Pas de place!\n"); exit(1); } printf("Apres malloc p=%p\n",p); Entrer n=3 Apres malloc p=245F:00F2
19
Tableaux Dynamiques Unidimensionnels
Exemple 1 for(q=p,s=0;q<p+n;q++) /3 {printf("Entrer un nombre:"); scanf("%d",q); s+=*q; } for(q=p;q<p+n;q++) printf("%3d",*q); printf("\n"); Remplir le tableau dynamique. Faire la somme des éléments entrés. Entrer un nombre:11 Entrer un nombre:22 Entrer un nombre:33 Affichage du tableau initial
20
Tableaux Dynamiques Unidimensionnels
Exemple 1 Modification de la taille p=(int*)realloc(p,(n+1)*sizeof(int)); /3 if(p == NULL) { printf("Pas de place!\n"); exit(1); } printf("Apres realloc p=%p\n",p); *(p+n)=s; for(q=p;q<p+n+1;q++) printf("%3d",*q); printf("\nLa somme=%3d\n",*(p+n)); free(p); p=NULL; Affichage du tableau après l’ajout de la somme Apres realloc p=245F:00E6 La somme=66
21
Tableaux Dynamiques Unidimensionnels
Exemple 2 Réserver de la mémoire pour un tableau (chaîne) de n caractères . Remplir la chaîne en dialogue. Modifier la taille s’il y a besoin. Afficher la chaîne et le nombre de caractères entrés. Trouver la chaîne miroir et l’afficher. 1/4 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <conio.h> #define NUM 2 char *entrer(int n); void miroir(char *s,char *t); Les prototypes des fonctions
22
Tableaux Dynamiques Unidimensionnels
Exemple 2 void main() /4 { int n,len; char *str,*rez; printf("Entrer n="); scanf("%d",&n); str=entrer(n); printf("\n"); len=strlen(str); puts(str); printf("Le nombre de caracteres=%d\n",len); rez=(char *) calloc((len + 1) , sizeof(char)); miroir(rez,str); printf("La chaine miroir est:\n"); puts(rez); free(rez); rez=NULL; }
23
Exemple 2 La définition de la fonction d’entré
char * entrer(int n) /4 { int i=0,len; char *s,c; s =(char *) calloc((n + 1) , sizeof(char)); if (s == NULL) { printf("Pas de place!|n"); exit(1); } do { fflush(stdin); printf("\nEntrer un car.:"); c=getchar(); if(i >= n) {len=n+NUM; s =(char *) realloc(s,len * sizeof(char)); { printf("Pas de place!\n"); exit(1); } n=len; } s[i++]=c; printf("Entrer car suivant - O/N?"); } while(toupper (getche()) == 'O'); s[i]='\0'; free(s); /* ne ne pas oublier ( s est une variable locale) */ return (s);
24
Tableaux Dynamiques Unidimensionnels
Exemple 2 La définition de la fonction de miroir void miroir(char *s,char *t) /4 { int n=strlen(t); t+=n-1; while(n) { *s++=*t--; n--; } *s='\0';
25
Tableaux Multidimensionnels
Réflexions sur la double indexation. Supposons que nous ayons à écrire un programme qui opère sur des matrices à L lignes et C colonnes. Un tableau à deux dimensions A est à interpréter comme un tableau (uni-dimensionnel) de dimension L dont chaque composante est un tableau (uni-dimensionnel) de dimension C. On appelle L le nombre de lignes du tableau et C le nombre de colonnes du tableau. L et C sont alors les deux dimensions du tableau. Un tableau à deux dimensions contient donc L*C composantes.
26
Tableaux Multidimensionnels
On dit qu'un tableau à deux dimensions est carré, si L est égal à C. En faisant le rapprochement avec les mathématiques, on peut dire que "A est un vecteur de L vecteurs de dimension C", ou mieux: "A est une matrice de dimensions L et C".
27
Tableaux Multidimensionnels
Exemple Pour mémoriser les notes des 20 élèves dans les 10 devoirs d'un trimestre, nous pouvons rassembler plusieurs des tableaux uni-dimensionnels dans un tableau NOTE à deux dimensions. Dans une ligne nous retrouvons les notes de tous les élèves dans un devoir. Dans une colonne, nous retrouvons toutes les notes d'un élève.
28
Tableaux Multidimensionnels
Exemple Déclaration et mémorisation Comme pour les tableaux à une dimension, le nom d'un tableau est le représentant de l'adresse du premier élément du tableau (c.-à-d. l'adresse de la première ligne du tableau). Les composantes d'un tableau à deux dimensions sont stockées ligne par ligne dans la mémoire. int NOTE[10][20] = { {45, 34, ... , 50, 48}, {39, 24, ... , 49, 45}, {40, 40, ... , 54, 44} }; <TypeSimple> <NomTabl>[<DimLigne>][<DimCol>];
29
Tableaux Multidimensionnels
Exemple En supposant qu'une variable du type double occupe 8 octets (c.-à-d: sizeof(double)=8), pour le tableau T déclaré par: double T[10][15]; C réservera L*C*M = 10*15*8 = 1200 octets en mémoire. Initialisation Lors de la déclaration d'un tableau, on peut initialiser les composantes du tableau, en indiquant la liste des valeurs respectives entre accolades. float B[3][2] = { {-1.05, }, {86e-5, 87e-5 }, {-12.5E4, -12.3E4} };
30
Tableaux Multidimensionnels
Initialisation Lors de l'initialisation, les valeurs sont affectées ligne par ligne en passant de gauche à droite. Nous ne devons pas nécessairement indiquer toutes les valeurs. Les valeurs manquantes seront initialisées par zéro. Il est cependant défendu d'indiquer trop de valeurs pour un tableau. Réservation automatique Si le nombre de lignes L n'est pas indiqué explicitement lors de l'initialisation, l'ordinateur réserve automatiquement le nombre d'octets nécessaires. float B[ ][2] = { {-1.05, }, {86e-5, 87e-5 }, {-12.5E4, -12.3E4} }; Réservation de 3*2*4 = 24 octets
31
Tableaux Multidimensionnels
Accès aux composantes Affichage du contenu d'un tableau à deux dimensions NomTableau>[<Ligne>][<Colonne>] #include <stdio.h> main() { int a[4][4]={{1},{1},{1},{1}}; int i,j; /* Pour chaque ligne ... */ for (i=0; i<4; i++) { /*considerer chaque composante */ for (j=0; j<4; j++) printf("%3d", a[i][j]); /* Retour a la ligne */ printf("\n"); } return 0;
32
Tableaux Multidimensionnels
Affectation avec des valeurs provenant de l'extérieur #include <stdio.h> main() { int a[3][4]; int i,j; for (i=0; i<3; i++) { for (j=0; j<4; j++) { printf("a[%d][%d]:",i,j); scanf("%d",&a[i][j]); } { for (j=0; j<4; j++) printf("%3d", a[i][j]); printf("\n"); return 0; a[0][0]:1 a[0][1]:2 a[0][2]:3 a[0][3]:4 a[1][0]:5 a[1][1]:6 a[1][2]:7 a[1][3]:8 a[2][0]:9 a[2][1]:10 a[2][2]:11 a[2][3]:12
33
Tableaux Multidimensionnels
Un élément particulier de la matrice (m1) sera noté m1[i][j]. D'après ce que nous savons déjà, on peut l'interpréter de la manière suivante (Pour alléger les formules, nous supposons ici que la taille d'un int, et donc celle d'un unsigned, sont égales à celle d'un pointeur): m1[i] est un pointeur sur i-ème ligne float m1[NL][NC]; m1[i][j] = *(m1[ i ] + j) = *(float *)((unsigned int) m1[ i ] + j * sizeof(float))
34
Tableaux Multidimensionnels
Etudions une autre manière d'accéder aux éléments de cette même matrice. Soient les déclarations: La variable m2 est donc déclarée comme un tableau de NL pointeurs vers des nombres flottants. Pour réaliser la matrice dont nous avons besoin, il nous sufit d'initialiser correctement ces pointeurs : chacun sera l'adresse d'une ligne de la matrice précédente. float m1[NL][NC], *m2[NL];
35
Tableaux Multidimensionnels
Il est remarquable qu'un élément de la nouvelle matrice ainsi déclarée se note encore m2[i][j]
36
Tableaux Multidimensionnels
L’expression m2[i][j] se traduira (en continuant à négliger les conversions des types pointeurs) par : Il nous faut initialiser le tableau de pointeurs m2. La matrice m1 est la matrice existante. m2[i][j] = *(m2[i] + j * sizeof(float)) = *(*(m2 + i * sizeof(float *)) + j * sizeof(float)) for (i = 0; i < NL; i++) m2[i] = m1[i];
37
Tableaux Multidimensionnels Dynamiques
Il n'y a pas en C d'équivalence d'écriture permettant une utilisation directe de l'allocation dynamique pour les tableaux multidimensionnels. En effet, NC doit être connu à la compilation pour que l'expression i * NC + j ait un sens. Pour allouer dynamiquement une matrice de taille (NL,NC), on réserve un tableau unidimensionnel de taille NL*NC.
38
Tableaux Multidimensionnels Dynamiques
Supposons que la fonction void unCalcul(int nl, int nc) implémente un algorithme qui requiert une matrice locale à nl lignes et nc colonnes. Version statique #define NL 20 #define NC 30 . . . void unCalcul(int nl, int nc) { double mat[NL][NC]; /* en espérant que nl <= NL et nc <= NC */ int i, j; /* utilisation de la matrice mat. Par exemple : */ for (i = 0; i < nl; i++) for (j = 0; j < nc; j++) mat[i][j] = 0; etc. }
39
Tableaux Multidimensionnels Dynamiques
void unCalcul(int nl, int nc) { double **mat; int i, j; /* initialisation des pointeurs */ mat =(double **) malloc(nl * sizeof(double *)); for (i = 0; i < nl; i++) mat[i] = (double *) malloc(nc * sizeof(double)); /* utilisation de la matrice mat. Par exemple : */ for (j = 0; j < nc; j++) mat[i][j] = 0; etc. /* libération (indispensable dans le cas d'une variable locale) */ { free(mat[i]); mat[i]=NULL; } free(mat); mat=NULL; } Version dynamique
40
Tableaux Multidimensionnels Dynamiques
Dans cette manière de procéder, les lignes de la matrice sont allouées à l'occasion de nl appels distincts de malloc. La matrice est réalisée par des morceaux de mémoire. lignes allouées séparément
41
Tableaux Multidimensionnels Dynamiques
Exemple : Faire un programme de: 1) création d’une matrice dynamique de nombres entiers de l lignes, c colonnes; 2) affichage de la matrice. Utiliser les fonctions differentes de création et d’affichage. Les prototypes des fonctions #include <stdio.h> /4 #include <stdlib.h> int **creation(int l,int c); void affichage(int l, int c, int **a);
42
Tableaux Multidimensionnels Dynamiques
Exemple void main() /4 { int **x,l,c; printf("nombre de lignes: "); scanf("%d",&l); printf("nombre de colonnes: "); scanf("%d",&c); x=creation(l,c); printf("La matrice cree.\n"); affichage(l,c,x); } nombre de lignes: 2 nombre de colonnes: 3 el[0][0]:1 el[0][1]:2 el[0][2]:3 el[1][0]:4 el[1][1]:5 el[1][2]:6 La matrice cree. La fonction main, appelante les fonctions
43
Tableaux Multidimensionnels Dynamiques
Exemple int **creation(int l,int c) /4 { int **t,i,j; t=(int **)malloc(l*sizeof(int *)); for(i=0;i<l;i++) t[i]=(int *)malloc(c*sizeof(int)); for(j=0;j<c;j++) { printf("el[%d][%d]:",i,j); scanf("%d",(t[i]+j)); } free(t); return t; La définition de la fonction de création
44
Tableaux Multidimensionnels Dynamiques
Exemple void affichage(int l, int c, int **a) /4 { int i,j; for(i=0;i<l;i++) { for(j=0;j<c;j++) printf("%3d",*(a[i]+j)); printf("\n"); } La définition de la fonction d’affichage
45
Tableaux Multidimensionnels Dynamiques
#include <stdio.h> #include <stdlib.h> void main() { int **t,i,j; t=(int **)malloc(2*sizeof(int*)); for(i=0;i<2;i++) t[i]=(int *)calloc(3,sizeof(int)); *(t[i]+2)=6; { for(j=0;j<3;j++) printf("%d%c",*(t[i]+j),' '); printf("\n"); } Exercice
46
Tableaux Multidimensionnels Dynamiques
#include <stdio.h> #include <stdlib.h> void main() { int **t,i,j; t=(int **)malloc(2*sizeof(int*)); for(i=0;i<2;i++) t[i]=(int *)calloc(3,sizeof(int)); { *(t[i]+1)=i; *(t[i]+2)=i+1; } { for(j=0;j<3;j++) printf("%d%c",*(t[i]+j),' '); printf("\n"); Exercice
47
Tableaux de Tableaux Dynamiques (matrices non pleines)
On gère en fait un ensemble de lignes de longueur différente (donc des tableaux dynamiques). On utilise alors la même méthode que pour les matrices pleines, en changeant simplement le calcul pour accéder à une composante. Chaque ligne est allouée dynamiquement (l'adresse et la longueur de chaque ligne étant stockée dans un tableau statique ou dynamique). Les manipulations de composantes (dans les lignes) restent des manipulations de type tableaux.
48
Tableaux de Tableaux Dynamiques (matrices non pleines)
Les manipulations de lignes se font par manipulation d'adresses (par exemple pour échanger deux lignes, il suffit d'échanger les deux adresses de lignes, les lignes elles-mêmes n'étant physiquement pas déplacées). Ces tableaux de tableaux dynamiques permettent toujours un accès presque direct à un élément l,c. tab[ adresse_ligne[l] ][c]
49
Tableaux de Tableaux Dynamiques (Tableaux de chaînes de caractères)
Le remplacement d'un tableau à deux indices par un tableau de pointeurs se révèle encore plus utile dans le traitement des tableaux de chaînes de caractères. Cette technique permet de remplacer un tableau rectangulaire dont la largeur est déterminée par la plus grande longueur possible d'une chaîne par un espace linéaire dans lequel chaque chaîne n'occupe que la place qui lui est nécessaire.
50
Tableaux de Tableaux Dynamiques (Tableaux de chaînes de caractères)
A. Matrice de caractères
51
Tableaux de Tableaux Dynamiques (Tableaux de chaînes de caractères)
B. Tableau de chaînes de caractères
52
Tableaux de Tableaux Dynamiques (Tableaux de chaînes de caractères)
Mot0 Mot1 Mot2 10 mots longueur maximale: 50 caractères Mot9 char *Mot[10]
53
Tableaux de Tableaux Dynamiques (Tableaux de chaînes de caractères)
Exemple - Ecrire un programme qui lit des mots (nombre des mots quelconque) au clavier (longueur maximale: 50 caractères). On attribue leurs adresses à un tableau dynamique a deux dimensions text. Afficher les mots saisies.
54
char **text Mot0 text[0] text[1] Mot1 text[2] Mot2 text[i] Motn
text[n]
55
Tableaux de Tableaux Dynamiques (Tableaux de chaînes de caractères)
Exemple #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <conio.h> #define L_MOT 51 #define NUM 2 void entrer_sortir(char **text,int *n_m,int *n_el); void main() { char **text; int n_m=0,n_el=NUM; text=(char **)malloc(n_el*sizeof(char *)); if(text==NULL) { printf("Error!Memory not allocated!\n"); exit(1); } entrer_sortir(text,&n_m,&n_el); }
56
Tableaux de Tableaux Dynamiques (Tableaux de chaînes de caractères)
Exemple void entrer_sortir(char **text, int *n_m, int *n_el) { char temp[51]; int i; char *mot; printf("Introduire des mots terminees par un retour a la ligne\n"); fflush(stdin); do{ printf("\nmot %d:",*n_m); fgets(temp,sizeof(temp),stdin); mot=(char *)malloc((strlen(temp)+1)*sizeof(char)); if(mot==NULL) exit(1); strcpy(mot,temp); if(*n_m==*n_el) { *n_el+=NUM; text=(char**)realloc(text,*n_el*sizeof(char*)); if(text==NULL) exit(1); }
57
Tableaux de Tableaux Dynamiques (Tableaux de chaînes de caractères)
Exemple text[(*n_m)++]=mot; printf("\nMot suivant? Y/N:"); } while(toupper(getch()) == 'Y'); strcat(*(text+*n_m-1),"\n"); printf("\nLes mots sont\n"); for(i=0;i<*n_m;i++) puts(text[i]); free(mot); mot=NULL; }
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.