Académique Documents
Professionnel Documents
Culture Documents
1
POINTEURS ET TABLEAUX
• Traitement de tableaux de chaînes de caractères
– Remplacement d’un tableau à deux indices par
un tableau de pointeurs Þ technique utile :
économie de place
M a s s a m b a \0
P a u l \0
I b r a \0
D e m b a \0
M a s s a m b a \0 P a u l \0 I b r a \0 D e m b a \0
3
POINTEURS ET TABLEAUX
• Tableaux de chaînes de caractères
Initialisation de tableaux de pointeurs
char * jour[7] = {“lundi“, “mardi”, “mercredi”, “jeudi”,
“vendredi”, “samedi”, “dimanche” }
– création des 7 chaînes de caractères correspondant aux 7
jours de la semaine
– Initialisation du tableau jour avec les 7 adresses de ces 7
chaînes
main() {
char * jour [7] = {“lundi“, “mardi”, “mercredi”, “jeudi”, “vendredi”,
“samedi”, “dimanche” }
int i;
printf (“Donnez un entier entre 1 et 7 : “);
scanf(‘%d”, &i);
printf(“le jour numero %d de la semaine est %s”, i, jour[i – 1]);
}
4
POINTEURS ET TABLEAUX
• 5) Allocation dynamique
void * malloc(size_t n) – demande la réservation d’un
bloc de taille n
void free( void *p) – libération de la mémoire
Exemple : si on veut copier la chaîne b dans a, on doit
réserver de l’espace pour a, et copier la chaîne
char *a;
char * b = “Une chaine“;
if ( ( a = (char*) malloc (strlen(b) + 1) == NULL) {
printf(“Pas assez de mémoire”); exit(1);
}
strcpy (a, b);
5
POINTEURS ET TABLEAUX
• Allocation d un tableau d entiers et initialisation à 0
int *arr, n, i;
scanf( %d , &n);
if ( (arr = (int*) malloc (n * sizeof(int)) == NULL) {
printf( Pas assez de mémoire ); exit(1);
}
for (i = 0; i < n; i++)
arr[i] = 0;
6
POINTEURS ET TABLEAUX
• Manipulation d un vecteur d entiers
int *construire_vecteur(int dimension) {
int *p, i;
p = (int *) malloc(dimension * sizeof(int)); // Allocation
if ( p == NULL ) {
printf( ²Attention : memoire saturee ...\n²);
return(NULL);
}
for(i = 0; i < dimension; i++) p[i] = 0; // Initialisation
return(p);
}
void detruire_vecteur(int *p) {
if (p) free p;
}
int produit_scalaire(int *v1, int *v2, int dimension) {
int i, produit;
for(i=0, produit=0; i<dimension; i++)
produit+=v1[i]*v2[i];
return(produit);
7
}
POINTEURS ET TABLEAUX
• Allocation d un tableau d entiers
void main() {
int *v1, *v2, i;
v1 = construire_vecteur(3);
v2 = construire_vecteur(3);
for(i = 0; i < 3; i++) {
v1[i] = i;
v2[i] = 2*i;
}
cout << ²v1.v2 = ² << produit_scalaire(v1, v2, 3);
detruire_vecteur(v1);
detruire_vecteur(v2);
}
affichage :
v1.v2 = 10
8
POINTEURS ET TABLEAUX
• Allocation dynamique d un tableau de chaînes de
caractères
char * jour[7] = { lundi , mardi , mercredi , jeudi ,
vendredi , samedi , dimanche }
char **j;
if ( ( j = (char**) malloc (7 * sizeof(char*))) == NULL) {
printf(“Pas assez de mémoire“); exit(1);
}
for ( i = 0 i < 7; i++) {
if ( (j[i] = (char *) malloc (strlen(jour[i]) + 1) == NULL) {
printf(“Pas assez de mémoire”); exit(1);
}
strcpy( j[i], jour[i] ); 9
}
POINTEURS ET TABLEAUX
Pour libérer l’espace :
j for( i = 0; i < 7; i++)
free(j[i]);
free(j);
L u n d i \0
D i m a n c h e \0
10
POINTEURS ET TABLEAUX
Allocation dynamique d une structure
typedef struct vecteur {
int dimension;
int* elements;
} Vecteur;
14
POINTEURS ET TABLEAUX
Pour obtenir la déclaration d’une variable ou d’une
fonction
1. Ecrire : - à gauche, la description naturelle du type;
- à droite, l’identificateur à déclarer (un seul)
2. Tant que l’expression de gauche n’est pas un type de base,
enum, struct ou union, transformer les deux expressions de la
manière suivante :
fonction rendant un expg expd → expg expd ( )
tableau de expg expd → expg expd [ ]
adresse de expg expd → expg *expd
Exples
Tableau de adresses de int t1
adresses de int t1[ ]
int *t1[ ]
15
POINTEURS ET TABLEAUX
adresse de tableau de int t2
tableau de int *t2
int (*t2) [ ]
parenthèses nécessaires car priorité de [ ] > priorité de *
16
POINTEURS DE FONCTIONS
• 5) Adresses de fonction
En C, on ne peut pas avoir une variable fonction, mais
on peut avoir une variable adresse de fonction, c’est-à-
dire une variable qui pointe sur une fonction et contient
ainsi son adresse.
De plus, le nom d’une fonction (employé seul) est traduit
par le compilateur en l’adresse de cette fonction
ex
adresse d’une fonction rendant un double f
fonction rendant un double *f
double (*f) ( );
17
POINTEURS DE FONCTIONS
double sin ( );
double (*f) ( );
f = sin;
int (*f) (double, int)
– (*f) – fonction à deux arguments qui renvoie un int
– f – pointeur de fonction
int f1(double, int);
int f2(double, int);
f = f1;
f = f2;
18
POINTEURS DE FONCTIONS
Il devient ainsi possible de programmer des appels de
fonction variable par
(*f) (9.5, 6)
Appel de la fonction dont l’adresse figure dans f (f1 ou f2)
19
POINTEURS DE FONCTIONS
Exemple 1 :
typedef struct pers {
char nom[20];
char prenom[20]:
int age;
} PERSONNE;
void personnel( PERSONNE t[ ], int n, void (*f) (PERSONNE)) {
int i;
for(i = 0; i < n; i++)
(*f) ( t[i] );
}
void afficher (PERSONNE p) {
…
}
main( ) {
PERSONNE table[100];
personnel(table, 100, afficher);
} 20
POINTEURS DE FONCTIONS
Exemple 2 : résolution de f(x)=0 par dichotomie
Soit une fonction f(x) continue. On veut résoudre l'équation f(x)=0 sur un
intervalle [a,b]. Pour cela, on utilise la méthode dichotomique : on divise
l'intervalle [a,b] en deux et on cherche la valeur de la fonction au point milieu; si
le produit f( (a+b)/2) * f(b) est négatif ou nul, on cherche le zéro dans l'intervalle
[ (a+b)/2, b], sinon on le cherche dans l'intervalle [a, (a+b)/2]. Cette recherche
est réitérée jusqu'à ce que l'amplitude de l'intervalle soit suffisamment petite,
c'est à dire plus petite qu'une certaine précision epsilon .
Trouver le zéro de la fonction f(x) = 4x2 + 5x -1 dans l'intervalle [0,1] avec une
précision de 1E-8.
21
POINTEURS DE FONCTIONS
double fonc(double x)
{
return (4*x*x+5*x-1);
}
double dicho(double a,double b,double eps,double (*f)(double))
{
double x;
while (b-a > eps)
if ((*f)(x=(a+b)/2) *(*f)(b) <= 0)
a=x;
else
b=x;
return x;
}
Appel
x = dicho(0.0, 1.0, 1E-8, fonc); 22
POINTEURS DE FONCTIONS
Exemple 3 : tableau de fonctions
Utilisation d un tableau d adresses de fonctions : chaque élément du tableau
est formé de deux champs :
• le nom d une fonction standard, sous forme de chaînes de caractères
• l adresse de la fonction correspondante
Lecture des lignes constituées d un nom de fonction, suivi d un ou plusieurs
Blancs, suivis d un nombre réel; évaluation, arrêt par « fin »
#include <stdio.h>
double sin(double), cos(double), exp(double), log(double);
23
POINTEURS DE FONCTIONS
struct {
char *nom;
double (*fon)(double);
} table[ ] = {
"sin", sin,
"cos", cos,
"exp", exp,
"log", log };
#define NBF (sizeof table / sizeof table[0])
main() {
char nom[80];
double x;
int i;
for(;;) {
scanf("%s", nom);
24
POINTEURS DE FONCTIONS
if (strcmp(nom, "fin") == 0)
break;
scanf("%lf", &x);
for(i = 0; i < NBF && strcmp(table[i].nom, nom) != 0; i++)
;
if (i < NBF)
printf("%f\n", (*table[i].fon)(x));
else
printf("%s ???\n", nom);
}
}
sin 1
0.841471
cos 1
0.540302
fin 25
CHAPITRE 7. GENIE LOGICIEL
26
Modularité :
Un programme mono-module
triselection.c
• 1) Modularité #define N 10 // pseudo constante
/*déclarations des fonctions Þ prototypes)
• Un programme = void saisirTableau(int*t);
void afficherTableau(int *t);
void triSelection(int *t);
un ensemble de
/* définition du main */
fonctions dont la
fonction main main() {
int t[N];
saisirTableau(t);
• Un seul fichier .c =
triSelection(t);
afficherTableau(t);
un unique module }
principal /* définitions des fonctions Þ les corps
void saisirTableau(int *t) {…}
void afficherTableau(int *t) {…}
void triSelection(int *t) {…} 27
Limites de l’approche mono-module
28
La notion de module
• Définition
Unité de programme composée
de constantes, de types, de variables et de fonctions
29
Un programme structuré en modules
tabio.h main.c
void saisirTableau(int *t, int n);
#define N 10
void afficherTableau(int *t, int n);
#include ²tabio.h²
void triSelection(int *t, int n);
void main() {
tabio.c
int t[N];
#include ²tabio.h²
saisirTableau(t, N);
#include <stdio.h>
triSelection(t, N);
void saisirTableau(int *t, int n) {
afficherTableau(t, N);
… /* corps */ }
}
void afficherTableau(int *t, int n) {
… /* corps */ }
void triSelection(int *t, int n) {
…}
Module principal
30
Module tabio.c
Intérêts des modules
• Réutilisation
– Un module peut être réutilisé par un autre module / programme
• Extensibilité – Flexibilité
– Changement du corps d’un module
– Ajout d’un nouveau service à un module
– Ajout d’un module, remplacement d’un module
• Sécurité
– Une unité utilisatrice n’a pas accès au corps du module
• Validation
– Facilité à tester chaque module indépendamment, en vue de
vérifier le bon fonctionnement de l’application
31
Modules et compilation séparée
• Unités de compilation
– Un fichier .h n’est pas une unité de compilation
– Un fichier .c est une unité de compilation qui inclut le fichier .h
• Règle de base
– Compiler un module (le fichier .c) avant toute unité utilisatrice
• Modification du corps d’un module
– Recompiler le fichier .c du module
– Édition des liens sans recompiler les unités utilisatrices
• Modification de l’interface d’un module
– Recompiler le fichier .c du module
– Recompiler toutes les unités utilisatrices
32
Mise en œuvre d’un programme
modulaire ( sous linux )
• Commandes de compilation
1. $ gcc –c tabio.c → production de tabio.o
2. $ gcc –c main.c → production de main.o
• Commandes d’édition de liens
– $ gcc main.o tabio.o –o tab
→ production du fichier exécutable tab
33
Utilisation des modules
• Gestion d’un ensemble de fonctions
– Modules standard : stdio, stdlib, string, math, …
– Modules graphiques, bases de données, …
34
Un module de gestion du type point
point.h Point.c
#include “point.h“
typedef struct point {
int x; POINT milieu (POINT X, POINT Y) {
int y; POINT M;
} POINT; M.x = (X.x + Y.x) / 2;
M.y = (X.y + Y.y) / 2;
POINT milieu(POINT, POINT); return M;
}
35
Un module de gestion du type point
main.c
#include “point.h“
int main( ) {
POINT point_courant;
POINT A = {1, 2};
POINT B = {3, 4};
point_courant = milieu(A, B);
printf(“%d %d”, point_courant.x, point_courant.y);
return 0;
}
36
GENIE LOGICIEL
• 2) Arguments du programme principal
En-tête complet de main
int main(int argc, char *argv[ ])
argc – nombre d’arguments du programme;
argv – tableau de chaînes de caractères (arguments du
programme. Par convention, le premier argument
est le nom du programme lui-même.
ex
Soit un programme de nom « exec » qui est lancé par la commande
exec Mamadou Ibra
37
GENIE LOGICIEL
e x e c \0 M a m a d o u \0 I b r a \0
argc
argv
3
NULL
double fonc(double x)
{
return (4*x*x+5*x-1);
}
double dicho(double a,double b,double eps,double (*f)(double))
{
double x;
while (b-a > eps)
if ((*f)(x=(a+b)/2) *(*f)(b) <= 0)
39
GENIE LOGICIEL
a=x;
else
b=x;
return x;
}
int main(int argc,char *argv[])
{
double x1,a1,b1,eps1;
//a1=0.0;b1=1.0;eps1=1E-8;
clrscr();
if (argc != 4)
{
printf("Mauvais usage de la commande"); exit(1);
}
40
GENIE LOGICIEL
a1=atof(argv[1]);
b1=atof(argv[2]);
eps1=atof(argv[3]);
x1=dicho(a1,b1,eps1,fonc);
printf("x1=%e",x1);
getch();
return 0;
}
Appel
dicho 0.0 1.0 1E-8
∫ab f(x) dx
integrale a b
41
GENIE LOGICIEL
3) Fonction exit
exit met fin à un programme : void exit (int status)
Pour exit status est fourni au processus appelant pour lui indiquer le code de
sortie du processus
En général, une valeur nulle indique une sortie normale et une valeur non
nulle indique une erreur
Valeurs symboliques de status
EXIT_SUCCESS fin normale
EXIT_FAILURE fin anormale, signale au SE que le
programme s’est terminé avec une erreur
42