Cours de Programmation S4
Cours de Programmation S4
Cours de Programmation S4
Programmation C Avancée.
Objectifs de ce module
Plan de ce module
Pointeurs
Pointeurs
Pointeurs
Pointeurs
Pointeurs
• Exemple :
int *pi; // pi est un pointeur vers un int
short int *psi; // psi est un pointeur vers un short int
char *pc; // pc pointeur vers un char
Pointeurs
Pointeurs
Pointeurs
Pointeurs
Exercices.
Petites devinettes : Soient i et j deux pointeurs vers des
entiers.
Pointeurs
Pointeurs
Pointeurs
Pointeurs
• Que va t il se passer ?
Pr. Abdessamad JARRAR SMI S4
Chapitre 1 : Pointeur et Allocation Dynamique.
Pointeurs
Pointeurs
Pointeurs
• Exemple :
int i = 2;
int *p1, *p2;
p1 = &i;
p2 = p1 + 1;
printf("Adresse p1 = Ox%lx \t Adresse p2 = 0x%lx\n", (unsigned long)p1,
(unsigned long)p2);
printf("Diff´erence des adresses: %lu \t sizeof(int)=%u\n", (unsigned
long)p2-(unsigned long)p1, sizeof(int));
printf("MAIS p2-p1 = %i !\n",p2-p1);
Pointeurs
• Ce programme renverra :
Adresse p1 = Oxbffffb24 Adresse p2 = 0xbffffb28
Différence des adresses: 4 sizeof(int)=4
MAIS p2-p1 = 1 !
• Exemple:
int *T;
int N, i;
printf("Veuillez saisir le nombre d'éléments du tableau :");
scanf("%d",&N);
T = (int*)calloc(N,sizeof(int));
for(i=0;i<N;i++)
printf("T[%d]=%d \n",i,T[i]);
• Attention :
• La fonction free peut aboutir à un désastre si on essaie
de libérer de la mémoire qui n’a pas été allouée par
malloc ou calloc.
• free ne change pas le contenu du pointeur.
• Si la mémoire n’est pas libérée à l’aide de free, alors elle
l’est automatiquement à la fin du programme.
Cependant, cela ne doit pas dispenser de l’utilisation de
cette fonction. Si la mémoire n’est pas libérée à chaque
suppression d’un élément de la liste, on aboutira
rapidement à une violation de mémoire et au
traditionnel message d’erreur ”Segmentation fault”.
Exercices.
Exercice 1 : Ecrire un programme en C qui permet de
d’inverser un tableau d’entiers de taille N (choisit par
l’utilisateur) en utilisant les pointeurs.
Exercices.
Solution :
int *T;
int N, i, aux; for(i=0;i<N/2;i++)
printf("Veuillez saisir le nombre {
d'éléments du tableau :"); aux = *(T+i);
scanf("%d",&N); *(T+i) = *(T+N-i-1);
T = (int*)malloc(N*sizeof(int)); *(T+N-i-1) = aux;
for(i=0;i<N;i++) }
{
printf("T[%d]=",i); for(i=0;i<N;i++)
scanf("%d",T+i); printf("T[%d]=%d \n",i,T[i]);
}
Exercices.
Exercice 2 : Ecrire un programme en C qui permet de remplir
un tableau de trois élément de différents types (Le premier
est un entier, le deuxième est un réel et le troisième est de
type char).
Exercices.
Solution :
Fin de ce chapitre
Chaines de Caractères.
Introduction
• Dans un programme informatique, les chaînes de
caractères servent à stocker les informations non
numériques comme par exemple une liste de nom de
personne ou des adresses.
Exemples d’initialisation
• Attention à la déclaration:
– Pour la mémorisation de la chaîne de caractères "Hello", C a
besoin de six (!!) octets.
– 'x’ est un caractère constant, qui a une valeur numérique:
• Par exemple: 'x' à la valeur 120 dans le code ASCII.
– "x” est un tableau de caractères qui contient deux caractères: la
lettre 'x' et le caractère NUL: '\0'
– 'x’ est codé dans un octet
– "x” est codé dans deux octets
A savoir (1)
• Les chaînes de caractères constantes (string literals) sont
indiquées entre guillemets. La chaîne de caractères vide
est alors: ""
• Dans les chaînes de caractères, nous pouvons utiliser
toutes les séquences d'échappement définies comme
caractères constants: "Ce \ntexte \nsera réparti sur 3
lignes."
• Le symbole " peut être représenté à l'intérieur d'une
chaîne par la séquence d'échappement \”.
• Le symbole ' peut être représenté à l'intérieur d'une liste
de caractères par la séquence d'échappement \' :
{'L','\'','a','s','t','u','c','e','\0'}
Pr. Abdessamad JARRAR SMI S4
Chapitre 2 : Chaines de Caractères.
Précédence et opérations
• Une chaîne de caractères est une variable : on peut utiliser
des opérations logiques et mathématiques.
• La précédence des caractères dans l'alphabet d'une
machine est dépendante du code de caractères utilisé.
Pour le code ASCII, nous pouvons constater l'ordre suivant:
– . . . ,0,1,2, ... ,9, . . . ,A,B,C, ... ,Z, . . . ,a,b,c, ... ,z, . . .
• Les symboles spéciaux (' ,+ ,- ,/ ,{ ,] , ...) et les lettres
accentuées (é ,è ,à ,û , ...) se trouvent répartis autour des
trois grands groupes de caractères (chiffres, majuscules,
minuscules). Leur précédence ne correspond à aucune
règle d'ordre spécifique.
Tableau ASCII
Précédence et opérations
• La précédence alphabétique des caractères induit une
relation de précédence 'est inférieur à' sur l'ensemble des
caractères. (idem pour les autres relations logiques)
• Ainsi, on peut dire que '0' est inférieur à 'Z‘ et noter '0' < 'Z’
• Ceci est possible car dans l'alphabet de la machine, le code
du caractère '0' (ASCII: 48) est inférieur au code du
caractère 'Z' (ASCII: 90).
– Exemples
• "ABC" précède "BCD” car 'A'<'B'
• "ABC" précède "B” car 'A'<'B'
• "Abc" précède "abc” car 'A'<'a'
• "ab" précède "abcd” car "" précède "cd"
• " ab" précède "ab” car ' '<'a'
Pr. Abdessamad JARRAR SMI S4
Chapitre 2 : Chaines de Caractères.
Tests logiques
• En tenant compte de l'ordre alphabétique des caractères,
on peut contrôler le type du caractère (chiffre, majuscule,
minuscule).
– Exemple: if (C>='0' && C<='9') printf("Chiffre\n", C);
if (C>='A' && C<='Z') printf("Majuscule\n", C);
if (C>='a' && C<='z') printf("Minuscule\n", C);
• ou vice-versa:
if (C>='a' && C<='z') C = C-'a'+'A';
Tableaux de chaînes
• Une chaîne de caractères est un tableau à 1 dimension de
caractères.
• On peut également définir des tableaux à plusieurs
dimensions qui peuvent contenir des mots:
char JOUR[7][9] = {“lundi” , ”mardi” , ”mercredi” , ”jeudi” ,
”vendredi”,”samedi”,”dimanche”};
Fonctions de bibliothèque
Fonctions de bibliothèque
– <string.h> :
• strlen(<s>): fournit la longueur de la chaîne sans compter le '\0' final
• strcpy(<s>, <t>): copie <t> vers <s>
• strcat(<s>, <t>): ajoute <t> à la fin de <s>
• strcmp(<s>, <t>): compare <s> et <t> lexicographiquement et fournit
un résultat:
– négatif si <s> précède <t>
– zéro si <s> est égal à <t>
– positif si <s> suit <t>
• strncpy(<s>, <t>, <n>): copie au plus <n> caractères de <t> vers <s>
• strncat(<s>, <t>, <n>): ajoute au plus <n> caractères de <t> à la fin
de <s>
Fonctions de bibliothèque
• Attention:
• La nature de tableau d’une chaîne de caractères (ie,
l’adresse en mémoire du premier élément) interdit des
affections du type A= “hello” en dehors de la phase
d’initialisation.
– char A[ ]=“Hello”; est correct mais
– char A[6]; A= “Hello”; ne l’est pas.
• Il faut bien copier la chaîne caractère par caractère ou
utiliser la fonction strcpy respectivement strncpy:
– strcpy(A, "Hello");
Fonctions de bibliothèque
• <stdlib>: conversion chaîne -> nombre
– atoi(<s>) retourne la valeur numérique représentée par <s>
comme int
– atol(<s>) retourne la valeur numérique représentée par <s>
comme long
– atof(<s>) retourne la valeur numérique représentée par <s>
comme double (!)
Exercices.
Exercice 1 : Ecrire un programme C qui lit une chaîne de
caractères et vérifie si elle est palindrome ou non. On
rappelle qu'une chaîne de caractères est dite palindrome, si
elle se lit de la même manière dans les deux sens.
Exemple: non, touot et 1234321 sont toutes
des chaînes de caractères palindromes.
Exercices.
Solution :
#include<stdio.h> {
#include<stdlib.h> if(s[i]!=s[j])
#include<string.h> {
ok=0;
int main() break;
{ }
char s[100]; }
int i, j, ok; if(ok==1) printf("%s est
printf("Donnez une chaine de palindrome.\n",s);
caracteres:\n"); else printf("%s n'est pas
scanf("%s",s); palindrome.\n",s);
ok=1; return 0;
for(i=0,j=strlen(s)-1;i<j;i++,j--) }
Fin de ce chapitre
Fonctions.
Programmation modulaire
• Un programme dépassant une ou deux pages est difficile à
comprendre
Programmation modulaire
Bien différencier :
• Le texte (ou code) d’un programme qui est donc une suite
de fonctions non emboîtées (on ne définit pas une
fonction dans une autre fonction)
– Une fonction appelée dans une autre fonction a son code propre
séparé de la fonction appelante
Les fonctions
• Dès qu’un groupe de lignes revient plusieurs fois on les
regroupe dans une fonction
• Attention:
• En C, une fonction ne peut retourner qu’une valeur (au plus) grâce à la
commande return
• Le type de la fonction doit être le même que celui de la valeur retournée
• Quand une fonction ne retourne pas de valeur elle est typée void
– Exemples : void main() ; void AfficheBonjour();
Le return
Il permet de:
• Retourne la valeur au programme appelant
• Et interrompt immédiatement l’exécution de la fonction
– On peut avoir plusieurs return.
– Mais un seul return pris en compte à chaque exécution.
• Exemple:
int est_positif(int val)
{
if( val >= 0)
return 1;
else
return 0;
}
Fonctions et tableau
• Un tableau peut être un argument d’entrée d’une fonction.
• La syntaxe est : int tab[22] ;
int N = 22 ;
… // bout de code
m = Moyenne(tab,N) ;
… // bout de code
x = Maximum(tab,N)) ;
• Il peut être retourné sous forme de pointeur.
• On transmet donc le nom du tableau sans crochets
• Très souvent, le nombre d’éléments du tableau sur lequel
on souhaite travaillé est aussi un argument de la fonction
pour donner un caractère générique à la fonction.
Conseils
• Si vous utilisez beaucoup de fonctions, tenez leur liste à
jour (Tableur, texte, …).
• Lorsque vous écrivez une fonction : testez‐la et
assurez‐vous de son bon fonctionnement avant de passer à
l’écriture de la suivante !!
• Ce qu’on ne doit jamais faire : écrire toutes les fonctions
et tester ensuite tout d’un bloc.
• Evitez les printf dans une fonction qui n’est pas dédiée à
l’affichage. Vous pouvez utiliser des affichages avec printf
dans vos fonctions pour les débugger, mais retirez‐les dès
que la fonction marche correctement.
Conseils
• Au niveau du texte :
– Un programme en C est un ensemble disjoint de fonctions dont
une seule porte le nom de main (programme principal) et
constitue le point d’entrée du programme.
– On verra qu’on peut répartir les fonctions dans plusieurs fichiers
textes
• Au niveau de l’exécution :
– Un programme en C est une succession d’appels d’instructions et
de fonctions pouvant utiliser comme paramètres des résultats de
fonctions (et ainsi de suite).
Programmation récursive
• Définition : la programmation récursive est une technique
de programmation qui remplace les instructions de boucle
(while, for, etc.) par des appels de fonction.
– (Ne pas confondre avec la notion de récursivité en
mathématiques)
• Exemple:
long fac (int n)
{
if (n>1)
return fac(n-1)*n ;
else
return 1 ;
}
void triple(int);
int main() void triple(int a)
{ {
int a = 1; a = 3*a;
triple(a); }
printf("%d",a);
return 0;
}
• se déclare par :
type (*p_fonction)(type_1,...,type_n);
Exercices.
Exercice 1 : écrire un programme qui permet de calculer le
nombre de combinaisons de p éléments parmi n éléments
définit par:
Exercices.
Solution :
int main() else
{ return factoriel(n-1)*n;
printf("%d",combinaison(2,10)); }
return 0;
} int combinaison(int p, int n)
{
int factoriel(int n) return factoriel(n) /
{ (factoriel(p)*factoriel(n-p));
if(n < 2) }
return 1;
Fin de ce chapitre
Les énumérations
• Les énumérations permettent de définir un type pour des
variables qui ne sont affectées qu’a un nombre fini de
valeurs.
• Un objet de type énumération est défini par le mot-clef
enum et un identificateur de modèle, suivi de la liste des
valeurs que peut prendre cet objet :
enum modele {constante1, constante2,. . . ,constanten} ;
Les énumérations
• Dans l’exemple suivant, le type enum boolean associe
l’entier 0 à la valeur FALSE et l’entier 1 à la valeur TRUE.
#include <stdio.h>
enum boolean {FALSE, TRUE};
int main () {
enum boolean b1 = TRUE; //declaration
printf("b = %d\n",b1);
return 0;
}
Les structures
• Une structure est une suite finie d'objets de types
différents.
• Contrairement aux tableaux, les différents éléments d'une
structure n'occupent pas nécessairement des zones
contiguës en mémoire.
• Chaque élément de la structure, appelé membre ou
champ, est désigné par un identificateur.
• Ce mécanisme permet de grouper un certain nombre de
variables de types différents au sein d’une même entité.
struct nom_structure {
type_1 membre1 ;
type_2 membre2 ;
...
type_n membren ;
};
Structures auto-référées
• Il s’agit de cas particulier de structures dont un des
membres pointe vers une structure du même type.
• Cette représentation permet en particulier de construire
des listes chaînées.
• il est possible de représenter une liste d’éléments de
même type par un tableau (ou un pointeur).
• Toutefois, cette représentation, dite contiguë, impose que
la taille maximale de la liste soit connue a priori.
• Pour résoudre ce problème, on utilise une représentation
chaînée : l’élément de base de la chaîne est une structure
appelée cellule qui contient la valeur d’un élément de la
liste et un pointeur sur l’élément suivant.
Pr. Abdessamad JARRAR SMI S4
Chapitre 4 : Types Composés (Structures, Unions, Synonymes).
Structures auto-référées
• Le dernier élément pointe sur le pointeur NULL (défini
dans stddef.h).
• La liste est définie comme un pointeur sur le premier
élément de la chaîne.
Structures auto-référées
• Grâce au mot-clef typedef, on peut définir le type liste,
synonyme du type pointeur sur une struct toto.
• On peut alors définir un objet liste l qu’il convient
d’initialiser à NULL.
Structures auto-référées
• Un des avantages de la représentation chaînée est qu’il est
très facile d’insérer un élément à un endroit quelconque
de la liste.
• Ainsi, pour insérer un élément en tête de liste, on utilise la
fonction suivante :
liste insere(int element, liste Q) {
liste L;
L = (liste)malloc(sizeof(struct toto));
L->data = element;
L->next = Q;
return L;
}
Structures auto-référées
De façon général, l’ajout d’un nouvel élément dans une liste
chaînée s’effectue en trois étapes :
1. recherche de l’endroit où la nouvelle cellule devra être
insérée ;
2. Création de la nouvelle cellule (par malloc) et mise à jour
de ses champs. Au niveau de l’allocation en mémoire, on
prendra garde :
1. de réserver le bon nombre d’octets (en reprenant l’exemple
précédent, sizeof(struct toto) et non sizeof(struct toto *))
2. de convertir le résultat du malloc vers le bon type (pointeur vers
la structure).
3. mise à jour des champs des cellules voisines.
Pr. Abdessamad JARRAR SMI S4
Chapitre 4 : Types Composés (Structures, Unions, Synonymes).
Structures auto-référées
• Pour supprimer le premier élément de la liste par exemple,
il est important de libérer l’espace mémoire alloué :
liste supprime_tete(liste L) {
liste suivant = L;
if (L != NULL) { // pour etre sûr que L->next existe
suivant= L->next;
free(L); //libération de l’espace alloué pour une cellule
}
return suivant;
}
Structures auto-référées
• Il est primordial d’utiliser free dans le cas des listes
chaînées.
• Sinon, la mémoire risque d’être rapidement saturée (par
exemple lors d’ajouts et de suppressions successives qui ne
libèrent pas l’espace alloué).
Les unions
• Il est parfois nécessaire de manipuler des variables
auxquelles on désire affecter des valeurs de types
différents.
• Une union désigne un ensemble de variables de types
différents susceptibles d’occuper alternativement une
même zone mémoire.
• Une union permet donc de définir un objet comme
pouvant être d’un type au choix parmi un ensemble fini de
types.
• Si les membres d’une union sont de longueurs différentes,
la place réservée en mémoire pour la représenter
correspond à la taille du membre le plus grand.
Pr. Abdessamad JARRAR SMI S4
Chapitre 4 : Types Composés (Structures, Unions, Synonymes).
• Exemple :
typedef unsigned char UCHAR;
typedef struct { double x, y } POINT;
typedef POINT *P_POINT; //pointeur vers un POINT
Exercices.
Exercice 1 : Définir un type rationnel comportant les deux
champs num (pour numérateur) et den (pour dénominateur)
de types entier puis des fonctions permettant la saisie d’un
rationnel, son affichage, la somme, la multiplication, la
soustraction et la division de deux rationnels.
Fin de ce chapitre
Fichiers.
Exercices.
Exercice 1 :
1. Ecrivez une fonction compte_c(FILE * f) qui renvoie le
nombre de caractères d’un fichier.
2. Ecrivez une fonction compte_m(FILE * F) qui renvoie le
nombre de mots d’un fichier. Les mots sont
séparés par des espaces ou des retours à la
ligne.
3. Ecrivez une fonction compte_l qui renvoie
le nombre de lignes.
Exercices.
Solution :
int compte_c(FILE ∗ f ){ on_est_sur_un_mot =1;
int cp_t =0; cp_t++; }
while ( fgetc( f )!=EOF) cp_t++; }
return cp_t ; return cp_t ;
} }
Fin de ce chapitre
La directive #include
• #include permet d’incorporer dans le fichier source le
texte figurant dans un autre fichier.
• La directive #include possède deux syntaxes voisines :
– #include <nom-de-fichier>: recherche le fichier mentionné dans
un ou plusieurs répertoires systèmes définis par l’implémentation
(typiquement /usr/include/) :
– #include "nom-de-fichier": recherche le fichier dans le répertoire
courant (celui où se trouve le fichier source). On peut spécifier
d’autres répertoires à l’aide de l’option -I du compilateur.
• La première syntaxe est généralement utilisée pour les
fichiers en-tête de la librairie standard, tandis que la
seconde est destinée aux fichiers créés par l’utilisateur.
La directive #define
• La directive #define permet de définir des constantes
symboliques (on parle aussi de macros sans paramètres)
ou des macros avec paramètre.
• Lorsque le préprocesseur lit une ligne du type :
#define nom reste-de-la-ligne
La directive #define
• L’utilité principale des macros sans paramètre est de
donner un nom parlant à une constante. Les avantages à
toujours donner un nom aux constantes sont les suivants :
– un nom bien choisi permet d’expliciter la sémantique de la
constante. Ex : #define NB_COLONNES 100
– la constante chiffrée se trouve à un seul endroit, ce qui facilite la
modification du programme quand on veut changer la valeur de la
constante (cas de la taille d’un tableau, par exemple).
– on peut expliciter facilement les relations entre constantes. Ex :
#define NB_LIGNES 24
#define NB_COLONNES 80
#define TAILLE_MATRICE NB_LIGNES * NB_COLONNES
La compilation conditionnelle
• La compilation conditionnelle a pour but d’incorporer ou
d’exclure des parties du code source dans le texte qui sera
généré par le préprocesseur, le choix étant basé sur un test
exécuté à la compilation.
• Elle permet d’adapter le programme au matériel ou à
l’environnement sur lequel il s’exécute, ou d’introduire
dans le programme des instructions de débuggage.
• Les directives de compilation conditionnelle se
répartissent en deux catégories, suivant le type de la
condition invoquée qui est testée :
– la valeur d’une expression
– l’existence ou l’inexistence de symboles
Pr. Abdessamad JARRAR SMI S4
Chapitre 6 : Compilation séparée et Directives du Préprocesseur.
La compilation conditionnelle
• La syntaxe de la compilation à condition liée à la valeur
d’une expression est :
#if condition-1
partie-du-programme-1
#elif condition-2
partie-du-programme-2
...
#elif condition-n
partie-du-programme-n
#else
partie-du-programme-else
#endif
La compilation conditionnelle
• Lors de la compilation, une seule partie-du-programme-i
sera compilée : celle qui correspond à la première
condition-i non nulle, ou bien la partie-du-programme-else
si toutes les conditions sont nulles.
• Par exemple, on peut écrire :
#define PROCESSEUR ALPHA
...
#if PROCESSEUR == ALPHA
taille_long = 64;
#elif PROCESSEUR == PC
taille_long = 32;
#endif
La compilation conditionnelle
• La syntaxe de la compilation à condition liée à l’existence
d’un symbole est :
#ifdef symbole
partie-du-programme-1
#else condition-2
partie-du-programme-2
#endif
La compilation conditionnelle
• La directive #else est comme précédemment facultative.
• Ce type de directive est utile pour rajouter des instructions
destinées au débuggage du programme :
#define DEBUG
....
#ifdef DEBUG
for (i = 0; i < N; i++)
printf("%d\n",i);
#endif /* DEBUG */
La compilation conditionnelle
• De façon similaire, on peut tester la non-existence d’un
symbole à l’aide de la directive #ifndef :
#ifndef symbole
partie-du-programme-1
#else condition-2
partie-du-programme-2
#endif
L’opérateur defined
• L’opérateur defined est un opérateur spécial : il ne peut
être utilisé que dans le contexte d’une commande #if ou
#elif.
• Il peut être utilisé sous l’une des deux formes suivantes :
– defined nom
– defined ( nom )
• Il délivre la valeur 1 si nom est une macro définie, et la
valeur 0 sinon. L’intérêt de cet opérateur est de permettre
d’écrire des tests portant sur la définition de plusieurs
macros, alors que #ifdef ne peut en tester qu’une :
#if defined(SOLARIS) || defined(SYSV)
La commande #error
• La commande #error a la syntaxe suivante :
#error chaine
La programmation modulaire
• Dès que l’on écrit un programme de taille importante ou
destiné à être utilisé et maintenu par d’autres personnes, il
est indispensable de se fixer un certain nombre de règles
d’écriture.
La programmation modulaire
• L’idée est alors de regrouper dans un même fichier les
instructions implémentant des fonctionnalités similaires.
Principes élémentaires
• Trois principes essentiels doivent guider l’écriture d’un
programme C. Ces principes s’appliquent en fait dans le cas
général du génie logiciel.
1. L’abstraction des constantes littérales
L’utilisation explicite de constantes littérales dans le corps d’une
fonction rend les modifications et la maintenance difficiles. Des
instructions comme : fopen("mon_fichier", "r");
perimetre = 2 * 3.14 * rayon;
sont à proscrire (il faudrait définir des constantes fournissant le nom
du fichier ou la valeur de Pi). Sauf cas très particuliers, les constantes
doivent être définies comme des constantes symboliques au moyen
de la directive #define.
Principes élémentaires
2. La factorisation du code
Le but est d’éviter les duplications de code. La présence d’une même
portion de code à plusieurs endroits du programme est un obstacle à
d’éventuelles modifications. Les fonctions doivent donc être
systématiquement utilisées pour éviter la duplication de code. Il ne
faut pas craindre de définir une multitude de fonctions de petite
taille.
3. La fragmentation du code
Pour des raisons de lisibilité, il est pertinent de découper un
programme en plusieurs fichiers. En plus, cette règle permet de
réutiliser facilement une partie du code pour d’autres applications.
On sépare alors le programme en modules, chaque module
implémentant des fonctions sur un thème similaire et qui se
traduiront physiquement par deux fichiers :
Pr. Abdessamad JARRAR SMI S4
Chapitre 6 : Compilation séparée et Directives du Préprocesseur.
Principes élémentaires
a. un fichier en-tête (on dit aussi de header) ayant l’extension .h et
contenant le prototype des fonctions principales implémentées dans
ce module.
b. un fichier source ayant l’extension .c contenant non seulement le
corps des fonctions déclarées dans le fichier en-tête mais également
celui des fonctions intermédiaires éventuellement utilisées. Ce fichier inclut
évidemment le fichier en-tête par le biais de la directive #include.
• L’exemple suivant illustre ce principe sur un programme
qui saisit deux entiers au clavier et affiche leur produit.
Sur cet exemple, il a été choisi de définir un module
arithmétique qui fournit la fonction effectuant le produit.
Ce module est donc implémenté dans les fichiers
arithmétique.h et arithmétique.c.
int main(void) {
int a, b, c;
scanf("%d",&a);
scanf("%d",&b);
c = produit(a,b); // appel de la fonction d´efinie dans arithmetique.h
printf("\nle produit vaut %d\n",c);
return EXIT_SUCCESS;
}
La compilation séparée
• Ce n’est pas le tout de bien fragmenter son code en
plusieurs fichiers, encore faut-il les compiler pour obtenir
un exécutable.
• La méthode consiste à générer un fichier objet par module
(option -c de gcc) :
gcc -O3 -Wall -I. -c module_1.c
gcc -O3 -Wall -I. -c module_2.c
...
gcc -O3 -Wall -I. -c module_n.c
Exercices.
Exercice 1 : Ecrire un programme qui affiche un menu puis
demande à l’utilisateur de choisir une opération
arithmétique élémentaire (+, -, x, /) ou une fonction
mathématique (cos, sin, tan, exp, ln). Ensuite, le programme
demande la saisie des valeurs nécessaire
pour le calcul et affiche le résultat.
Vous devez créer les fichiers suivant:
Main.c, operation_arith.c, operation_arith.h,
Operation_math.c, operation_math.h
Fin de ce chapitre