ProgrammationII SMI S4 (Aide)

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 113

Programmation II

Filière SMI/S4
Pr Jaouad BOUMHIDI

1
Plan du cours/S4
1. Pointeurs et allocation dynamique
2. Les Fonctions et récursivité
3. Les chaines de caractères
4. Types composés : Structures et Unions
5. Gestion des fichiers
6. Complément:
• Traitement par le préprocesseur, compilation, assemblage et édition
des liens
• compilation séparée, directives du processeur
• définition de macros
• Compilation conditionnelle 2
Chapitre 1: LES POINTEURS
Variable déclarée:
Toute variable manipulée dans un programme est stockée
quelque part en mémoire centrale

Lorsqu’on déclare une variable var de type T, l’ordinateur réserve un


espace mémoire (de sizeof(T) octets) pour y stocker les valeurs de var 3
Exemple:
int rt=100;

Il est possible d’ accéder au contenu d’une variable


(non pas par son nom) mais par son adresse en
utilisant les pointeurs

13/04/2015 4
Définition:
• Un pointeur est une variable caractérisée par un
identificateur et un type,

• Sa caractéristique spéciale est qu’elle est destiné à


contenir l’adresse en mémoire d’une autre variable(où
est stocké) .
On dit qu’il pointe vers un emplacement en mémoire.

5
Intérêts des Pointeurs :
• Simplicité(passage tableau en arguments)
au lieu de passer à une fonction un élément très grand (en
taille) on pourra par exemple lui fournir un pointeur vers
cet élément...
• stocker des éléments de taille diverse
Les tableaux statiques ne permettent de stocker qu'un
nombre fixé d'éléments de même type.
En stockant des pointeurs dans les cases d'un tableau, il
sera possible de stocker des éléments de taille diverse.

6
Intérêts des Pointeurs :

• Rapidité
• économie de mémoire.
définit des types structurés dynamiques(Les
listes),
Exemple: salle d’attente médecin

7
Déclaration
Syntaxe :
type *ptr ;
(*) c’est l’opérateur d’indirection qui indique que le pointeur ptr pointe
sur la variable de type (type)

Exemple:
char *pc; pc est un pointeur pointant sur un objet de type char
int *pi; pi est un pointeur pointant sur un objet de type int
float *pr; pr est un pointeur pointant sur un objet de type float .

8
Les opérateurs & et *
L’opérateur & est utilisé pour renvoyer l’adresse d’une variable.

Syntaxe: &var /*retourne l’adresse de la variable de nom var*/.


Exemple

int i=100 ;
printf(" voici i :d\n ",i) ;
printf(" voici son adresse en hexadécimale : %x\n ",&i) ;

9
Exemple:
int rt;
int *P_rt;
rt =100;

P_rt=NULL ;

P_rt=& rt ;

13/04/2015 10
& et * : deux opérateurs symétriques

Si x est un pointeur vers un entier a. (x=&a et a=*x)


& donne l’adresse d’une variable
• donne la valeur pointée par un pointeur

Exercice :
Écrire un programme (expliqué par des schémas en mémoire) dans lequel:
Vous déclarez une variable entière i et un pointeur p de type entier ;
Initialisez i par une valeur saisie et pointez p sur i ;
Affichez la valeur de i, de p et de (*p) ;
En utilisant p, modifiez l'entier pointé par p ;
Affichez la valeur de i, de p et de (*p) ;

13/04/2015 11
Void* et NULL
• Il est possible de définir un pointeur sur void , c’est-`a-dire sur
quelque chose qui n’a pas de type prédéfini.

Un pointeur de type void * est un pointeur :


– universel,
– générique,
• Il existe un pointeur qui ne pointe sur rien : NULL.
int *p = NULL;

12
Opérations possibles sur les pointeurs(Rappel) :

Incrémentation et décrémentation ou généralement (l’addition/


soustraction d’un entier à un pointeur )
On peut ajouter (ou soustraire) un nombre entier à la valeur d’un pointeur
pour pointer sur un emplacement mémoire différent

Exemple: int* ad; ad++ ad est incrémenté de sizeof(int).

Différence :
Possible entre deux pointeurs de même type (si vous avez deux
pointeurs sur un même tableau, le résultat de leur soustraction
correspond au nombre d’éléments qui les séparent).
Comparaison :
= = , != , > , < , >= et <=
Ne sont validés que pour deux pointeurs de même type.

Remarques
Eviter d’effectuer des opérations mathématiques comme des divisions,
des multiplications ou des modulos
Remarque:
Après avoir déclaré un pointeur il faut l’initialiser.

Risques possibles:
- soit message d’erreur à l’exécution ”Segmentation fault”. Et arrêt du
programme.
- Soit plantage et redémarrage de votre ordinateur

Il faut noter que certain compilateurs ont la bonne idée d’initialiser


automatiquement à la valeur NULL un pointeur non affecté.
Mais cela ne doit pas empêcher de prendre la bonne habitude d’initialiser
tout pointeur

13/04/2015 14
Pointeurs et tableaux

Deux types d’allocation d’espace mémoire

• Statique (Réservation d’espace mémoire lors de la compilation)


• Dynamique (Réservation d’espace mémoire lors de l’éxécution)

Déclaration statique d’un tableau

int tab[100] ; Ici Tab est un pointeur dit constant


Tab équivalent à &tab[0]
Tab+i équivalent à &tab[i]
*(Tab+i) équivalent à tab[i]
15
int tab[10];
tab: pointeur constant: Attention Tab++!!
Solution: On déclare un tableau statique et
un pointeur ainsi :
• int tab[10];
• int *p;
alors l’affectation : p=&tab[0]
P++ est possible

16
Allocation dynamiques
• Allouer de la mémoire statique avait un intérêt limité.
• Comment faire pour réserver de l’espace au moment de l’exécution ?
• Solution: Il faut allouer la mémoire dynamiquement.

void * malloc (size_t size); // Void* est compatible avec tous les types.

• Alloue size octets ;


Pour l’utiliser il faut inclure la bibliothèque <stdlib.h> en début de
programme.
malloc( N ) renvoie l’adresse d’un bloc de mémoire de N octets libres (ou
la valeur NULL s’il n’y a pas assez de mémoire).
• La zone de mémoire n’est pas initialisée.
• long *a = (long *)malloc( sizeof(long) );
• long *tab = (long *) malloc(100 * sizeof(long));
Tableaux et allocation dynamiques
Allocation dynamique pour un Tableau(Tableau dynamique)

Principe:
• Déclarer un pointeur sur le type des éléments
• Allouer l’espace nécessaire par une fonction d’allocation et Affécter
l’adresse du premier octet au pointeur

Réserver de la place pour un tableau de n entiers, où n est lu au clavier :


int n ;
int *tab ;
printf("taille du tableau :nn") ;
scanf("%d", &n) ;
tab = (int *)malloc(n*sizeof(int));

tab[i] est équivalent à *(tab+i)


(tab+i) est équivalent à &tab[i]
Fonction calloc
Fonction calloc :
La fonction calloc de la librairie stdlib.h a le même rôle que la fonction
malloc mais elle initialise en plus le tableau à zéro.
void *calloc (size_t nb, size_t size);
Alloue et remplit de 0 la mémoire nécessaire pour nb éléments
de size octets ; renvoie un pointeur sur la zone allouée.
Attention, ce n’est pas la même signature que malloc !
Syntaxe:

int* p; p = (int*)malloc(N * sizeof(int));


p = (int*)calloc(N, sizeof(int)); for (int i = 0; i < N; i++)
*(p + i) = 0;

L’emploi de calloc est simplement plus rapide.


19
void* realloc (void *p, size_t size);
• Réduit (ou augmente) la taille du bloc de mémoire pointé par p à
une taille de size octets ;
• realloc() s'utilise après qu'on ait utilisé la malloc() ou calloc()

• Si la zone mémoire précédemment allouée peut être augmentée


sans empiéter sur une zone mémoire utilisée pour autre chose,
alors l'adresse mémoire renvoyée n'est pas modifiée (c'est la même
que l'ancienne)
En revanche, si en augmentant la zone mémoire initiale on déborde sur
une zone mémoire déjà occupée, le système d'exploitation
cherchera une autre adresse pour laquelle le nombre de cases
mémoire nécessaires (le paramètre size) est disponible

20
• Exemple:
int * tab;
tab = (int *) calloc ( 2, sizeof(int) );
tab[0] = 33; tab[1] = 55;

tab = (int *)realloc(tab, 3 * sizeof(int) );


tab[2] = 77;
Quelle risque peut on avoir!!!

Si la ré-allocation échoue, realloc renvoie NULL, qui est affecté à tab,


on perd donc l'adresse de la zone mémoire allouée !

La solution consiste à créer un autre pointeur: temp par exemple, et


c'est à temp qu'on affectera le résultat de realloc. Il suffit ensuite de
tester sa valeur, et si elle n'est pas nulle, on la réaffecte à tab.
• temp = (int *)realloc(tab, 3 * sizeof(int) );
if (temp != NULL) tab = temp;
21
tab[2] = 77;
! Attention, il peut toujours se produire des erreurs lors de
l’allocation dynamique de mémoire : il faut TOUJOURS vérifier
que le pointeur retourné lors de l’allocation n’est pas NULL!
int *tab;
tab = (int *) malloc( 1000*sizeof(int) );
if( tab == NULL ){
printf("allocation ratée !");
exit(EXIT_FAILURE);
}
else{

}

Principe générale d’allocation:


1) On demande d ’allouer la mémoire
2) On vérifie si la mémoire a été alloueé
3) Utilisation de la mémoire allouée
22
Libérer l’espace mémoire déjà alloué

La mémoire n’étant pas infinie, lorsqu’un emplacement mémoire n’est


plus utilisé, il est important de libérer cet espace.
la fonction: void free( void *p ):
• libère l’espace mémoire pointé par p qui a été obtenu lors d’un
appel à malloc, calloc ou realloc
• Attention, free ne met pas le pointeur p à NULL, c’est à vous de la
faire.
• Exemple1
int *tab ;
printf("taille du tableau :nn") ;
scanf("%d", &n) ;
tab = (int *)malloc(n*sizeof(int)) ;
free(tab);
tab=NULL; 23
Exercice
En utilisant uniquement le formalisme pointeur et
allocation dynamique (pas de déclaration statique du
tableau.
Ecrire un programme qui permet de:
• lire au clavier les valeurs d'un tableau de N entiers.
• l’afficher à l’écran
• Calculer et afficher la somme des entiers saisis, leur
moyenne, la valeur maximale et son indice ainsi que
la valeur minimale et son indice.
Exercice

1) Créer un tableau dynamique T d’une taille N, lue au clavier et le remplir


d’entiers allant de 0 à N-1
2) Afficher le contenu de T
3) Ajouter un nouvel élément au tableau T sans avoir à écraser des données
dans T. Justifier cette possibilité pour T.

25
Pointeur et tableau à deux dimensions
Un tableau à deux dimensions (Matrice) est, par définition, un tableau
de tableaux. Il s’agit donc en fait d’un pointeur vers un pointeur.

Tab

Tab[0]

Tab[1]

Tab[2]

Tab[3]

26
Par exemple, pour créer avec un pointeur de pointeur, une matrice à L
lignes et C colonnes à coefficients entiers, on écrit :

main()
{
int L, C;
int ** tab;
tab = (int**)malloc(L * sizeof(int*));
for (i = 0; i < L; i++)
tab[i] = (int*)malloc(C * sizeof(int));

//Lecture au clavier
for (i = 0; i < L; i++)
for (j = 0; j < C; j++)
scanf("%d",tab[i]+j);
27
Libérer l’espace
la fonction free()
pour libérer (désallouer) l’espace mémoire
déjà alloué par la fonction malloc en utilise
la fonction free().
Exemple :
for (i = 0; i < L; i++)
{free(tab[i]); tab[i]=NULL}
free(tab);tab=NULL
28
Exercice
Soit M une matrice LxC éléments de type
entiers.
En utilisant uniquement la notion de pointeur
et d’allocation dynamique, écrire un
programme qui permet de:
a)saisir la matrice M
b)afficher la matrice M

29
Chapitre2. LES FONCTIONS EN C

On appelle fonction une partie de code source qui permet d’effectuer


un ensemble d’instructions par simple appel de la fonction.

simplicité du code et donc une taille de programme minimale.

Plusieurs fonctions pré-définies:


printf(), sin(), strlen(), strcpy()…

30
LA DEFINITION D’UNE FONCTION
Une fonction comporte deux parties :
La signature de la fonction consiste au type et au nom de la fonction suivis par les
types et les noms des paramètres.

Le corps de la fonction contient des déclarations de variables locales et un ensemble


d’instructions qui indiquent ce que la fonction doit faire. Il est sous forme de bloc.

Syntaxe

Type_retour nom_f (typ1 p1, ………….,typn pn) //signature de la fonction


{
Instructions //corps de la fonction
return valeur;
}

Avec:
type_retour : type de retour de la fonction
nom_f : nom de la fonction
typi (1<i<=n) : type du ieme paramètre de la fonction
pi (1<i<=n) : nom du ieme paramètre(argument) de la fonction.
31
Exemple de définition de fonction

int plus(int a,int b)


{ int A; espace libéré automatique
A=a+b ;
return A ; }

32
Structure générale d’un programme en
langage C
Déclaration des bibliothèques à utiliser

Type retour f1(arguments){


……
}

Type retour f2(arguments){


……
}
.
.
.

main( )
{
Instructions de déclaration
Instructions exécutables
return 0 ;
}
33
Instruction return :
Le rôle de l’instruction return dans la fonction est double : d’une part, il précise
la valeur qui sera fournie en résultat,
d’autre part, il met fin à l’exécution des instructions de la fonction.

Exemple : (fonction cube)


float cube(float x) /*en-tête de la fonction cube (Attention pas de ;)*/
{ float y ; /* variable local de la fonction cube*/
y=x*x*x ;
return y ; /* retour du résultat du cube de x*/
}
float : type du résultat de retour de la fonction
float x : type et nom du paramètre formel
cube : nom de la fonction

L’instruction return peut mentionner non seulement un nom de la variable, mais


en fait n’importe quelle expression.

34
Exemple :
float cube(float x)
{ return(x*x*x) ; }
/* les ( ) ne sont pas indispensables*/

L’instruction return apparaît comme la dernière de


la définition de notre fonction, mais il est
théoriquement possible de placer plusieurs
instructions return dans une même fonction

Exemple :
float max(float a, float b)
{ if (a>b) return a;
35
else return b; }
Remarques :
– L’imbrication d’une fonction n’est pas autorisée en C, une
fonction ne peut pas être déclarée à l’intérieure d’une autre
fonction. Par contre une fonction peut appeler une autre
fonction
– Si la fonction ne renvoie aucune valeur, on la fait précéder du
mot-clé void
syntaxe : void nom_fonction(arguments)

– S’il n’y a pas d’arguments les parenthèses doivent rester


présentes: Type_retour nom_fonction()

36
Variables locales et globales :
• Une variable connue uniquement dans la
fonction ou dans main() est une variable locale.

• Une variable connue dans tout le programme


est une variable globale(déclarée au début du
programme et en dehors de toute fonction y
compris main).

• Une variable locale à une fonction n’est


accessible que par cette fonction. Cependant,
une variable global est accessible à toutes les
fonctions (y compris le programme principal) 37
APPEL D’UNE FONCTION

Syntaxe
Nom_De_La_Fonction(paramètres d’appel) ;
Exemple
#include<stdio.h>

main()
{int x,y;
Printf(“donner deux entiers”);
Scanf(“%d %d”,&x,&y);

printf("\n la somme de %d et %d est égal à %d ",x,y,somme(x,y)) ;


System(« pause »);
}

int somme(int x, int y)


{
return(x+y) ;
}
38
Le Prototype d’une fonction

• Un prototype de fonction a la syntaxe suivante :

Type Nom_Fonction(type1,type2,…) ;

• Remarques :

– Le prototype est une instruction, il est donc suivi d’un point virgule ;

– Le prototype d’une fonction doit être utilisé, lorsque la définition


d’une fonction est placée après les fonctions qui l’utilisent.

39
Exemples de prototypes :
void affiche_car(char,int) ;
int somme (int,int) ;

Exemple d’utilisation de prototype


#include <stdio.h>

int main()
{int x,y;
printf(" Entrer les valeur à sommer : ") ;
scanf(" %d %d",&x,&y) ;

int somme (int,int) ;


printf (" \n la somme de %d et %d est égal à %d",x,y,somme(x,y)) ;
System(" pause ");
}

int somme(int x,int y)


{return(x+y) ;}

40
Exercice
• Ecrire une fonction itérative permettant de calculer XP avec X réel et
p entier non nul.
• Ecrire une fonction itérative permettant de calculer p!
• En utilisant les deux fonctions précédentes, écrire un programme
principal qui permet de:
• Lire un réel X et un entier p au clavier et affiche XP et p!
• évaluer l’expression suivante :

 n Xi 
S      n!
 i 1 i! 
Passage d’Arguments à une Fonction :
Passage des arguments par valeurs
En C, tous les arguments sont passés par valeur. Les valeurs de ces arguments ne
changent pas après l’appel de la fonction
Exemple : (échange de deux entiers) :
void echange(int a,int b)
{ int k /*valeur intermidiare*/
k=a;
a=b;
b=k;

main()
{ int i=2,j=3 ;
echange(i,j) ;

À l’exécution on a:
Avant l’appel les valeurs sont i=2 et j=3
A la fin de la fonction les valeurs sont 3 et 2
Après l’appel les valeurs sont i=2 et j=3
42
Passage des arguments par adresse :
(Utilisation des pointeurs)
Exemple :
Le même exemple que pour les paramètres passes par valeur mais en utilisant des
adresses :

void echange(int *a,int *b)


{ int k /*valeur intermidiare*/
k=*a;
*a=*b;
*b=k;
}

main()
{ int i=2,j=3 ;
echange(&i,&j) ;
}

À l’exécution on a:
Avant l’appel les valeurs sont i=2 et j=3
A la fin de la fonction les valeurs sont 3 et 2
Après l’appel les valeurs sont 3 et 2
43
Exercice:
1) Ecrire une fonction saisie(int * T, int taille), qui reçoit le tableau
dynamique T et lit au clavier ses éléments.(L’allocation dynamique
se fera dans le programme principal)
2) Ecrire une fonction Affiche(int * T, int taille), qui affiche les éléments
du tableau T.
3) Ecrire une fonction Taille_Tableau(int * T), qui reçoit le tableau
dynamique T et retourne sa taille.
Sachant que taille(T)=sizeof(T)/sizeof(type des eléments de T)

• Ecrire un programme principal de test.

44
Les fonctions récursives

Une fonction récursive est une fonction qui


s’appelle elle-même lors de sa définition

• directement (récursivité simple) ou


• indirectement (récursivité croisée)

13/04/2015 45
Récursivité croisée (indirecte)
L’appel se fait d’une manière fermée entre deux ou plusieurs fonctions

Exemple : une fonction f1 appelle une fonction f2 et vice versa :

int f1(int );

int f2(char c){


Int i,j;
j =f1(i);

}

int f1(int n){


Int k; char c;

K= f2(c);

}

13/04/2015 46
Récursivité directe(récursivité)

Dans ce cas, une fonction comporte dans sa


définition au moins un appel à elle-même.
Exemple:

int f(int n){


if (n==0) return 1 ;
else return n*f(n-1);
}

13/04/2015 47
Il y a deux notions à retenir :

 La fonction s’appelle elle-même : on


recommence avec de nouvelles données
 Il y a un test de fin, dans ce cas (lorsqu’il est
vérifié), il n’y a pas d’appel récursif. Le test de fin
des appels récursifs est souvent indiqué en
début de la fonction.

13/04/2015 48
Exemples sur la récursivité simple
Exemple1 : Factorielle :

N! 1 si N  0

N! N * ( N  1)! si N  0

On réalise une fonction factorielle(N) qui


permet de calculer la factoriel de N.
Cette fonction est récursif et se rappelle
une fois en factorielle(N-1).

13/04/2015 49
int factorielle(int n){
if (n==0) return 1 ;
else return n*factorielle(n-1);
}

n=0 test vérifié arrêt de récursivité on


revient alors en arrière
13/04/2015 50
Remarque:

• Tout usage de la récursivité est un moyen


très simple et très rapide pour effectuer
des taches complexes. Mais consomme
beaucoup d’espaces mémoires pour
sauvegarder les traces des niveaux
d’appels récursives.

13/04/2015 51
Absence du test d’arrêt
Récursivité sans fin
Exemple:

Void F(int x){


X=X+1;
F(X);
}

Main(){
F(1);}

13/04/2015 52
Exercice1
Que fait la procédure suivante?

void afficher(char* s){


If(strlen(s)>0)
Printf(« %c »,*s);
Afficher(s+1)
}
Main(){
Char* ch="abcd" ;
afficher(ch);
}
Ecrire une procédure qui affiche tous les caractères d’une
chaine dans l’ordre inverse

13/04/2015 53
Exercice2
Puissance nième d’un nombre:
Écrire une fonction récursive qui reçoit un
réel x et un entier n et qui permet de
calculer et de retourner xn

13/04/2015 54
Exercice 3 : Tableaux et récursivité

Ecrire les fonctions récursives suivantes :


saisie des N entiers d’un tableau dynamique T.
affichage des éléments d’un tableau dynamique T.
calcul de la somme des N éléments de T
écrire un programme principal de test

55
void lecture(int *t, int i,int n){
if (i<n){ scanf("%d",t+i); lecture(t,i+1,n);}
}

void affiche(int *t,int i, int n){


if(i<n) {printf("%d",*(t+i)); affiche(t,i+1,n);}
}
int main(){
int n=5;
int *t=(int *)malloc(n*sizeof(int));
lecture(t,0,n);
affiche(t,0,n);
system("pause");
}

56
Chapitre3 Les chaînes de caractères
Chaine de caractères statique:
C’est un tableau de caractères:

char chaine[100];
Lecture au clavier du nombre d’éléments
Lecture au clavier de la chaine: gets(chaine);
Affichage à l’écran: puts(chaine);

57
Pointeurs et chaînes de caractères dynamique
Une chaîne de caractères est un tableau de caractères, on peut les
manipuler dynamiquement, se sont des tableaux dynamiques de
caractères

Une chaîne dynamique est un tableau dynamique de caractères.


Syntaxe:
int n ; char*s ;
printf("Donnez la taille de la chaine: n") ;scanf("%d", &n) ;
s = (char *)malloc(n*sizeof(char));

58
Chaînes constantes
Attention, les chaînes de type char * initialisées
avec des " " sont statiques et constantes : on
ne peut pas les modifier.
Exemples:
• char s1[ ] = "SMI"; s1[0] = ’x’; /* OK */
• char *s2 = "SMA" ; s2[0] = ’y’; /* NON! */ erreur d’exécution

59
Lecture et affichage de chaines

Les fonctions gets et puts non formatées:


Lire au clavier La taille N de la chaine:
char *s2 =(char*)malloc(N*sizeof(char));
Puts(" Entrer votre chaine " );
gets(s2);
Puts(s2);
Gets() ajoute automatiquement le caractère
de fin de chaine. Et ignore les délimiteurs
espace. 60
longueur d’une chaîne de caractères

Fonction: Size_t strlen(const char * s);


(déja vue pour les chaines statiques)
Renvoie la longueur de la chaîne de caractères s, sans compter le
caractère nul ’\0’ final.

Exemple:
char* s2="smi";
printf("taille est:%d",strlen(s2));

61
Copie de chaines

char * strcpy (char *dest, const char *src)

Copie la chaîne pointée par src (y compris le ’\0’ final) dans


la chaîne pointée par dest.
La chaine dest doit être assez grande pour la copie.
Renvoie un pointeur sur la chaîne dest.

Exercice:
Écrire une fonction permettant de faire la permutation de deux
chaines passées en arguments
Écrire un programme principal de test

62
Duplication d’une chaine

char * strdup (const char * s)

Renvoie un pointeur sur une nouvelle chaîne de caractères qui


est dupliquée depuis s, ou NULL s’il n’y avait pas assez de mémoire.

Exemple:
char *s1="smi";
char *s2;
s2=strdup(s1);

63
Concaténation de chaines
char * strcat (char *dest, const char *src)

Ajoute la chaîne src à la fin de la chaîne dest en écrasant le


’\0’ à la fin de dest, puis en ajoutant un nouveau ’\0’ final.
Les chaînes ne doivent pas se chevaucher, et dest doit être assez
grande pour le résultat.
Renvoie un pointeur sur dest.
Exemple:
char *des=(char*)malloc(20*sizeof(char));
puts("entrer votre chaine");gets(des);
char *src="bonjour";
strcat(des,src);
puts(des);
64
Comparaison de chaines

int strcasecmp(const char *s1, const char *s2);

Compare les chaînes s1 et s2 et renvoie un entier :


- négatif, si chaine s1 est inférieure à chaine s2 ;
- nul, si chaine s1 est égale à chaine s2 ;
- positif, si chaine s1 est supérieur à chaine s2.

Exemple d’utilisation:
• Lecture d’un tableau dynamique de chaines de caractères
dynamiques
• Tri d’un tableau dynamique de chaines de caractères dynamiques
• Affichage du tableau

65
Chapitre4 Les structures, énumérations
et Unions

Inconvénient des tableaux: regroupe des éléments uniquement de


même type,

Les structures permettent de remédier à cette lacune des tableaux, en


regroupant des variables(appelés champs) de types différents au
sein d’une entité repérée par un seul nom de variable.

66
Déclaration d’une structure

struct nom_de_structure
{ Type1 nom_champ1 ;
Type2 nom_champ2 ;
Type3 nom_champ3 ;
….. ….. ……. ;
TypeN nom_champN ;
};
Les types des champs type1, type2,…, typeN peuvent être différents
ou identiques.
Remarques :
la dernière accolade doit être suivi d’un point virgule
Les champs peuvent être de n’importe quel type hormis le type de la
structure dans laquelle elles se trouvent
67
Exemples :
1) struct date
{
int jour ;
int mois ;
int an ;
};

2) struct Mastructure
{ int Age;
char Nom[12];
float Moyenne;
struct Autre_structure S;
/*en considérant que la structure Autre_Structure est définie*/
};

68
Structure incorrecte
Par contre la structure suivante est incorrecte

struct Mastructure
{ int Age ;
char Age ;
struct Mastructure S ;
};

Il ya deux raisons à cela:


. Le nom de variable Age n’est pas unique
. Le type de donnée struct Mastruture n’est pas autorisé.

69
Déclaration de variables d’une structure
1) Déclaration simultanée de structure et de variables

struct nom_structure
{ Type1 nom_champ1 ;
Type2 nom_champ2 ;
Type3 nom_champ3 ;
….. ….. ……. ;
TypeN nom_champN ;
}var1, var2, …… ;

Exemple :
struct date
{int jour ;
int mois ;
int an ;} départ,arrivée,naissance ; 70
2) Déclaration séparée de structure et de variables
il faut d’abord déclarer la structure puis les variables après.

Syntaxe de déclaration de variable structure en C :


struct nom_struct var1, var2,…………….;
Exemple :
Une fois la structure date déclarée, ont peut écrire les déclarations
suivantes :
struct date départ, arrivée, naissance ;

71
Utilisation de structures
Les structures peuvent être manipulées champ par champ ou dans leur
ensemble.
Utilisation champ par champ
La syntaxe : nom_de _variable.nom_du_champ
Exemple :
En utilisant la déclaration
struct date
{ int jour ;
int mois ;
int an ;
} départ,arrivée,naissance;
Pour accéder aux champs des variables départ, on écrira :
départ.jour =16 ; départ.mois=11 ; départ.an=2012;
72
arrivée.jour=28; arrivée.mois=12; arrivée.an=2012;
Utilisation globale d’une structure

si la structure s1 et s2 sont définie suivant le même modèle, nous


pouvons écrire
s1=s2 ;

Exemple :
Si départ et arrivée sont deux variables de la structure date déjà définie
nous pouvons écrire
départ=arrivée ;

73
Lorsqu’on dispose d’un pointeur sur une structure, l’écriture diffère un peu
en s’écrivant :

Nom_de_variable pointeur->nom_de_champ;
où la flèche est construite avec le signe moins (-) et le signe supérieur (>).
Exemple :
struct date
{ int jour ;
int mois ;
int an ;} ;

struct date *p ;
p est un pointeur sur une variable structure de type struct date
On peut écrire
P->jour=15 ; /*equivalent à (*p).jour=15 ; */

74
Exercice
• Réaliser un modèle de structure pour représenter des nombres
complexes. Chaque nombre complexe est caractérisé par son nom
(caractère), sa partie réelle et sa partie imaginaire (des réels).
• Ecrire les fonctions suivantes :
– Affiche qui reçoit un complexe et qui permet d’afficher un
nombre complexe sous la forme suivante : z=a+b*i, où a et b
représentent respectivement la partie réelle et la partie
imaginaire de z.
• Ecrire l’algorithme du programme principal de test

75
Déclaration de type synonymes : typedef

La déclaration typedef permet de définir des « types synonymes ».


Elle s’applique à tous les types et en particulier aux structures.
Syntaxe : typedef Ancien-type nouveau-type ;

Exemples :
Typedef int entier ;
: signifie que entier est synonyme de int. Dans ce cas :
int n,p ; est équivalent à entier n,p ;

76
Application aux structures:

typedef struct identificateur


{
Type1 nom_champ1 ;
Type2 nom_champ2 ;
Type3 nom_champ3 ;
….. ….. ……. ;
TypeN nom_champN ;
} str1, str2, …… ;

77
Exemples :
Typedef struct temps
{ int champ1 ;
int champ2 ;
int champ3 ;
}date, time ;

Typedef struct temps


{ int champ1 ;
int champ2 ;
int champ3 ;
}*date ;
Date est un type équivalent à struct temps*

78
Tableau statique de structures

1. Soit la structure suivante représentative d’un employé:


Typedef struct employe{
Char* nom;
Char* prenom;
float salaire;
} emp;
2. Ecrire une fonction permettant la saisie d’un tableau
statique T de N employés
3. Une fonction qui affiche le tableau statique T de N
employés
4. Écrire le programme principal de test
5. Refaire l’exercice avec la structure suivante:
Typedef struct employe{
Char nom[100];
Char prenom[100];
float salaire;
} *emp;
79
Exercice
1. Soit la structure suivante représentative d’un employé:
Typedef struct employe{
Char nom[100];
Char prenom[100];
float salaire;
} emp;
2. Ecrire une fonction permettant la saisie d’un employé au clavier
3. Ecrire une fonction permettant la saisie d’un tableau dynamique
de N employés (l’allocation dynamique se fera dans le programme
principal).
4. Une fonction qui affiche un tableau dynamique de N employés
reçu en argument
5. Écrire le programme principal de test

80
Exercice
Refaire l’exercice précédent avec la structure suivante

Typedef struct employe{


Char* nom;
Char* prenom;
float salaire;
} emp;

81
Les énumérations
Objectif: permet de définir quelques nouveaux types.

enum Nom{constante1, constante2,. . . ,constante n} ;


Où constante i, i=1,n sont des constantes entières
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}; //définition de l’énumération boolean
int main () {
enum boolean b1 = TRUE; //declaration
printf("b = %d\n",b1);
return 0;}
82
Remarque:
À chaque fois que le type boolean est précédé
par le mot enum.

D’où:

Typedef enum {FALSE = 0, TRUE = 1} boolean ;

83
On peut modifier le codage par défaut des
valeurs de la liste lors de la déclaration du
type énuméré, par exemple :
typedef enum boolean {FALSE = 10, TRUE = 25} boolean ;

typedef enum couleur{vert, bleu, rouge}couleur;


// Par défault: vert=0, bleu=1, rouge=2, …
main(){
couleur x=rouge;
printf("%d",x);
system("pause");} 84
Les unions
• Une union est une entité représentant un
ensemble de variables de types différents
susceptibles d’occuper alternativement
une même zone mémoire.
• 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 (même
emplacement en mémoire)
85
Déclaration d’une union
union jour {
char lettre;
int numero;
};
int main() {
union jour hier;
hier.lettre = 'J'; //jeudi
printf("hier = %c\n",hier.lettre);
hier.numero = 4;
printf("hier = %c\n",hier.lettre);
system("pause");
} 86
Remarques
• la zone mémoire allouée pour une variable
de type union jour sera de sizeof(int) (2 ou
4 octets).

• On accède aux éléments d’une union avec


le même opérateur de sélection (. ou ->)
que celui utilisé dans les structures

87
Exercices
On considère la structure etudiant suivante :
Typedef struct etudiant{
char nom[100];
char prenom[100];
int code;
float Note[4] ;}etd;
• Ecrire une fonction permettant la saisie des étudiants d’une classe
de N étudiants (la procédure accepte un tableau dynamique de
structures en arguments).
• Ecrire une fonction permettant l’affichage de tous les étudiants de la
classe (la procédure accepte un tableau dynamique de structures
en arguments).
• Une fonction qui calcule et retourne la moyenne d’un étudiant (la
fonction accepte une structure étudiant en argument)
• Utiliser la fonction précédente pour afficher la liste des étudiants
ayant la moyenne supérieure ou égale à 10.
• Ecrire le programme principal de test 88
Chapitre5

La gestion des fichiers en Langage C

• Pourquoi un fichier?
C’est le seul moyen utilisé pour stocker les informations sur
ordinateurs et sauvegarder des résultats nécessitant une
réutilisation ultérieure.

• Définition d’un fichier?


C’est un ensemble d’informations, situé sur une
mémoire de masse (disque dure, disquette, CD
ROM,…).

89
Schéma général de gestion d’un fichier:

• Déclaration
• Ouverture
• Manipulation (Lecture/écriture)
• Fermeture

90
Déclaration d’un fichier
Pour pouvoir utiliser un fichier (l’ouvrir, écrire, lire,…) il faut
déclarer un pointeur sur un objet de type FILE
(le type FILE est une structure définie dans le fichier
<stdio.h>

Syntaxe : FILE *nom_fichier ;

Exemple : FILE *f ;

Cette déclaration ne réserve qu’un emplacement pour un


pointeur. C’est la fonction fopen qui créera effectivement
une telle structure et qui en fournira l’adresse en résultat. 91
Création/Ouverture d’un fichier
Pour travailler sur un fichier, il est nécessaire de l’ouvrir.
La fonction fopen permet de réaliser l’ouverture d’un fichier selon la
syntaxe suivante:
FILE * nom_fichier ;
nom_fichier =fopen(nom_physique_du_fichier , Mode);

nom_physique_du_fichier : chaîne de caractère constante indiquant


le nom du fichier sur le disque.

Mode : chaîne de caractère constante indiquant le mode d’ouverture du


fichier (lecture, écriture/ajout) et (binaire/texte).

92
La fonction fopen retourne l’adresse du fichier ouvert ou un
pointeur NULL si le fichier n’a pas pu être ouvert

(problèmes d’existence de fichiers ou de droits d’accès).

Exemple: f= fopen("c:\\test.txt", "rt");


• Si on n’utilise pas le caractère t dans le mode
d’ouverture. "r" implique fichier texte implicitement.

93
Le type d’ouverture est spécifié à partir d’un mode de base et de compléments

• "r" le fichier est ouvert en lecture. Si le fichier n’existe pas, la fonction ne


le crée pas.
• "w " le fichier est ouvert en écriture. Si le fichier n’existe pas, la fonction
le crée. Si le fichier existe la fonction le vide.
• "a" le fichier est ouvert en ajout. Si le fichier n’existe pas, la fonction le crée.
Les écritures auront lieu à la fin du fichier.
• Le type d’ouverture peut être agrémenté de deux caractères qui sont :
• "b" le fichier est considéré en mode binaire. Il peut donc contenir des
données qui sont transférées sans interprétation par les fonctions de la
bibliothèque.
• "+ " le fichier est ouvert dans le mode complémentaire du mode de base.
• Par exemple s’il est ouvert dans le mode “r+“ cela signifie qu’il est ouvert en
mode lecture et plus, soit lecture et écriture.
• …
• …
94
Fermeture d’un Fichier :

fclose(nom_fichier);

Exemple :
fclose(f) ;

95
Exemple :
Écrire une fonction qui se contente d’afficher
si un fichier de nom lu par le clavier a pu
être ouvert en lecture, ou non.

96
Accès au contenu d’un fichier

Une fois le fichier ouvert, le langage c


permet plusieurs types d’accès à un fichier
• par caractère,
• par ligne,
• par enregistrement,
• par données formatées,

97
Accès par caractère
Ecriture caractère par caractère

int fputc(int, FILE *) ;


écrit dans le fichier associé décrit par le second argument un caractère
spécifié dans le premier argument.
Le premier argument contient le caractère à écrire
Le second contient le descripteur de fichier ouvert ;
Retour : la valeur du caractère écrit mise dans un entier sauf en cas
d’erreur;
Condition d’erreur : en cas d’erreur d’écriture, la fonction retourne
EOF(= -1)

98
Exemple:

Ecrire une fonction qui permet de lire un texte à partir du clavier et


permet de l’écrire caractère par caractère dans un fichier dont le
nom physique est passé en paramètres
Écrire un programme principal de test
Lecture caractère par caractère dans un fichier :

int fgetc(FILE *fich) ; lit un caractère dans le fichier


associé.
fich : le nom du fichier ouvert ;

Elle retourne la valeur du caractère lu et la met dans un


entier.

feof(fich) retourne une valeur différente de zéro, si la


tête de lecture du fichier référencé par <fich> est arrivée
à la fin du fichier; sinon la valeur du résultat est zéro
Tanqu’on n’a pas atteint la fin du fichier: while(!feof(f)){…}
100
Exercice:

• écrire une fonction qui reçoit le nom d’un fichier texte et


permet de lire son contenu et de l’afficher à l’écran
• Écrire un programme principal de test

101
Accès par ligne
• Il est possible de réaliser des opérations
de lecture et d’écriture ligne par ligne à
l’intérieur de fichiers ouverts.

102
Ecriture ligne par ligne
int fputs(const char* , FILE*) ; cette fonction permet d’écrire une
chaîne de caractères référencée par le premier argument dans le
fichier décrit par le second argument.
Arguments :
le premier argument contient l’adresse de la zone mémoire qui contient
les caractères à écrire. Cette zone doit être une chaîne de
caractères (terminée par un caractère nul)
le second argument contient le descripteur de fichier ouvert dans lequel
les caractères seront écrits.
Retour :
Une valeur positive si l’écriture s’est correctement déroulée.
Condition d’erreur :
En cas d’erreur d’écriture, la fonction retourne EOF.
Exemple :
char *s=”ma chaine”;
fputs(s,f) ; 103
Exercice
• Écrire une fonction qui permet d’écrire un
texte ligne par ligne dans un fichier
• Écrire un programme principal de test

104
Lecture ligne par ligne
char * fgets(char*, int , FILE*) ;

Arguments :
adresse de la zone de stockage des caractères de la ligne en mémoire,
nombre de caractères (au maximum la taille de la zone de stockage),
descripteur de fichier ouvert.
Retour :
Adresse reçue en entrée sauf en cas d’erreur ;
Condition d’erreur :
À la rencontre de la fin de fichier, la fonction retourne NULL

105
Exercice
• Écrire une fonction qui permet de lire un
texte ligne par ligne dans un fichier et de
l’afficher à l’écran
• Écrire un programme principal de test

106
Accès par enregistrement
permet de lire et d’écrire des objets structurés dans un fichier.
Pour ce type d’accès, le fichier doit être ouvert en mode binaire.
Les données échangées ne sont pas traitées comme des caractères.
fread(void *Zone, size_t Taille, size_t Nbr, FILE *fp) ;
fwrite(void *Zone, size_t Taille, size_t Nbr, FILE *fp) ;

le premier argument, appelé Zone est l’adresse de l’espace mémoire à


partir duquel l’échange avec le fichier est fait

le deuxième argument, appelé Taille est la taille d’un enregistrement en


nombre d’octets.
le troisième argument, appelé Nbr est le nombre d’enregistrements que
l’on désire échanger.
le dernier argument, appelé fp, est un descripteur de fichier ouvert dans
un mode binaire.
107
Exercice.
Ecrire une fonction qui permet d’écrire un ensemble
d’individus dans un fichier. Un individu sera représenté
par une structure possédant les champs : un nom, un
prénom et un âge (entier).
Ecrire une fonction qui lit les individus contenus dans un
fichier et les affiche à l’écran
Ecrire une fonction qui copie un fichier d’individus dans un
autre fichier
Copie la liste des individus ayant l’âge supérieur à 20 dans
un autre fichier nommée « adulte.dat »
Ecrire un programme principal de test
108
Fonctions de positionnement

La fonction fseek

int fseek(FILE *fp, long int deplacement, int origine) ;


cette fonction permet un accès direct au niveau de l’octet.
Si origine vaut 0 ou SEEK_SET, le déplacement se fera par rapport au
début du fichier.
Si origine vaut 1 ou SEEK_CUR, le déplacement se fera par rapport au
pointeur courant (position courante)
Si origine vaut 2 ou SEEK_END, le déplacement se fera depuis la fin
de fichier
Les valeur SEEK_SET, SEEK_CUR et SEEK_END sont prédéfinies
dans le fichier unistd.h
Si le pointeur n’et bien positioné dans le fichier, la fonction retourne -1,
sinon elle retourne 0.
109
Exemple1 :
fseek(f,20,0) ;char c=fgetc(f) ;
Exemple2 :
fseek(f,sizeof(str)*10,0) ;
str v;
fread(&v,sizeof(str),1,f);

110
Exercice
Considérant l’exercice précédent d’individus

Ecrire une fonction qui permet d’ouvrir le fichier d’individus


et d’afficher directement à l’écran la liste des individus,
le premier, le troisième, le 5ieme …
(Ne pas stocker les individus du fichier dans un tableau)
Accès par données formatées

La fonction d’´ecriture fprintf

syntaxe:
fprintf(f,"format de contrôle",expression-1, ..., expression-n)

où f est le nom logique du fichier. Les spécifications de format utilisées


pour la fonction fprintf sont les mêmes que pour printf.

La fonction de saisie fscanf

fscanf(f,"formats de contrôle",argument-1,...,argument-n)

112
Chapitre6: Complément:

Traitement par le préprocesseur, compilation,


assemblage et édition des liens
compilation séparée, directives du processeur
définition de macros
Compilation conditionnelle

113

Vous aimerez peut-être aussi