ProgrammationII SMI S4 (Aide)
ProgrammationII SMI S4 (Aide)
ProgrammationII SMI S4 (Aide)
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
13/04/2015 4
Définition:
• Un pointeur est une variable caractérisée par un
identificateur et un type,
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.
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
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.
12
Opérations possibles sur les pointeurs(Rappel) :
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
13/04/2015 14
Pointeurs et tableaux
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.
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
20
• Exemple:
int * tab;
tab = (int *) calloc ( 2, sizeof(int) );
tab[0] = 33; tab[1] = 55;
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
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.
Syntaxe
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
32
Structure générale d’un programme en
langage C
Déclaration des bibliothèques à utiliser
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.
34
Exemple :
float cube(float x)
{ return(x*x*x) ; }
/* les ( ) ne sont pas indispensables*/
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)
36
Variables locales et globales :
• Une variable connue uniquement dans la
fonction ou dans main() est une variable locale.
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);
Type Nom_Fonction(type1,type2,…) ;
• Remarques :
– Le prototype est une instruction, il est donc suivi d’un point virgule ;
39
Exemples de prototypes :
void affiche_car(char,int) ;
int somme (int,int) ;
int main()
{int x,y;
printf(" Entrer les valeur à sommer : ") ;
scanf(" %d %d",&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 :
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)
44
Les fonctions récursives
13/04/2015 45
Récursivité croisée (indirecte)
L’appel se fait d’une manière fermée entre deux ou plusieurs fonctions
int f1(int );
13/04/2015 46
Récursivité directe(récursivité)
13/04/2015 47
Il y a deux notions à retenir :
13/04/2015 48
Exemples sur la récursivité simple
Exemple1 : Factorielle :
N! 1 si N 0
N! N * ( N 1)! si N 0
13/04/2015 49
int factorielle(int n){
if (n==0) return 1 ;
else return n*factorielle(n-1);
}
13/04/2015 51
Absence du test d’arrêt
Récursivité sans fin
Exemple:
Main(){
F(1);}
13/04/2015 52
Exercice1
Que fait la procédure suivante?
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é
55
void lecture(int *t, int i,int n){
if (i<n){ scanf("%d",t+i); lecture(t,i+1,n);}
}
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
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
Exemple:
char* s2="smi";
printf("taille est:%d",strlen(s2));
61
Copie de chaines
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
Exemple:
char *s1="smi";
char *s2;
s2=strdup(s1);
63
Concaténation de chaines
char * strcat (char *dest, const char *src)
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
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 ;
};
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.
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
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
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:
77
Exemples :
Typedef struct temps
{ int champ1 ;
int champ2 ;
int champ3 ;
}date, time ;
78
Tableau statique de structures
80
Exercice
Refaire l’exercice précédent avec la structure suivante
81
Les énumérations
Objectif: permet de définir quelques nouveaux types.
D’où:
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 ;
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
• 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.
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>
Exemple : FILE *f ;
92
La fonction fopen retourne l’adresse du fichier ouvert ou un
pointeur NULL si le fichier n’a pas pu être ouvert
93
Le type d’ouverture est spécifié à partir d’un mode de base et de compléments
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
97
Accès par caractère
Ecriture caractère par caractère
98
Exemple:
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) ;
La fonction fseek
110
Exercice
Considérant l’exercice précédent d’individus
syntaxe:
fprintf(f,"format de contrôle",expression-1, ..., expression-n)
fscanf(f,"formats de contrôle",argument-1,...,argument-n)
112
Chapitre6: Complément:
113