Chapitre 5 : Définition de nouveaux types Rappel : le type d une entité x détermine L ensemble des valeurs possibles pour x L ensemble des opérations «élémentaires» possibles sur x Canevas de types: exemple Simple Non simple Homogène int, double, bool, char, énuméré, pointeur tableau Non homogène - classe classe: vu au chap. 12 et sq + références donner un alias à une entité 1
Types simple de base en C++ et valeurs possibles Entier (int) -7, 0, 5 Réel (double) 3.14, 1.0e-6, 1.17e121 Logique ou booléenne (bool) true false [Caractère (char) 'a' 'b' '0' '$' ] 2
Type énuméré Collection de valeurs définies explicitement par le programmeur Exemple: // définition du type couleur enum couleur bleu, blanc, rouge, vert, jaune, noir // déclaration de la variable c de type couleur couleur c; // utilisation de la variable c c = bleu; if (c!= rouge) 3
Format d une définition d un type énuméré Définition: Identificateur de Ce nouveau type Liste d identificateurs donnant l ensemble des constantes de ce type enum nom constante 1, constante 2,, constante n 4
«Traduction» d énuméré en entiers Code correct: (avec la définition du type couleur précédente) int i; couleur c; c=bleu; // c = 0 i=c; Code incorrect: cout << bleu << endl; Valeurs explicites: enum val a=100, b=50, c=100, d, e=-10; // d vaut 101 5
Structure générale d un programme * // inclusion (librairies, fichiers de définition, ) #include // définitions des constantes globales const // définition des nouveaux types // définitions des fonctions //définition de main main() 6 * Voir aussi chapitre sur la découpe en fichiers Nous verrons que typedef permet de définir des nouveaux type non simples
Pointeur Chaque variable C++ est stockée en mémoire à une certaine adresse Pointeur = variable ou constante de type adresse Exemple: int i = 0, Somme=1; int *p = &i; /* = p est une variable «pointeur de variable entière» qui reçoit l adresse de i */ p=&somme; //= p reçoit l adresse de Somme 7 Notation graphique p 0 i ou p 0 i p 0 Somme ou p 0 Somme
Pointeur Déclaration d une variable pointeur vers une variable typ type_pointé *nom _du_pointeur Déclaration d une variable pointeur vers une constante typ const type_pointé *nom _du_pointeur Déclaration d une constante pointeur vers une variable typ type_pointé * const nom_du_pointeur = nom_de_la_variable Déclaration d une constante pointeur vers une constante typ const type_pointé * const nom _du_pointeur = nom_de_la_constante 8
Pointeur Exemple: #include <iostream.h> main() const int ci = 3; const int * pci; // variable pointeur de constante entière int i =3; double x=3.14; int * pi; // variable pointeur de variable entière double * const cpr = &x; // constante pointeur vers le réel x const int * const cpci = &ci; // constante pointeur vers la constante entière ci pi = &i; cout << pi << " " << cpr << endl; pci =&ci; cout << pi << " " << cpr << endl; cin >> i; 9
Pointeur Exemple: #include <iostream.h> main() const int ci = 47; const int * pci; int i =3; double r=3.14; int * pi; double * const cpr = &r; const int * const cpci = &ci; pci cpci pi cpr 47 ci 3 i 3.14 r pi = &i; cout << pi << " " << cpr << endl; pci =&ci; cout << pi << " " << cpr << endl; cin >> i; 10
Pointeur Pointeur NULL : pointe vers rien Permet de tester si un pointeur pointe vers quelque chose ou est à NULL Opérateur de deferencing: *nom_du_pointeur Appliqué à un pointeur, il renvoie l entité pointée Exemple: #include <iostream.h> main() int i,j; int * pi= NULL, pj=&j; cin >> i >> j; if (i > 0) pi = &i; else if (j > 0) pi = &j; if (pi!= NULL) cout << *pi; // imprime la valeur de i ou de j *pj = *pi; // équivalent à j=i 11 pci cpci pi cpr 47 ci 3 i 3.14 r
Référence Permet de déclarer un alias c est-à-dire un nom alternatif pour une variable une constante Exemple: int i = 7; int &ri = i; // le & devant ri signifie que ri est un alias de i Note: Déclarer une référence ne définit pas de nouvelles variables La déclaration d une référence est constante, et doit être initialisé directement Contrairement à C++, la notion de référence et de passage de paramètres par référence n existe pas en C (son précurseur) 12 7 i ri Définissez en C, la fonction swap et montrer comment il faut l appeler
Tableau (array) Type non simple homogène: une variable tableau contient simultanément plusieurs variables de même type. Exemple: V main() int i; /* définition d une variable V tableau de 10 variables int */ int V[10]; // utilisation V[0]=14; V[3]=36; cin >> i; //par exemple i=7 if ((0 <= i) && (i <= 9)) V[i]=45; 13 14 36 45 0 1 2 3 4 5 6 7 8 9
Tableau Meilleure façon de définir un tableau // définition globale du type Vecteur10int typedef int Vecteur10int[10]; // un vecteur est un tableau à une dimension main() //déclaration des variables int i; Vecteur10int V; // utilisation V[0]=14; V[3]=36; cin >> i; if ((0 <= i) && (i <= 9)) V[i]=45; 14
Tableau : vocabulaire Vecteur: tableau à une dimension Matrice: tableau à 2 dimensions (voir plus loin) Composante: un élément du tableau Exemple: typedef int Vecteur10int [10]; Vecteur10int V; V[3] = 5 V est un vecteur à 10 composentes entières 15
Tableau! Ici les [ ] ne sont pas des méta-notations Définition d un vecteur V de N éléments de type Typ Typ V [ N ] Meilleure façon: avec définition d un nouveau type NOM typedef Typ NOM [ N ] NOM V Accès aux éléments du vecteur V[i] avec i dans l intervalle [0.. N-1] 16
Exemple: Le triangle de Pascal Calcul des coefficients de (x+1) n (x+1) 0 = 1 (x+1) 1 = 1.x + 1 (x+1) 2 = 1.x 2 + 2.x + 1 (x+1) 3 = 1.x 3 +3.x 2 + 3.x + 1 17
Le triangle de Pascal Généralisation (x+1) 0 = 0.x 3 + 0.x 2 + 0.x 1 + 1.x 0 (x+1) 1 = 0.x 3 + 0.x 2 + 1.x 1 + 1.x 0 (x+1) 2 = 0.x 3 + 1.x 2 + 2.x 1 + 1.x 0 (x+1) 3 = 1.x 3 + 3.x 2 + 3.x 1 + 1.x 0 18
Le triangle de Pascal Programme : (x+1) 0 = 0.x 3 + 0.x 2 + 0.x 1 + 1.x 0 (x+1) 1 = 0.x 3 + 0.x 2 + 1.x 1 + 1.x 0 (x+1) 2 = 0.x 3 + 1.x 2 + 2.x 1 + 1.x 0 (x+1) 3 = 1.x 3 + 3.x 2 + 3.x 1 + 1.x 0 19
Le triangle de Pascal Programme : (x+1) 0 = 0.x 3 + 0.x 2 + 0.x 1 + 1.x 0 3 2 1 0 (x+1) 1 = 0.x 3 + 0.x 2 + 1.x 1 + 1.x 0 3 2 1 0 (x+1) 2 = 0.x 3 + 1.x 2 + 2.x 1 + 1.x 0 3 2 1 0 (x+1) 3 = 1.x 3 + 3.x 2 + 3.x 1 + 1.x 0 3 2 1 0 V V V V V[j] = V[j]+V[j-1] 20
Le triangle de Pascal Programme : Pour calculer (x+1) 3 avec (x+1) 2 et ne pas «écraser (x+1) 0» les valeurs = 0.x 3 nécessaires + 0.x 2 aux + 0.x 1 calculs + 1.x 0 1. V[3] = V[3]+V[2] 2. V[2] = V[2]+V[1] 3. (x+1) 1 V[1] = V[1]+V[0] = 0.x 3 + 0.x 2 + 1.x 1 + 1.x 0 (x+1) 2 = 0.x 3 + 1.x 2 + 2.x 1 + 1.x 0 3 2 1 0 (x+1) 3 = 1.x 3 + 3.x 2 + 3.x 1 + 1.x 0 3 2 1 0 V V V[j] = V[j]+V[j-1] 21
Le triangle de Pascal: initialisation #include <iostream.h> #include <iomanip.h> const int MAX = 20; typedef int VecteurMAXint [MAX]; main() /* impression des coefficient du triangle de Pascal de degré n */ VecteurMAXint V; int n; //initialise tout le vecteur V[0]=1; for (int i=1; i<max; ++i) V[i]=0; cout << "(x+1) exposant?: " ; cin >> n; 22
Le triangle de Pascal : canevas du traitement //imprime (x+1)^0 cout << V[0] << endl; for (int i=1; i<=n; ++i) //calcul de (x+1)^i for (int j=i; j>0; --j) V[j]=V[j]+V[j-1]; cout << setw(4) << V[j]; cout << setw(4) << V[0] << endl; 23 // imprime (x+1)^n cout << "coefficient de degre " << n << " jusque 0" << endl; for (int i=n; i>=0; --i) cout << V[i]; cout << endl;
Exemple: Le triangle de Pascal //imprime (x-1)^0 cout << setw(4) << V[0] << endl; for (int i=1; i<=n; ++i) //calcul de (x-1)^i for (int j=i; j>0; --j) V[j]=V[j]+V[j-1]; cout << V[j]; cout << V[0] << endl; // imprime (x-1)^n cout << "coefficient de degre " << n << " jusque 0" << endl; for (int i=n; i>=0; --i) cout << setw(4) << V[i]; cout << endl; 24 cin >> n; //lecture «bidon»
Exemple: Le triangle de Pascal setw(4) imprime les nombres sur 4 caractères #include <iostream.h> #include <iomanip.h> //imprime (x+1)^0 cout << setw(4) << V[0] << endl; const int MAX = 20; typedef int VecteurMAXint [MAX]; main() /* impression des coefficient du triangle de Pascal de degré n */ VecteurMAXint V; int n; //initialisation du vecteur V[0]=1; for (int i=1; i<max; ++i) V[i]=0; cout << "(x+1) exposant?: " ; cin >> n; for (int i=1; i<=n; ++i) //calcul de (x+1)^i for (int j=i; j>0; --j) V[j]=V[j]+V[j-1]; cout << setw(4) << V[j]; cout << setw(4) << V[0] << endl; // imprime (x+1)^n cout << "coefficient de degre " << n << " jusque 0" << endl; for (int i=n; i>=0; --i) cout << setw(4) << V[i]; cout << endl; 25 cin >> n; //lecture «bidon»
Opérations sur les tableaux Initialisation lors de la déclaration Exemples: int V[] = 7,7,7,7; int V2[8] = 6,6,6,6; Pas d initialisation en «bloc» en dehors des déclarations Pas d assignation ou de test «en bloc» Exemples: int V[5],W[5]; V=0,0,0,8,7; // interdit W=V; // interdit if (V = = W) // interdit Pas de meilleure notation pour l initialisation Exemple: int V[100] = 0*; // notation inexistante en C++ 26 7 7 7 7 0 1 2 3 6 6 6 6???? 0 1 2 3 4 5 6 7
Définition de tableaux à plusieurs dimensions Définition d une matrice V de NJM éléments de type Typ Typ V [ N ][ M ] Meilleure façon: avec définition d un nouveau type NOM typedef Typ NOM [ N ] [ M ] NOM V Accès aux éléments du tableau V[i][j] avec i dans l intervalle [0.. N-1] j dans l intervalle [0.. M-1] 27
Représentation interne d un tableau // définition globale du type Vecteur4int typedef int Vecteur4int[4] // un vecteur est un tableau à une dimension main() //déclaration des variables Vecteur4int V =1,2,3,4; int *p1 = V; int *p2 = &V[0]; int *p3 = &V[3]; // utilisation *V = 7; // Equivalent à V[0] = 7 *p3 =8; // Equivalent à V[3] = 8 V p1 p2 p3 7 2 3 8 0 1 2 3 28
Allocation dynamique de nouvelles variables main() //définition des variables «statiques» int dimension; int *p1, *p2; cin >> dimension; // exemple dimension vaut 4 p1 = new int[dimension]; //création d une variable «dynamique» p2 = new int[2*dimension]; // idem p1[0]=7; p2[dimension]=8; delete[] p2; //destruction de la variable «dynamique» pointée par p2 p1 p2???? depuis le new 29 jusqu au delete 7??? 0 1 2 3 8??? 0 1 2 3 4 5 6 7 Les variables allouées dynamiquement existent
Gestion de la mémoire lors de l exécution La mémoire est subdivisée en 3 parties: La partie statique contenant principalement le code des fonctions mais aussi les variables statiques dont la durée de vie va jusqu à la fin de l exécution du programme La Pile (Stack) run time qui contient les variables créés automatiquement Le Tas (Heap) run time qui contient les variables créées dynamiquement (par un new) Code (mémoire statique) Stack (variables automatiques) Zone de mémoire non encore utilisée Heap (variables dynamiques) Sommet du stack 30 Limite de la zone utilisée par le heap (il existe une freelist de zone mémoire allouable)
! Problème de perte de mémoire allouée main() int i; cin >>i; while (i >0) int *p1; p1 = new int[i]; //allocation d un vecteur à i éléments entiers //oubli de la désalocation de la mémoire pointée par p1 Overflow quand le heap est rempli (par des zones qui ne sont plus référencées!) (sauf si le run time a un garbagge collector ce qui n est généralement pas le cas) 31