Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Support Cours C++ Allo Dynamique Structure Fichier

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

Support de cours Algo. et Prog.

C++

Parties traitées :

✓ Allocation dynamique de la mémoire


✓ Eléments structurés
✓ Fichiers

Pr. S. Amri API /2èmeAnnée


AU : 2023/2024
Partie 1 : Allocation dynamique de la mémoire

L’allocation réclame des blocs de mémoire dans la zone de la mémoire


appelée le tas (heap, en anglais) (dit aussi mémoire dynamique ou RAM
vive) et la met à la disposition du programme. Cette opération est dite
allocation dynamique (en opposition a l’allocation statique) parce que
l’espace mémoire est réservé lors de l’exécution du programme (run time)
et non lors de la compilation. Par analogie, les entités créées de cette façon
sont dites dynamiques. La durée de vie d’une entité créée dynamiquement
n’est pas limitée à la portée dans laquelle elle a été créée : elle existe depuis
son point de création jusqu’à sa destruction ou jusqu’à la fin du programme.
La libération dynamique Lorsque celle-ci est devenue inutile permet de
détruire l’entité dynamique : la mémoire allouée est libérée et redonnée au
système.
En algorithmique, on suppose que le système possède une place mémoire
sans limite et que l’instruction d’allocation se termine correctement. Dans
les langages de programmation, des mécanismes existent pour savoir si le
système d’exploitation a échoue dans son essai de réservation d’espace
mémoire pour la variable pointée.
Allocation d’un élément
T *p;
p = new T; // allocation
p = new T(valeur); // allocation et initialisation
Explication
Reserve une zone de mémoire de type T et renvoie l’adresse
correspondante (mémorisée ici dans p). Dans le cas où une valeur est
spécifiée, l’élément pointe est initialise lors de son allocation.
C++ : Allocation d’un tableau
T *p;
p = new T[nelems];
Explication
Reserve une zone de mémoire de type T[nelems], initialise chacun des
éléments du tableau dynamique a la valeur nulle du type T c.-a-d. T()
puis renvoie l’adresse correspondante
(0 en cas d’erreur).

1
Liberation dynamique de memoire
Elle ne doit être appliquée qu’a des pointeurs pointant sur une zone
allouée dynamiquement.
C++ : Libération d’un élément
delete p;
Explication
Libère et restitue au système d’exploitation la zone mémoire pointée par
le pointeur p et rend indéterminée la valeur de p.
Liberation d’un tableau
delete[] p;
Explication
Libere la zone mémoire allouée au pointeur p. Ce sont les crochets qui
indiquent au système que l’adresse dans p réfère une structure tabulaire.

Exemple :

int * tableau = new int[ 10] ; // alloue un tableau de 10


delete [] tableau; // ATTENTION : ne pas oublier les crochets []
Libérer un tableau alloué dynamiquement en C++ se fait grâce à
l'opérateur delete [].

delete [] se charge d'appeler le destructeur de chaque objet du tableau.


Notez qu'il n'y a pas besoin de spécifier le nombre d'éléments à libérer.
Cette information est conservée au moment de l'allocation du tableau
avec new [].
Une erreur grave et fréquente est d'oublier les crochets après le mot-
clé delete. Malheureusement cette erreur n'est pas détectée à la
compilation, mais seulement à l'exécution pour les meilleurs compilateurs
lors d'une exécution en mode de débogage. Cette détection se traduit
généralement par un message de corruption de la mémoire.
En effet, appeler delete au lieu de delete [] provoque un comportement
indéfini par la norme, qui se traduit souvent par un plantage pur et simple,
ou par un fonctionnement anormal du programme (mémoire qui semble
être modifiée toute seule). Donc en cas de problème de ce genre, vérifiez
vos delete [] !

2
Tableau à 2 dimensions :

Déclaration et réservation dynamique de la mémoire :

Déclaration d’un tableau d’entiers Tab[10][10]


int N = 10;
int **Tab = new int *[N];
for (int i = 0; i < N; i++) {
Tab[i] = new int[N];

Libération de la mémoire
int** Tab;
int i;

for(i=0; i<10; i++) {


delete [] Tab[i];
}

delete []Tab;

3
Partie 2 : Structures

Une structure permet de créer de nouveaux types qui regroupent plusieurs


variables. D'apparence anodine, cette idée est extrêmement puissante.
Exemple :
struct point {
double x,y;
};
Variable de type structuré On peut maintenant définir des variables de type
point.
Par exemple : point a , b;
a contient 2 réels appelés a.x et a.y.
L'abscisse du point a sera notée a.x. a.x est de type double.
L'ordonnée du point b sera notée b.y, de type double également.
a.x et a.y peuvent être utilisés pour des affectations, des entrées-sorties,
comme toute variable de type double.

Exemple 1 : structure point

#include<iostream>
using namespace std;
struct point
{
double x,y;
};
int main()
{
point a,b,c;
a.x=3.2;
a.y=6.4;

4
cout << "Tapez l'abscisse de b : ";
cin >> b.x;
cout << "Tapez l'ordonnee de b : ";
cin >> b.y;
c.x = (b.x + a.x) / 2;
c.y = (b.y + a.y) / 2;
cout << "Abscisse de c : " << c.x << endl;
cout << "Ordonnee de c : " << c.y << endl;
return 0;
}
Utilisation de typedef

L'utilisation la plus fréquente de typedef concerne les structures et permet


d'éviter l'écriture un peu lourde struct toto.
Prenons l'exemple d'une structure permettant de décrire une courbe
caractérisée par son nom, son nombre de points et les ordonnées de ses
points (les abscisses sont supposées réparties de façon équidistante sur un
intervalle donné). On désire donc créer un type structuré T_COURBE avec
typedef :

#define MAX_POINTS 10
typedef struct
{
char nom[20] ;
char nb_points ;
double y[MAX_POINTS] ;
} T_COURBE ;

Pour créer des variables structurées de ce nouveau type T_COURBE, il suffit


d'écrire :

5
T_COURBE parabole ;
T_COURBE sinus = { "sinusoide", 4, { 1., 0., ‐1., 0. } } ;
T_COURBE* ptr ;

Exemple d’application
1- On peut définir une structure employe qui est défini par un nom, un
prénom et un salaire. Le nom et le prénom comporteront au
maximum 9 caractères utiles.
Code :
struct employe {
char nom[10];
char prenom[10];
double salaire;
};
2- Définir les fonctions saisir_employe et affiche_employe
Code :
void saisir_employe(employe &e) {
cout<<"Tapez le nom : ";
cin>>e.nom;
cout<<"Tapez le prenom : ";
cin>>e.prenom;
cout<<"Tapez le salaire : "; cin>>e.salaire;
}

void affiche_employe(employe e) {
cout<< e.nom <<" "<< e.prenom <<" " << e.salaire << ;
}

3- On veut maintenant gérer une liste d’employé, sachant que cette liste
peut contenir au maximum 100 emplyés

6
Code :
struct liste {
int nb;
employe t[100];
};
4- On s’intéresse maintenant à la définition des fonctions suivantes qui
manipulent la liste de ces employés
Code :

Fonction d’initialisation de la liste :


void init_liste(liste &l) {
l.nb=0;
}
Fonction d’ajouter un employé à la liste :
int ajoute(liste &l, employe e) {
int r;
if (l.nb == liste_nb_max)
r = liste_pleine;
else { r=0;
l.t[l.nb]=e; l.nb++;
}
return r;
}

Fonction d’affichier les employés de la liste :

void affiche(liste l) {
int i;
if(l.nb==0)
cout<<"LISTE VIDE "<< ;

7
for(i=0; i<l.nb; i++)
affiche_employe(l.t[i]);
}
Fonction qui recherche le nom donné d’un employé dans la liste :

void recherche(liste l1, char nom[],liste &l2)


{
int i;
init_liste(l2);
for(i=0; i<l1.nb; i++)
if(strcmp(l1.t[i].nom, nom)==0)
ajoute(l2, l1.t[i]);
}

8
Partie 3 : Fichiers

La règle générale pour créer un fichier est la suivante :


• il faut l'ouvrir en écriture.
• on écrit des données dans le fichier.
• on ferme le fichier.
Pour lire des données écrites dans un fichier :
• on l'ouvre en lecture.
• on lit les données en provenance du fichier.
• on ferme le fichier.

Fichiers textes ou binaires


Il existe 2 types de fichiers :
• les fichiers textes qui sont des fichiers lisibles par un simple éditeur de
texte.
• les fichiers binaires dont les données correspondent en général à une
copie bit à bit du contenu de la RAM. Ils ne sont pas lisibles avec un
éditeur de texte.

cstdio ou fstream
Il existe principalement 2 bibliothèques standard pour écrire des fichiers :
• cstdio qui provient en fait du langage C.
• fstream qui est typiquement C++.

Dans le reste de ce cours, on va se contenter de la


bibliothèque cstdio de langage C.

La fonction FILE * fopen(const char * filepath, char * mode)


Cette fonction permet d'ouvrir un fichier en lecture ou en écriture. Le
paramètre filepath est un tableau de char contenant le chemin du fichier

9
sur lequel on souhaite travailler. Le paramètre mode indique le mode
d'ouverture de filepath : lecture ou écriture, texte ou binaire.
Le mode peut avoir l'une des valeurs suivantes :
• "r" (read) : lecture,
• "w" (write) : écriture, fichier créé ou écrasé s'il existait déjà,
• "a" (append) : écriture en fin de fichier existant (ajout de données).
Sur certaines plateformes (Windows par exemple), on peut y ajouter le type
d'écriture (texte ou binaire), sur les autres (Linux par exemple) le type est
ignoré :
• "b" : mode binaire,
• "t" : mode texte.
Enfin, on peut ajouter le signe "+" afin d'ouvrir le fichier en lecture et
écriture à la fois.
Exemples :
• "r+" : ouverture en lecture et écriture,
• "wb" : ouverture en écriture binaire
La fonction fopen retourne le pointeur NULL si l'ouverture du fichier a
échouée. Dans le cas contraire, elle retourne
un pointeur vers une structure FILE. Ce pointeur servira à écrire ou lire dans
le fichier, ainsi qu'à le fermer.

La fonction fclose(FILE *)

Cette fonction permet de fermer un fichier, qu'il soit ouvert en lecture ou


en écriture. On passe en paramètre à cette fonction le pointeur FILE *
fourni par la fonction fopen(...).

Les fichiers binaires

• La fonction fwrite(const void * buffer, int size,int nb, FILE * f) :


Cette fonction écrit nb élements de size octets (soit nb*size octets) à partir
du pointeur buffer (dans la RAM) vers le fichier f qui doit être ouvert en
écriture. Il s'agit donc d'un transfert d'octets de la RAM dans un fichier.
10
• La fonction fread(const void * buffer, int size,int nb, FILE * f) :
Cette fonction lit nb éléments de size octets (soit nb*size octets) à partir du
fichier f (qui doit être ouvert en lecture) vers le pointeur buffer (dans la
RAM). Il s'agit donc d’un transfert d'octets d'un fichier vers la RAM.

• Exemple : écriture du fichier

#include <iostream>
#include<cstdio>
using namespace std;
int main (void)
{
FILE * f;
int a = 78, i, t1 [6];
double b = 9.87;
char c = 'W', t2 [10];
for(i = 0; i < 6; i++)
t1 [i] = 10000 + i;
strcpy (t2, "AZERTYUIO");
cout << t2 << endl;
f = fopen ("toto.xyz", "wb");
if (f == NULL)
cout << "Impossible d'ouvrir le fichier en écriture !" << endl;
else
{
fwrite (&a,sizeof(int),1,f);
fwrite (&b,sizeof(double),1,f);
fwrite (&c,sizeof(char),1,f);
fwrite (t1,sizeof(int),6,f);
fwrite (t2,sizeof(char),10,f);

11
fclose (f);
}
return 0;
}

Dans ce programme, on ouvre le fichier binaire nommé toto.xyz en écriture.


Si on a réussi à ouvrir le fichier, on y écrit un entier, un double, un char,
puis un tableau de 6 entiers et finalement un tableau de 10 char.
On remarquera que pour écrire un entier il faut écrire &a pour obtenir un
pointeur vers cet entier. Pour copier le tableau t1 on écrire juste t1 car t1
est déjà un pointeur vers le premier élément du tableau.

• Exemple : lecture du fichier

#include <iostream>
#include<cstdio>
using namespace std;
int main (void)
{
FILE * f;
int a, t1 [6], i;
double b;
char c, t2[10];
f = fopen("toto.xyz", "rb");
if (f == NULL)
cout << "Impossible d'ouvrir le fichier en lecture !" << endl;
else
{
fread (&a,sizeof(int),1,f);
fread (&b,sizeof(double),1,f);
fread (&c,sizeof(char),1,f);

12
fread (t1,sizeof(int),6,f);
fread (t2,sizeof(char),10,f);
fclose (f);
}
cout << "a=" << a << endl
<< "b=" << b << endl
<< "c=" << c << endl;
for (i = 0; i < 6; i++)
cout << t1 [i] << endl;
cout << t2 << endl;
return 0;
}

Dans ce programme, on ouvre le fichier binaire nommé toto.xyz en écriture.


Si on a réussi à ouvrir le fichier, on lit un entier, un double un char, puis un
tableau de 6 entiers et finalement un tableau de 10 char.

Les fichiers textes

• la fonction fprintf(FILE *f, const char * format,...)


La fonction fprintf permet d'écrire en mode texte dans un fichier différentes
données. On n'oubliera pas de laisser un espace entre les données pour
pouvoir les relire (ou un passage à la ligne).
Le paramètre format permet de spécifier la nature des données et des
caractéristiques sur leur écriture dans le fichier (le nombre de caractères
par exemple.
Exemples de formats :
"%d" ==> indique un entier
"%lf" ==> indique un double
"%3.7lf" ==> indique un double avec 3 chiffres avant la virgule et 7
après.
"%s" ==> indique une chaine de caractères sans expace.
13
• la fonction fscanf(FILE * f, const char * format,...)
La fonction scanf permet de lire les données à partir d'un fichier texte en
utilisant le format de données indiqué ( qui est identique à printf).
• Exemple : écriture du fichier

#include <iostream>
#include<cstdio>
using namespace std;
int main (void)
{
FILE * f;
int a = 78, t1 [6], i;
double b = 9.87;
char c = 'W', t2 [10];
for (i = 0; i < 6; i++)
t1 [i] = 10000+i;
strcpy (t2, "AZERTYUIO");
f = fopen ("toto.txt", "wt");
if (f == NULL)
cout << "Impossible d'ouvrir le fichier en écriture !" << endl;
else
{
fprintf (f, "%d %lf %c ", a, b, c);
for (i=0;i<6;i++)
fprintf (f, "%d ", t1[i]);
fprintf (f, "%s ", t2);
fclose (f);
}
return 0;
}

14
Dans ce programme, on ouvre le fichier texte nommé toto.txt en écriture.
Si on a réussi à ouvrir le fichier, on y écrit un entier, un double, un char,
puis un tableau de 6 entiers et finalement une chaîne de caractères sans
espace contenu dans un tableau de char.

• Exemple : lecture du fichier

#include <cstdlib>
#include <iostream>
#include<cstdio>
using namespace std;
int main (void)
{
FILE * f;
double b;
int a, t1 [6], i;
char c, t2 [10];
f = fopen ("toto.txt", "rt");
if (f == NULL)
cout << "Impossible d'ouvrir le fichier en lecture !" << endl;
else
{
fscanf (f, "%d %lf %c ", &a, &b, &c);
for (i = 0; i < 6; i++)
fscanf (f, "%d ", &t1 [i]);
fscanf (f, "%s ", t2);
fclose (f);
}
cout << "a=" << a << endl

15
<< "b=" << b << endl
<< "c=" << c << endl;
for (i = 0; i < 6; i++)
cout << t1 [i] << endl;
cout << t2 << endl;
return 0;
}
Dans ce programme, on ouvre le fichier binaire nommé toto.txt en lecture.
Si on a réussi à ouvrir le fichier, on lit un entier, un double, un char, puis
un tableau de 6 entiers et finalement une chaîne de caractères.

Fin de support de cours

NB :
Les TDs et TPs de ces chapitres sont fournis dans un autre document.

16

Vous aimerez peut-être aussi