Développement structuré C++ en BTS IG 1ère année

Gilles Thomassin

Julien Legrand

Ce document est plaçé sous licence gnu FDL


Dédicace

Ce cours est dédié à tous les étudiants qui prennent du plaisir à apprendre et grâce auxquels on a du plaisir à enseigner, il est dédié aussi à la communauté Linux qui partage sans compter et grâce à laquelle on peut disposer d'un environnement de développement performant.

Table des matières

Introduction
Les premiers pas
Prologue
Hello world
Programme C++ minimal
une instruction avec cout
Les variables
Les types de variable
Le nom des variables
Organiser la saisie d'information
Exercices de base
Les structures de contrôle
Les structures alternatives
Les structures répétitives
Quelques compléments sur l'affichage
Les séquences d'échappement
Les affichages formatés
Compléments pour la saisie de données
Traitement des chaines de caractères
Quelques concepts
Exercices sur les chaines de caractères
Les tableaux
Introduction: pourquoi les tableaux
Ce qu'il faut savoir sur les tableaux
Algorithmes de base sur les tableaux
Exercices sur les tableaux
Les sous-programmes
Introduction
Les fonctions
Les procédures
Valeurs par défaut des paramètres
Paramétres par valeur et par référence
Les structures
Introduction aux structures
exemple de stucture
S'en sortir avec les types structurés
Exercices sur les structures
Les fichiers textes
Introduction sur les fichiers
Le principe d'utilisation des fichiers
Algorithmes de base sur les fichiers textes:
Problématique des accés concurrents
Les fichiers en accés direct
Exercices sur les fichiers à accès direct
Les index
L'accés aux bases de données

Liste des tableaux

1. Table de multiplication

Liste des exemples

1. instruction sur plusieurs lignes
2. affichage de caractères, entier, réels, chaînes de caractères
3. les variables
4. invite de saisie
5. structure alternative simple
6. structure alternative simplifiée
7. Utilisation de la fonction pow(x,y)
8. switch
9. Utilisation du break dans le switch
10. Boucle while(prop){}
11. do..while
12. Affichage d'un rectangle de 3 * 4 étoiles.
13.
14. setprecision
15. Affichage du 4ième caractère d'une chaîne
16.
17. fonction sans paramètre
18. Une fonction qui accepte plusieurs paramètres

Loin d'être une référence sur le langage C++. Ce document est constitué d'un ensemble de cours et de TP permettant une initiation à la programmation. Il contient donc une progression sur les principaux concepts à mettre en oeuvre. Chaque partie contient des exercices permettant d'assimiler les concepts. Il s'agit dans ce livre de programmation structurée.

Introduction


Les premiers pas

Prologue

Ce cours constitue une approche par la pratique du langage C++ Ansi.

Il suppose l'utilisation complémentaire d'une référence pure au langage C++.

Vous pourrez trouver cette référence soit sur internet: Cours de C/C++ de Christian Casteyde soit sous forme d'un ouvrage du genre C++ pour les nuls que vous trouverez en librairie ou grande surface.

Hello world

Vous apprendrez ici à préparer votre environnement, éditer le source d'un programme, le compiler et l'exécuter.

Dans votre répertoire personnel, créez un répertoire "projetsC++". Ce répertoire accueillera les programmes que vous allez écrire lors de votre formation. Vous prendrez comme habitude de créer à l'intérieur de ce répertoire un répertoire par projet que vous commencez. Créez donc un répertoire "projetHello" placez vous à l'intérieur, et à l'aide de gvim, tapez le source de ce premier programme en langage C++.

/*Premier programme*/
//Inclusion des bibliothéques
#include <iostream>
using namespace std;
int main()
{
	char touche;
	cout<<"Bienvenue dans la communauté des programmeurs"<<endl;
	cout<<"Tapez un caractère suivi de Entrée pour continuer"<<endl;
	cin>>touche;
}

Ce programme est constitué d'instructions en langage C++. Il s'agit pour l'instant d'un simple fichier texte que l'on va sauver avec l'extension "cpp" hello.cpp.

Il s'agit maintenant de compiler le fichier source "hello.cpp": g++ hello.cpp

Si le fichier source est bien tapé, aucun message d'erreur n'apparait. En tapant la commande ls -l. Vous devriez obtenir la liste des fichiers suivante:

total 20
-rwxr-xr-x  1 gthom gthom 13447 aoû 10 09:10 a.out*
-rw-r--r--  1 gthom gthom    94 aoû 10 09:07 hello.cpp

La compilation a été effectuée. Le compilateur g++ a créé un éxécutable dont le nom est "a.out" dans le répertoire "projetHello".

Pour exécuter ce programme, on va signifier au système que l'on souhaite exécuter le fichier a.out se trouvant dans le répertoire courant. Nous allons donc taper la commande suivante: ./a.out Le programme a.out s'exécute alors.

	[gthom@bigserv projetHello]$ ./a.out
	Bienvenue dans la communauté des développeurs
	Appuyer sur une touche suivie de Entrée pour continuer
	a
	[gthom@bigserv projetHello]$
	

Quelques explications: a.out en tant que programme compilé est constitué d'une suite d'octets correspondant à des ordres que le processeur de l'ordinateur sait exécuter. On parle de langage machine.

Afin d'obtenir un exécutable au nom moins rébarbatif, nous allons voir une option de g++ qui va nous permettre de choisir le nom de l'exécutable généré par le compilateur. g++ -o coucou hello.cpp L'option "-o" suivie du nom de l'exécutable que l'on souhaite obtenir permet d'oublier le fameux "a.out". En lieu et place, g++ crée un exécutable nommé coucou.

Exercices sur la compilation

En vous inspirant du contenu de hello.cpp écrire un programme qui affiche:

	Ce programme est sous licence gpl.
	Vous êtes autorisés à le copier.
	Vous êtes autorisés à le modifier.
	

et demande à l'utilisateur d'appuyer sur une touche pour continuer.

Consignes: Un répertoire exo1 sera créé. Le fichier source s'appellera exo1.cpp. L'exécutable obtenu s'appellera gpl.

Même exercice que précédemment, mais cette fois on demandera à l'utilisateur de taper une touche aprés affichage de chacune des trois phrases.

Consignes: Un répertoire exo2 sera créé. Le fichier source s'appellera exo2.cpp. L'exécutable obtenu s'appellera gpl2.

à retenir:

  • La compilation se fait comme ceci: g++ -o "nom de l'exécutable " "nom du fichier source"
  • L'orsqu'on ne donne pas le nom de l'exécutable, g++ crée un fichier a.out
  • On créera un répertoire pour chacun de nos projets

Programme C++ minimal

Il semble que le plus petit programme C++ qui puisse se compiler soit le suivant:

int main()
{
}
					

Ce programme contient une fonction appelée main mot anglais qui signifie "principal". Il s'agit donc de la partie principale du programme et elle est obligatoire. Le "int" placé devant main signifie que la fonction main renvoie un entier. Toute fonction est suivie de la liste de ses paramètres placés entre parenthéses. Ici la fonction n'a pas d'argument. Il n'y a donc rien entre les parenthéses. Suivent enfin les instructions de la fonction main placées entre accolades. Nous remarquons que dans ce programme il n'y a pas d'instruction.

Editez, compilez et exécutez ce programme.

à retenir:

  • Tout programme C++ doit contenir une fonction appelée main
  • La fonction main doit être du type entier.
  • Les instructions d'une fonction sont écrites entre deux accolades.
  • Les paramètres d'une fonction sont écrits entre parenthèses.
  • Les parenthèses doivent exister même si la fonction ne prend pas de paramètre

une instruction avec cout

"cout" est le "petit nom" du périphérique de sortie standard de l'ordinateur: l'écran.

Lorsqu'un programme doit afficher quelque chose, le meilleur endroit où il peut le faire est l'écran.

L'information part de l'ordinateur et va sur l'écran: ecran <---info-- ordinateur

L'instruction permettant d'afficher le message "bonjour" est comme on l'a déjà vu:

	cout<<"bonjour";
					

Notez bien le sens des chevrons qui permet à la chaîne de caractères "bonjour" d'aller sur l'écran.

Toute instruction se termine par un ";" en anglais: "semicolon". Oublier le ";" provoquera l'affichage suivant lors de la compilation:

semicolon missing on line xxx

. Le xxx est le numéro de la ligne suivant l'instruction non correctement délimitée.

Comme vous pouvez le voir dans l'exemple ci-dessous, une instruction peut tenir sur plusieurs lignes.

Exemple 1. instruction sur plusieurs lignes

	cout
	<<
	"bonjour"
	<<
	endl
	;
						


C'est là une pratique que l'on évitera mais qui justifie la présence du ";" marqueur de fin d'instruction.

On peut afficher à l'écran: un caractère, un entier, un réel, une chaine de caractères.

Exemple 2. affichage de caractères, entier, réels, chaînes de caractères

	cout<<"Le nombre d'élèves"
	<<endl<<"est de"<<4<<endl
	<<"la moyenne est de "<<10.25<<endl;
		 


Chaque information à afficher est à précéder du <<

Attention

  • Les chaînes de caractères (ensemble de plusieurs caractères) sont notées entre " doubles-quotes.
  • Un caractère est noté entre simples quotes '
  • Les numériques sont notés sans quotes

Les variables

Les informations saisies par les utilisateurs du programme ou les résultats intermédiaires obtenus lors de calculs doivent nécessairement être stockées quelque part dans la mémoire de l'ordinateur. Ces informations sont mémorisées dans des variables. Chaque variable a un un nom et un type, elles doit de plus être déclarée.

Voici ci-dessous un exemple de programme qui déclare et utilise des variables.

Exemple 3. les variables

//Inclusion des bibliothéques nécessaires
#include <iostream>//bibliothéque des flux d'entrée/sortie
using namespace std;//utilisation de l'espace de nom "std"
	 int main()
	 {
		//déclaration des variables:
		double taille;
		double poids;
		double densite;

		//affichage du message d'accueil
		cout<<"Bienvenue sur le calculateur de densité"<<endl;
		//saisie du poids
		cout<<"Votre poids : ";
		cin>>poids;
		//saisie de la taille
		cout<<"Votre taille : ";
		cin>>taille;
		//calcul de la densité
		densite=poids/taille;
		cout<<"Votre de densité est de "<<densite<<endl;
	 }
 


Dans l'exemple ci-dessus, 3 variables de type double sont déclarées.Ces trois variables ont pour nom respectivement:

  • taille
  • poids
  • densite

Le type double correspond au type réel (nombre à virgule) courant.

La forme générale d'une déclaration est: <type> <nom>;

Si l'on a plusieurs variables du même type, on peut les déclarer sur une même ligne:

string nom, prenom;

Les types de variable

On considèrera pour l'instant qu'il existe 5 types de variables:

  • double pour les nombres réels ex: 145.26
  • long pour les nombres entiers ex: 65210
  • char pour un caractère ex: 's'
  • string pour les chaînes de caractères ex: "Bonjour"
  • bool pour les booléens ex: false ou true

Exercice: Indiquez pour chacune des informations suivantes le type informatique qui correspond:

  • couleur:
  • altitude
  • pi
  • taux de réduction
  • smic horaire
  • nom
  • prénom
  • âge
  • nombre d'enfants

Le nom des variables

Le nom de la variable doit être significatif du contenu de celle-ci les variables appelées i, j, x, ou y sont à proscrire définitivement. Le nom de variable ne comporte que des lettres en minuscule. Il est toutefois possible lors de noms de variable composés de changer de casse pour marquer le début d'un nouveau mot. Voici quelques exemples de noms de variable composés: nomProduit prixUnitaireProduit. Il est éventuellement possible aussi d'utiliser les chiffres mais jamais en première position. On peut donc trouver les noms de variable suivant: taux1, taux2. On ne mettra donc dans les noms de variable ni espaces ni caractères accentués.

Organiser la saisie d'information

La saisie d'information suppose l'affichage préalable d'un message qui informe l'utilisateur sur la nature de ce qu'il doit taper.

Exemple 4. invite de saisie

	cout<<"Votre nom :";


Tout comme cout désigne l'écran cin désigne le périphérique d'entrée standard: le clavier.

cin>>nomClient;

L'information part du clavier et va dans la variable: cin ---info--> variable.

Voici donc le programme complet:

//Inclusion des bibliothéques
#include <iostream>;
using namespace std;

	int main()
	{
		cout<<"Votre nom :";
		cin>>nomClient;
		cout<<endl<<"Bonjour "<<nomClient;
	}	
	

Exercices de base

exo1: Ecrire le programme convertisseur qui demande à un utilisateur une somme en francs et lui affiche l'équivalent en euros

exo2: Ecrire le programme bienvenue qui conformément à l'écran ci-dessous demande à l'utilisateur son nom et son prénom et lui affiche un message d'accueil.

	Tapez votre prénom : Louis
	Tapez votre nom : Dupond
	Bonjour Louis Dupond

exo3: Ecrire le programme piscine qui demande à l'utilisateur la largeur, la longueur et la profondeur de sa piscine et lui calcule son volume en mètres cubes (le fond de la piscine est plat).

exo4: Ecrire le programme piscine qui demande à l'utilisateur la largeur, la longueur et les profondeurs de sa piscine et lui calcule son volume en mètres cubes. La piscine ayant un fond en pente et la profondeur varie linéairement dans le sens de la longueur.

exo5: Réaliser une nouvelle version du programme ci-dessus permettant de calculer le cout de remplissage de la piscine.

exo6: Une entreprise de préfabriqués coule des dalles de béton rectangulaires. Afin de lever ces plaques, un anneau en fer est introduit dans le béton encore frais. Afin qu'au levage, la pièce ne bascule pas, il faut placer le crochet à un endroit précis de la dalle. Ecrire un programme qui renvoie cette position à partir des caractéristiques de la dalle rentrées par l'utilisateur.

exo7: Ecrire le programme qui convertit en heures, minutes, secondes une durée exprimée en seconde rentrée par l'utilisateur. Indications:

  • si la duree est de 7274s 7274=2*3600+1*60+14 la durée est donc de 2 heures 1 minute et 14 secondes.
  • En utilisant la division euclidienne, 7274 divisé par 3600 donne 2 et il reste 74. Pour obtenir le reste on utilise l'opérateur %. L'instruction correspondante est donc:
    reste=7274 % 3600;

exo8: Ecrire un programme qui demande à l'utilisateur l'heure de départ d'un train, la durée du voyage et renvoie l'heure d'arrivée. L'heure de départ ainsi que celle d'arrivée et la durèe du voyage seront exprimées en heures, minutes, secondes.

Les structures de contrôle

Les instructions sont par défaut exécutées en séquence (les unes à la suite des autres).

Mais il est heureusement possible de contrôler l'exécution des instructions de façon plus fine. Par exemple, on peut n'effectuer une instruction que sous certaine condition. Ou alors on peut répéter un groupe d'instruction un certain nombre de fois. Dans le premier cas on parlera de structure alternative et dans le second de structure répétitive.

Les structures alternatives

Les structures alternatives permettent l'exécution conditionnelle d'un bloc de code.

Les structures alternatives simples

Structure alternative siAlorsSinonFsi

Syntaxe:

if(prop)
{
	bloc1...
}
else
{
	bloc2...
}
						

C'est la structure de test générale.

Elle se lit comme ceci: si la proposition logique "prop" est vérifiée alors exécuter les instructions contenues dans le bloc1 sinon exécuter les instructions du bloc2.

Exemple 5. structure alternative simple

	if (nom=="Dupond")
	{ 
       		cout<<"Bonjour patron"<<endl; 
		cout<<"Bonne journée";
	} 
	else
	{
	  cout<<"Bonjour simple employé"<<endl;
	}
							


Structure alternative siAlorsFinSi

Il existe aussi une structure alternative simplifiée similaire à la structure alternative simple mais ne disposant pas du bloc sinon:

Exemple 6. structure alternative simplifiée

plusGrand=nombre1;
if (nombre2>nombre1)
{ 
	plusGrand= nombre2;
}
cout<<"Le plus grand est : "<<plusGrand<<endl;
							


Exercices sur les stuctures alternatives siAlorsFinSI et siAlorsSinonFinSI

exo1: Ecrire un programme qui demande à l'utilisateur deux noms et les lui affiche dans l'ordre alphabétique.

exo2: Ecrire un programme qui demande à l'utilisateur deux réels, en affiche la somme, la moyenne, trouve le minimum et le maximum.

exo3: Ecrire un programme qui demande à l'utilisateur de saisir 4 réels et lui affiche le plus petit des quatres.

exo4: Ecrire un programme qui demande à l'utilisateur 3 réels et les lui affiche dans l'ordre croissant.

exo5: Calcul du montant d'une facture. Sont demandés: libellé du produit , quantité à facturer, prix unitaire hors taxe. Seront affichés: le montant total ht, le montant total ttc auquel seront ajoutés les frais de port. Les frais de port correspondent au montant forfaitaire de 100 euros. Les frais de port ne sont pas facturé lorsque le montant ht de la facture est supérieur à 1000 euros. Une réduction de 10% du montant ht de la facture est appliqué entre 500 et 1000 euros. Le taux de TVA appliqué sera 20%.

exo6: Ecrire un programme qui résoud une équation du second degré du type 0=ax²+bx+c, a,b et c seront rentrés par l'utilisateur. Indication: la fonction pow(x,y) renvoie l'élévation à la puissance y du nombre x.

Exemple 7. Utilisation de la fonction pow(x,y)

	double res=pow(nb,0.5);
	cout<<endl<<"La racine de "<<nb<< " est  "<<res<<endl; 


exo7: Le nuancier: écrire un programme qui demande à l'utilisateur de taper deux couleurs et lui affiche le nom de la couleur composée. Les couleurs pouvant être tapées sont à prendre parmi l'ensemble suivant:(rouge,jaune,bleu).

exo8: Ecrire le programme qui détermine si une année saisie par l'utilisateur est une année bissextile.Année bissextile divible par 4 et pas par 100 ou par 400.

exo9: Ecrire le programme qui demande une note et affiche la mention correspondante ou un message si la note saisie n'est pas correcte.

Exo 10: Ecrire le programme qui affiche le nombre de jours que comporte le mois saisi par l'utilisateur dans l'année saisie par l'utilisateur.

Structure alternative multiple

C++ dispose aussi d'une structure permettant de comparer le résultat d'une expression à plusieurs valeurs et d'associer des instructions pour chacune de ces valeurs :

...
switch (variable)
{
	case...
	case... 
	default...
}
...
					

Voici un exemple de code utilisant la structure alternative multiple.

Exemple 8. switch

						
	long	nombre;
	cout<<"Tapez un nombre compris entre 1 et 5 : ";
	cin>>nombre;
	switch(nombre) 
	{
		case 1:
			{
				cout<<"vous avez tapé 1";
				break;
			}
		case 2:
			{ 
				cout<<"vous avez tapé 2";
				break;
			}
		case 3:
			{
				cout<<"vous avez tapé 3";
				break;
			}
		case 4:
			{
				cout<<"vous avez tapé 4";
				break;
			}
		default:
			cout<<"Le nombre tapé est sans doute = à 5;
	}

					


La variable examinée ne peut être qu'un entier ou un caractère. l'instruction break permet de sortir du switch, si on l'oublie, toutes les instructions suivantes sont exécutées même si le cas ne correspond plus à la valeur de la variable. Voici un autre exemple exploitant cette particularité :

Exemple 9. Utilisation du break dans le switch

						
	char lettre;
	cout<<"Tapez une lettre entre a et z : "
	switch(lettre)
	{
		case 'a':
		case 'e':
		case 'i':
		case 'o':
		case 'u':
		{
			cout<<"c'est une voyelle"<<<<endl;
			break;
		}
		default:
		cout<<"c'est une consonne"<<endl;
	}
	
					


A partir du moment où l'on rentre dans un cas les instructions sont exécutées jusqu'au prochain break. On ne rentrera dans la section default que si aucun des cas précédents n'a été vérifié.

Exercice n°7: La voyelle 'y' n'a pas été prise en compte rectifiez le programme en conséquence.

Les structures répétitives

Choix du type de boucle

Les boucles servent à répéter un certain nombre de fois une instruction ou un bloc d'instructions.

On distingue 3 types de boucles différents que l'on choisi en fonction de la situation.

	Si on connait le nombre de fois où l'on va exécuter le bloc d'instruction, 
		on utilisera la boucle for(...;....;...){....}
	Sinon
		Si le nombre de répétition appartient à [0..n] 
			on utilisera la boucle while(...) {...} //on peut ne pas passer ds la boucle.
		Sinon
			On utilisera la boucle do {...} while(...); 
		FINSI
	FINSI
						

Boucle 0,N

syntaxe: while(proposition logique){bloc d'instructions};

Utilisation: Cette boucle est à utiliser lorsqu'on ne connait pas le nombre de passage dans la boucle, et qu'on peut ne pas y passer du tout.

Exemple 10. Boucle while(prop){}

long dividande, diviseur;
cout<<"Ce programme affiche le résultat de la division entière d'un dividande par un diviseur";
cout<<"Tapez le dividande :";
cin>>dividande;
cout<<"Tapez le diviseur";
cin<<diviseur;
long resultat, intermediaire;
intermediaire=dividande;
resultat=0;
while(intermediaire>=diviseur)
{
  intermediaire=intermediaire-diviseur;
  resultat=resultat+1;
}
cout<<"Le résultat est : "<<resultat;
						


Principe: Tant qu'il est possible d'enlever le diviseur au dividande, on le fait. Résultat compte le nombre de soustractions que l'on a pû effectuer. Tant que intermediaire est plus grand que le diviseur, on enlève à intermédiaire diviseur et on ajoute 1 à résultat.

Boucle 1,N

syntaxe: do {blocd'instructions}while(proposition logique);

Utilisation: Cette boucle est à utiliser lorsqu'on ne connait pas le nombre de passage dans la boucle, et qu'on sait qu'on doit y passer au moins une fois.

Exemple 11. do..while

Obtention du nb de lancers de dés à effectuer pour obtenir le chiffre 3.
								
#include <time.h>
#include <iostream>
using namespace std;
int main()
{	
	//déclarations des variables:
	long nombreDeLancers , nombreAleatoire , nombreTire;				
	// initialisation du générateur de nombres aléatoires
	srand((unsigned)time(NULL));
	// initialisation à zero du nb de lancés
	nombreDeLancers=0;
	do
	{
		nombreDeLancers++; //incrémentation du nb de lancé de dé
		nombreAleatoire=rand();
		nombreTire=nombreAleatoire%6 +1;//tirage entre [1..6]
	}
	while (nombreTire!=3); // tant que le nb tiré est différent de 3
	cout<<"Pour tirer le chiffre 3 il a fallut : "<<nombreDeLancers<<" lancers du dé"<<endl;
}

		
							


Boucle X passages

syntaxe:for(...;...;...){...}

Utilisation: la boucle for est à utiliser lorsque l'on connait à l'entrée dans la boucle, le nombre de passage à effectuer dans la boucle.

Exemple 12.  Affichage d'un rectangle de 3 * 4 étoiles.

		for(ligne=1;ligne<=3;ligne++)
		{
			for(col=1;col<=4;col++)
			{
				cout<<'*';
			}
			cout<<endl;
			
		}
							


Exercices sur les boucles

Exercice : Affichez les 10 premiers entiers.

Exercice : Afficher les 10 premiers entiers pairs.

Exercice : affichez un rectangle d'étoiles de 10 lignes de 7 étoiles

Exercice: Affichez ceci:

							*
							**
							***
							****
							*****
							******
							*******
							********
							*********						
						

Exercice: Affichez un cône identique à celui-ci:

					    	            *
							   ***
							  *****
							 *******
							*********						
						

Même exercice que précédemment sauf que le nombre d'étoiles impair de la base sera saisi par l'utilisateur.

Idem mais on contrôlera que le nombre d'étoiles de la base appartient à l'intervalle [1..79] et est impaire.

Reprendre l'exercice précédent en ajoutant un tronc de 10*5 étoiles.

					    	            *
							   ***
							  *****
							 *******
						        *********					
						       ***********
						      *************
						     ***************
						    *****************
						   *******************
						          *****	 
						          *****	 
						          *****	 
						          *****	 
						          *****	 
						          *****	 
						          *****	 
						          *****	 
						          *****	 
							  *****	 
						  

Exercice : Faites un programme qui affiche la table de multiplication de 1 à 10 d'un nombre N quelconque saisi par l'utilisateur.

Tableau 1. Table de multiplication

*12345678910
4481216202428323640


Exercices sur les boucles

exo : Faites un programme qui calcule la moyenne de n notes. Le nombre de notes est demandé au préalable à l'utilisateur.

exo : Faites un programme qui calcule la moyenne de n notes. Le nombre de notes n'est pas demandé au préalable à l'utilisateur. La saisie des notes s'arrête lorsque l'utilisateur saisi une note égale à 99.

exo : Faites un programme qui converti un nombre binaire en décimal.

exo : Faites un programme qui affiche le contenu de la table ASCII (à partir du caractère n°32).

Quelques compléments sur l'affichage

Nous verrons ici comment parfaire ou soigner l'affichage.

Les séquences d'échappement

Problématique: le délimiteur de chaîne est comme on le sait maintenant le caractère ".Comment alors faire afficher une double quote? puisque le code suivant provoque une erreur à la compilation.

cout<<"Bonjour "Patron"";
			

Solution: Pour indiquer qu'on veut faire afficher le caractère " il suffit de l'indiquer mais précédé du caractère \. Ainsi le code suivant est correct:

				cout<<"Bonjour \"Patron\"";
			

Liste des séquences d'échappement les plus utiles:

  • \0: caractère de fin de chaîne à zero terminal
  • \n: nouvelle ligne
  • \r: retour chariot
  • \t: tabulation horizontale
  • \\: le caractère \

Les affichages formatés

Il existe un certain nombre de fonctionnalités permettant de soigner les affichages ces fonctionnalités sont inclues dans la bibliothéque de fonction <iomanip> que l'on pensera à inclure.

Sélection de la largeur de champ: Il est possible de choisir sur quel nombre de caractère s'effectuera un affichage grâce à setw(largeur), lorsque l'on fait appel à setw les affichages suivants seront réalisés avec la largeur choisie. Les données affichées seront complétées par le caractère de remplissage courant (par défaut l'espace). Exemple:

cout<<setw(20)<<"chaussette"<<setw(5)<<12<<3<<36<<endl;
cout<<setw(20)<<"bas"<<setw(5)<<23<<10<<230<<endl;
			

Cet exemple produit l'affichage suivant:

chaussette          12   3    36
bas                 23   10   230
			

Il est possible de choisir le caractère de remplissage grâce à setfill('caractère').

Exemple 13. 

cout<<setfill('*')<<setw(20)<<"Nom"<<setw(5)<<"Pu"<<"Qte"<<"Total"<<endl;
				


Le caractère de remplissage choisi est utilisé jusqu'à ce qu'il soit modifié par le prochain setfill.

Alignement de la donnée dans le champ: Dans la largeur spécifiée par le setw, la donnée peut être affichée à gauche(par défaut) ou à droite.Il suffit de l'indiquer en envoyant left ou right avant l'affichage. On a pour habitude d'afficher les chaînes de carctères à gauche et les données numériques à droite.Comme dans l'exemple suivant:

cout<<setw(20)<<left<<"chaussette"<<setw(5)<<right<<12<<3<<36<<endl;
cout<<setw(20)<<left<<"bas"<<setw(5)<<right<<23<<10<<230<<endl;
			

Attention

Il n'existe pas de possibilité de centrer la donnée dans la largeur réservée.

Formatage des réels: On peut choisir le nombre de chiffres d'un réel grâce à la commande setprecision(precision) la precision est en fait le nombre de chiffres total du réel. Le réel correspondant est alors arrondi à la précision demandée.

Exemple 14. setprecision

cout<<setprecision(4)<<3.14547;//produit l'affichage suivant:3.145
cout<<setprecision(5)<<3.14547;//produit l'affichage suivant:3.1455
				


Compléments pour la saisie de données

Le séparateur de données saisie est le caractère espace par défaut.

Nous allons voir que ce comportement n'est pas sans conséquence.

Aprés l'avoir complété, compilez et exécutez le programme ci-dessous:

cout<<"Tapez le titre de votre film préféré: ";
cin>>titreDuFilm;
cout<<"Tapez le nom de l'acteur principal: ";
cin>>nomActeur;
cout<<"Tapez l'année de sortie du film: ";
cin>>anneeSortieFilm;
cout<<"Nous avons enregistré que votre acteur préféré était "<<nomActeur<<" dans "<<titreDuFilm<<"sorti en "<<anneeSortieFilm<<endl;
		

Qu'observe-t-on si l'on rentre les données suivante "le jour le plus long",?

Le programme ne demande pas la saisie de l'acteur principal ni de l'année. La zone nom du film contient "le" la zone acteur contient "jour" et la zone année contient "le".

le cin>> ne convient donc pas à la saisie de chaînes de caractères pouvant contenir des espaces.

Solution: pour faire saisir une variable de type chaîne pouvant contenir des carctères, on utilisera la procédure suivante: getline(cin,nomDeLaVariable);

Notre programme devient donc:

cout<<"Tapez le titre de votre film préféré: ";
getline(cin,titreDuFilm);
cout<<"Tapez le nom de l'acteur principal: ";
getline(cin,nomActeur);
cout<<"Tapez l'année de sortie du film: ";
cin>>anneeSortieFilm;
cout<<"Nous avons enregistré que votre acteur préféré était "<<nomActeur<<" dans "<<titreDuFilm<<"sorti en "<<anneeSortieFilm<<endl;
		

Traitement des chaines de caractères

Quelques concepts

Une chaine est un vecteur de caractères: tableau de dimension 1.

On peut accéder individuellement à chaque caractère de la chaîne en donnant son indice (n° du caractère dans la chaîne

Le premier caractère a le n°0, le deuxième le n°1 etc...

Exemple 15. Affichage du 4ième caractère d'une chaîne

				string nom="Dupond";
				cout<<"Voici le 4ième caractère de la chaîne nom: "<<nom[3];//affiche "o"				
			

Obtention de la longueur d'une chaîne: int nomDelaVariableString.length()

Corrolaire: le dernier caractère a donc pour indice: nomDelaVariableString.length()-1

Exercices sur les chaines de caractères

exo: Ecrire un programme qui demande à l'utilisateur de saisir une chaîne de caractère et la lui réaffiche avec un seul caractère par ligne.

exo: Ecrire un programme qui demande à l'utilisateur de saisir une chaîne de caractère et la lui réaffiche du dernier au premier caractère.

exo : Faites un programme qui convertit un nombre décimal saisi dans une chaine de caractères en hexadécimal.

exo : Faites un programme qui convertit un nombre binaire saisi dans une chaine en nombre décimal.

exo : Faites un programme qui simule le jeu du pendu. Un mot est saisi au départ par un utilisateur, puis caché, et un autre utilisateur doit proposer des lettres. A chaque fois qu'une lettre est proposée, soit elle est placée dans le mot soit elle est placée dans la liste des lettres déjà jouées. A chaque fois, il faut afficher le mot tel qu'il a été trouvé, la liste des lettres déjà jouées et le nombre d'erreurs avant d'avoir perdu.

Les tableaux

Introduction: pourquoi les tableaux

Une variable sert à mémoriser une valeur. Ainsi, si l'on doit mémoriser une note, on crée une variable "note". Mais que se passe-t-il si l'on doit mémoriser 2 notes ? On crée deux variables: note1 et note2. Imaginons maintenant que l'on ait 45 notes à mémoriser, il serait fastidieux de créer 45 variables. La solution est de créer un tableau de 45 notes. Il y a plusieurs types de tableau: les vieux tableaux statiques dont la taille est fixée àla déclaration du tableau, et les jeunes tableaux dynamiques dont la taille varie au fur et à mesure qu'on les rempli. Nous nous intéresserons tout d'abord aux vieux tableaux statiques.

Ce qu'il faut savoir sur les tableaux

Un tableau est une structure de donnée permettant de stocker un ensemble de valeurs du même type. Chaque case du tableau est une variable. Un tableau a une dimension (1,2,3).

Un tableau a un nom, un type: celui des valeurs qu'il va contenir et un nombre de case. Ce nombre de case est fixé lors de la déclaration du tableau.

Déclaration d'un tableau de dimension 1:

				long tabNotes[45]; //déclaration du tableau tabNotes tableau de 45 entiers				
			

Le tableau s'appelle tabNotes, c'est un tableau d'entiers, il comporte 45 cases et contient donc d'ores et déjà 45 valeurs indéterminées (?).

Les cases du tableau ont un indice: il s'agit de leur position dans le tableau, la première case du tableau a l'indice 0 tandis que la dernière a l'indice 44.

Chaque case se comporte exactement comme une variable, toutes les opérations exercés sur les variables sont donc reproductibles sur les cases d'un tableau.

Exemple 16. 

					//affectation
					tabNotes[2]=20;
					//utilisation dans des opérations:
					somme=somme+tabNotes[3];
					//accueillir une saisie
					cout<<"Veuillez saisir la note n°10: ";
					cin>>tabNotes[9];
				


Algorithmes de base sur les tableaux

Affichage de ttes les cases d'un tableau

Saisie de toutes les cases d'un tableau

Recherche d'une valeur dans un tableau et affichage de son indice

Tri d'un tableau

Correspondances entre tableaux par indice

Tableaux surdimensionnés gestion du nombre de cases remplies

Suppression d'un element t dans un tableau

Insertion dans un tableau trié

Exercices sur les tableaux

Exo1: Ecrire un programme qui fait saisir 30 notes dans un tableau puis affiche le contenu du tableau

Exo2: Reprendre l'exercice précédent et ajouter une partie qui trouve la note maximale contenue dans le tableau et l'indice de la première case contenant cette note.

Exo 3: En partant de l'exercice n°1, afficher le nb de note au dessus de la moyenne et le nombre de note en dessous de la moyenne.

Chaque note correspond à un élève dont on trouvera le nom et le prénom dans le tableau tabEleves. La note à l'indice 3 dans le tableau tabNotes correspond à l'élève dont le nom se trouve dans le tableau tabEleves à l'indice 3. Compléter le programme obtenu à l'exo2 pour afficher le nom des élèves ayant obtenu la meilleure note.

Exo4: Affichage du libellé d'un mois dont le n° est saisi par l'utilisateur. On se servira d'un tableau qui contient les libellés des mois.

Exo5 : Reprendre l'algorithme qui donne le nombre de jour d'un mois en se servant d'un tableau de 12 cases qui contient le nb de jour de chacun des 12 mois de l'année choisie par l'utilisateur.

Exo6: Dans la suite des exercices, les tableaux seront surdimensionnés et on gérera dans une variable à part le nb de case remplies. Ecrire un programme qui permet l'ajout d'un élève et de sa note, permet l'affichage des élèves et de leurs notes, permet l'affichage de la moyenne générale, permet la suppression d'un élève et de sa note. On proposera donc dans un menu les actions réalisables par l'utilisateur et en fonction de l'action choisie on réalisera le code en conséquence jusqu'à ce que l'utilisateur demande la fin du programme.

exo : Faites un programme qui fait saisir et stocke les tirages du loto, puis qui classe les numéros en fonction de leur fréquence de tirage.

Les sous-programmes

Introduction

Il est possible de structurer les programmes en sous-programmes, et c'est pour cela que l'on appelle le style de programmation que nous utilisons la programmation structurée. Il existe deux types de sous-programmes: les procédures et les fonctions.

Les fonctions

Une fonction a un nom et un type elle renvoie un résultat.

Nous avons déjà utilisé une fonction: la fonction "pow" de la bibliothéque "math".

			double racine;
			racine=pow(16,0.5);
			cout<<racine;
			

Nous allons maintenant créer une fonction qui renvoie la moitiée d'un nombre passé en paramètre. Notre fonction renvoie un rééel elle est donc du type réel. déclaration:

				double moitiee(double leNombre);
				

implémentation:

				double moitiee(double leNombre)
				{
				  double resultat;
				  resultat =leNombre/2.0;
				  return resultat;
				}
				

Pour se servir de la fonction, on l'utilise ainsi:

			int main(void)
			{
			  cout<<"la moitiée de 12 est:"<<moitiee(12);
			}
			

Le nb de paramètres qu'accepte une fonction est compris entre 0 et n.

Lorsqu'une fonction ne prend pas de paramètre, on met "void" ou rien du tout entre les parenthèses lors de la déclaration et dans l'utilisation on ne met rien dans les parenthèses.

Exemple 17. fonction sans paramètre

			string dateDuJour(void);
			string aujourdhui();
			...
			cout<<"bonjour aujourd'hui nous sommes "<<dateDuJour();
			


Lorsqu'une fonction nécessite plusieurs paramètres, ils sont séparés par des virgules comme dans l'exemple suivant:

Exemple 18. Une fonction qui accepte plusieurs paramètres

			double max(double nb1, double nb2);
			double max(double nb1, double nb2)
			{
			   if (nb1>nb2)
			   {
			     return(nb1);
			   }
			   else
			   {
			     return(nb2);
			   }
			}
			int main(void)
			{
			  double prixPublic=154;
			  double prixPromo=126;
			  cout<<max(prixPublic,prixPromo);
			}
			


Exercice: ecrire et utiliser une fonction somme qui renvoie la somme de ses deux paramètres

Exercice: ecrire et utiliser une fonction somme qui renvoie la somme de ses trois paramètres

Exercice: ecrire et utiliser une fonction min qui renvoie le plus petit de ses quatre paramètres

Utilisez la fonction typeof qui renvoie le type d'une variable passée en paramètre

Ecrire et utiliser la fonction nombreDeCaracteres qui prend en paramètre une chaîne de caractère et renvoie la taille de celle-ci en caractères.

Ecrire la fonction inverse qui renvoie l'inverse d'un nombre passé en paramètre

Ecrire la fonction inverse qui renvoie l'inverse d'une chaîne passée en paramètre

Ecrire une fonction toDouble qui prend en paramètre une string et renvoie un double

Les procédures

Une procédure est une fonction qui ne renvoie rien, il n'y a donc pas de return et le type est void. main est une procédure.

Valeurs par défaut des paramètres

Une valeur par défaut est spécifié aprés la déclaration du paramètre avec =valeur.

Par exemple:

		void affLigneEtoiles(long nbEtoile=80);
		

La valeur 80 est la valeur par défaut du paramètre nbEtoile. lors de l'appel suivant:

		affLigneEtoiles();//80 étoile seront affichées.
		

Lorsque la procédure est appelée sans valeur la valeur par défaut est utilisée.

		affLigneEtoiles(40);//40 étoile seront affichées.
		

On peut comme on le voit toujours spécifier une valeur qui écrase alors la valeur par défaut.

Paramétres par valeur et par référence

Les paramètres d'un sous programme peuvent être passés en lecture seule ce que nous avons fait jusqu'à présent ou en lecture-écriture comme nous allons le voir bientôt.

Le passage de paramètres en lecture écriture va permettre au sous-programme de modifier le contenu du paramètre, ainsi le programme ou sous-programme appelant bénéficiera des modifications effectuées par le sous-programme.

Au travers du programme suivant nous allons constater qu'il est impossible à un sous-programme de modifier de façon permanente la valeur d'un paramètre.

			void echange(long nb1, long nb2)
			{
			  long temp=nb1;
			  nb1=nb2;
			  nb2=temp;
			  cout<<"nb1 vaut<<nb1;//affiche nb1 vaut 20
			  cout<<"nb2 vaut<<nb2;//affiche nb2 vaut 4
			}
			void main(void)
			{
			  long hauteur, largeur;
			  hauteur=4;
			  largeur=20;
			  echange(hauteur,largeur);
			cout<<"hauteur vaut<<hauteur;//affiche hauteur vaut 4
			cout<<"largeur vaut<<largeur;//affiche largeur vaut 20
			}
			

En réalité, par ce mode de passage de paramètre ce sont des valeurs qui arrivent dans le sous-programme et qui sont temporairement stockées dans nb1 et nb2 mais ces variables disparaissent dés la dernière ligne du sous-programme

Il est possible de travailler avec des paramètres en lecture-écriture. C'est un mode de passage de paramètre différents, chaque paramètre passé en lecture écriture doit être précédé du signe & cela signifie que le paramètre est une variable sur laquelle le sous-programme peut travailler.

Notre programme devient:

			void echange(long & nb1, long & nb2)
			{
			  long temp=nb1;
			  nb1=nb2;
			  nb2=temp;
			  cout<<"nb1 vaut<<nb1;//affiche nb1 vaut 20
			  cout<<"nb2 vaut<<nb2;//affiche nb2 vaut 4
			}
			void main(void)
			{
			  long hauteur, largeur;
			  hauteur=4;
			  largeur=20;
			  echange(hauteur,largeur);
			cout<<"hauteur vaut<<hauteur;//affiche hauteur vaut 20
			cout<<"largeur vaut<<largeur;//affiche largeur vaut 4
			}
			

Voilà, évidemment, on peut mélanger les deux formes de passage de paramètre.

Quelques exercices sur le passage de paramètres

Ecrire un sous-programme qui range dans l'ordre croissant deux doubles passés en paramètres.

Ecrire un sous-programme qui trie un tableau de 50 chaînes passé en paramètre.

Ecrire un sous-programme qui ajoute à un tableau de chaînes passé en paramètre une chaîne saisie par l'utilisateur.

Les structures

Introduction aux structures

Pour l'instant, on utilisait des types prédéfinis pour nos variables. double, long, int char unsigned char string etc... Nous allons voir que le programmeur peut définir ses propres types de variable construits à partir des types de base que vous connaissez déjà. Les types construits à partir de type existants s'appellent des structures.

exemple de stucture

	typedef struct
	{
  		unsigned long numero;
  		string nom;
  		string prenom;
	}enrClient;
			

Dans l'exemple ci-dessus on definit un type de variable: le type: "enrClient".

Ce type est une structure comportant 3 champs: le numéro, le nom et le prénom.

S'en sortir avec les types structurés

Déclaration de variables d'un type structuré

.

	enrClient monPremierClient,monDeuxiemeClient;
					

.

	monPremierClient.nom="Dupond";
	monPremierClient.prenom="Jean";
	monPremierClient.numero=12;
					

nomDeLaVariableStructuree.nomDuChamp est donc une variable à part entière. On peut donc lui affecter une valeur:

	nomDeLaVariableStructuree.nomDuChamp=valeur;
				

On peut aussi la faire saisir au clavier:

	cout <<"Tapez le prénom du client: ";
	cin>>monDeuxiemeClient.prenom;
				

Pour faire afficher un client, il faut afficher ses champs un par un.

	cout<<"nom: "<<monPremierClient.nom<<" Prénom: "<<monPremierClient.prenom<<endl;
				

Pour faire saisir un client, il faut faire saisir ses champs un par un.

cout <<"Tapez le nom du client: ";
	cin>>monDeuxiemeClient.nom;
cout <<"Tapez le prénom du client: ";
	cin>>monDeuxiemeClient.prenom;
cout <<"Tapez le numéro du client: ";
	cin>>monDeuxiemeClient.numero;
				

Attention

Evidemment il est impossible d'afficher un client avec un seul cout ou de faire saisir un client avec un seul cin.

Les types des champs d'une structure peuvent être aussi des structures

Supposons que nous définissions un type structuré "enrAdresse", ce type peut être utilisé dans d'autre structure comme indiqué dans le code ci-dessous:

typedef struct
{
	string rue;
	string cpostal;
	string ville;
}enrAdresse;
typedef struct
{
	string nom;
	string prenom;
	enrAdresse adresse;
}enrPersonne;
//pour faire saisir la ville :
//.............qlq part dans le main
enrPersonne monPatron;
cin>>monPatron.adresse.ville;
				

Les tableaux d'enregistrement

Si l'on souhaite mémoriser un ensemble de personnes en mémoire, il est tout à fait possible de déclarer un tableau de "enrPersonne".

typedef struct
{
	string rue;
	string cpostal;
	string ville;
}enrAdresse;
typedef struct
{
	string nom;
	string prenom;
	enrAdresse adresse;
}enrPersonne;

//déclaration d'un tableau de 100 personnes
enrPersonne tabPersonnes[100];

//pour faire saisir la ville de la personne contenue dans la case 18 du tableau :
//.............qlq part dans le main
cin>>tabPersonnes[18].adresse.ville;
//pour faire saisir le nom de la personne contenue dans la case 4 du tableau :
cin>>tabPersonnes[4].nom;
//pour faire saisir afficher le prénom de la personne contenue dans la case 20 du tableau :
cout<<tabPersonnes[20].prenom;
				

Exercices sur les structures

Exercice 1) réaliser un programme qui déclare 2 points chaque point ayant une abcisse et une ordonnée et qui fournit le milieu du segment de droite ainsi défini. Les abcisses et ordonnées des deux points seront saisies par l'utilisateur du programme. Les abcisses et ordonnées du milieu seront affichées comme résultat.

Exercice 2) Etablissez la structure nécessaire à la définition d'une date, en faire saisir une et l'afficher.

Exercice 3) Etablissez la structure nécessaire à l'enregistrement d'un élève nom prénom numéro, date de naissance, en faire saisir deux et les afficher.

Exercice 4) Gestion d'une classe (tableau d'élève)

Exercice 5) Ecrire un programme qui permet d'enregistrer dans un tableau en mémoire le stock disponible de chaque produit. Pour chaque produit on enregistrera son n° sa désignation, son prix unitaire et la quantité en stock. Le programme permettra de plus: a) de lister tout le tableau b) de calculer le montant total du stock de l'entreprise c) de calculer le montant du stock pour un produit dont la désignation est saisie par l'utilisateur.

Les fichiers textes

Introduction sur les fichiers

Il est temps maintenant d'apprendre à sauver les informations saisies dans un fichier sur une mémoire de masse.Nous allons tout d'abord nous intéresser à de la simple sauvegarde de texte dans un fichier du disque dur.

Le principe d'utilisation des fichiers

Afin de pouvoir utiliser un fichier, il est nécessaire de l'ouvrir. On réalise ensuite notre traitement: lecture ou écriture. Enfin on le ferme. La bibliothéque nécessaire s'appelle "fstream" et on réalisera donc l'inclusion correspondante.

Lire un fichier entier

Comme vous allez le voir dans le code ci-dessous, il est nécessaire de faire une boucle pour lire un fichier texte, en effet, lorsqu'on lit dans un fichier texte, on n'obtient qu'une seule ligne du fichier.

#include <iostream>
#include <fstream>>
void main(void)
{
	ifstream monFichier("/home/gthom/clients.txt");//ouverture en lecture du fichier physique "/home/gthom/clients.txt"
	string ligneLue;
	while(monFichier>>ligneLue)	//tant que l'obtention de la ligne est possible
	{
	cout<<ligneLue;			//on affiche la ligne obtenue
	}
}
			

Evidemment si votre ligne comporte des espaces, vous n'obtiendrez pas le résultat escompté, en effet comme quand vous faisiez un cin>>nomDuFilm et que l'utilisateur saisissait arthur et les minimoys, vous ne récupériez dans nomDuFilm que la partie saisie précédent le premier espace à savoir "arthur". Il faudra donc utiliser le getline(idDuFichier,laLigneLue) pour obtenir la totalité de la ligne.

Ecrire dans un fichier texte

Un fichier texte peut être ouvert en écriture de deux façons différentes:

  • soit il est ouvert en mode "création" (mode par défaut) auquel cas si le fichier n'existait pas il est créé, ou s'il existait il est remplacé.
  • soit il est ouvert en mode ajout: ios::app. App signifie append qui veut dire ajout en anglais.

#include <iostream>
#include <fstream>>
void main(void)
{
	ofstream monFichier("/home/gthom/clients.txt");//ouverture en création du fichier physique "/home/gthom/clients.txt"
	string premiereligneAEcrire="Raoul;Flaubert;3rue des violettes;05320;Tallard";
	string deuxiemeligneAEcrire="Gertrude;Gonzalvez;6 place du four;05110;la Saulce";

	monFichier<<premiereligneAEcrire;//ecriture de la première ligne
	monFichier<<deuxiemeligneAEcrire;//écriture de la deuxième ligne
	...
	//puis le fichier est fermé
	monFichier.close();
	...
	//puis qlq part ailleurs on veut rajouter une ligne au fichier
	//pour ne pas l'écraser, il faut l'ouvrir en mode ajout
	ofstream monFichier("/home/gthom/clients.txt",ios::app);//ouverture en ajout du fichier physique "/home/gthom/clients.txt"
	string laTroisiemeLigne="Victor;Laricot;5 rue des suisses;05230;Embrun les bains";
	monFichier<<laTroisiemeLigne;//ecriture de la troisième ligne
	//puis le fichier est fermé
	monFichier.close();
}
			

Algorithmes de base sur les fichiers textes:

Le splittage des lignes consiste à extraire d'une ligne à séparateur, les informations élémentaires qu'elle comporte. Dans le code ci-dessus, on observait 5 informations différentes. Pour extraire ces informations de la ligne, il va falloir transformer la chaîne soit en un tableau de 5 chaînes soit en un enregistrement.

  • Un tableau: Pour remplir un tableau le principe est simple : on regarde chaque caractère de la chaîne du premier au dernier si ce n'est pas un séparateur on l'ajoute à la chaîne contenue dans la case du tableau en cours de remplissage. Si c'est un séparateur, alors on change de case. exercice: ecrire la procédure qui réalise ce travail. consignes: tableau à remplir et chaîne à splitter seront passés en paramètre.

Fusion de deux fichiers triés, modif d'une ligne d'un fichier texte, suppression d'une ligne d'un fichier texte.

Fusion:

/*
 * =====================================================================================
 *
 *       Filename:  main.cpp
 *
 *    Description:  fusion de fichiers textes sequentiels triés
 *
 *        Version:  1.0
 *        Created:  21.03.2007 17:31:56 CET
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  (gilles thomassin), gthom@btsinfogap.org
 *        Company:  BTS Informatique Lycée D.Villars Gap
 *
 * =====================================================================================
 */
#include <iostream>
#include <fstream>
using namespace std;
int main(void)
{
	//ouverture des deux fichiers à fusionner en mode lecture
	ifstream fichierclientsRaoul("fichierDesClientsARaoul.txt");
	ifstream fichierclientsNorbert("fichierDesClientsANorbert.txt");
	//ouverture du fichier résultat en mode création
	ofstream fichierResultat("fichierResultat.txt");
	//Boucle qui s'arrête lorsque les deux fichiers sont finis
	string ligneRaoul,ligneNorbert;
	//obtention d'une ligne depuis Raoul
	bool fichierRaoulTermine=!getline(fichierclientsRaoul,ligneRaoul);
	//obtention d'une ligne depuis Norbert
	bool fichierNorbertTermine=!getline(fichierclientsNorbert,ligneNorbert);
	//boucle qui se termine qd l'un ou l'autre des fichiers est fini
	//tq non condition de sortie
	//on sort qd on ne peut plus lire  dans le premier ou dans le deuxième

	while(!(fichierRaoulTermine||fichierNorbertTermine))
	{
		if(ligneRaoul<ligneNorbert)//"a" est plus petit que "b" et donc on écrit "a" avant "b"
		{
			fichierResultat<<ligneRaoul<<endl;;
			fichierRaoulTermine=!getline(fichierclientsRaoul,ligneRaoul);
		}
		else
		{
			fichierResultat<<ligneNorbert<<endl;
			fichierNorbertTermine=!getline(fichierclientsNorbert,ligneNorbert);
		}
	}
	//voilà c'est la fin de la boucle, on arrive là qd au moins un des deux fichiers
	//est fini
	//si le fichierRaoul n'est pas terminé on écrit la suite de fichierRaoul
	if(!fichierRaoulTermine)
	{
		fichierResultat<<ligneRaoul<<endl;
		while(getline(fichierclientsRaoul,ligneRaoul))
		{
			fichierResultat<<ligneRaoul<<endl;
		}
	}
	else//fichier raoul terminé qu'en est-il du fichier de Norbert?
	{
		//si le fichierNorbert n'est pas terminé on écrit la suite de fichierNorbert
		if(!fichierNorbertTermine)
		{
			fichierResultat<<ligneNorbert<<endl;
			while(getline(fichierclientsNorbert,ligneNorbert))
			{
				fichierResultat<<ligneNorbert<<endl;
			}
		}
	}
}//bouh déjà la fin trop triste...
// à bientôt pour de nouvelles aventures

	
	

Exercices sur les fichiers

Transformer en xml un fichier csv.

Transformer en csv un fichier xml.

Problématique des accés concurrents

Les fichiers en accés direct

Un fichier en accès direct est un fichier où contrairement aux fichiers séquentiels, on n'a pas besoin de lire les 20 premiers enregistrements pour lire le 21ième.

Dans un fichier à accés direct, les enregistrements ont une taille fixe par exemple 30 octets.

Pour lire le 21ième enregistrement, on se positionnera à 20*30 octets à partir du début du fichier

Dans un fichier en accès direct, on peut positionner indépendamment la tête de lecture et la tête d'écriture, respectivement par seekg (g pour get) et seekp (p pour put).

Voici un exemple complet

/*
 * =====================================================================================
 *
 *       Filename:  main.cpp
 *
 *    Description:  démo fichiers accés direct
 *
 *        Version:  1.0
 *        Created:  19.03.2007 11:25:34 CET
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:   (gthom), 
 *        Company: BTS Informatique Lycée D.Villars Gap
 *
 * =====================================================================================
 */
#include <iostream>
#include <fstream>
using namespace std;

char* const NOMFICHIER="produits.dat";

typedef struct
{
	long noProduit;
	char  libelleProduit [30];
	double prix;
} enrProduit;

void ajoutProduit(enrProduit nouveauProduit)
{
	ofstream fichierProduit(NOMFICHIER,ios::app); //ouverture du fichier en mode ajout donc tête ecriture placée en fin de fichier
	fichierProduit.write((char *)&nouveauProduit,sizeof(enrProduit));//on écrit à la position courante dans le fichier sizeof(enrProduit) octets que l'on prend à l'adresse suivante: &nouveauProduit
	fichierProduit.close();//fermeture du fichier
}

void afficheProduit(enrProduit leP)
{
	cout<<leP.noProduit<<"\t"<<leP.libelleProduit<<"\t"<<leP.prix<<endl;
}

void affFichier()
{
	//ouverture du fichier en lecture tête de lecture placée en début de fichier
	ifstream fichierProduit(NOMFICHIER);
	enrProduit leProduit;
	//boucle
	while(fichierProduit.read((char *)&leProduit,sizeof(enrProduit)))
	{
		afficheProduit(leProduit);//affichage du produit lu
	}
	//fin boucle qd la lecture a échouée
	fichierProduit.close();
}
void afficheUnProduit(long numero)
{
	//ouverture du fichier en lecture
	ifstream fichierProduit(NOMFICHIER);
	//positionnement de la teête de lecture au bon endroit
	fichierProduit.seekg((numero-1)*sizeof(enrProduit));
	enrProduit leProduit;
	//lecture d'un produit
	fichierProduit.read((char *)&leProduit,sizeof(enrProduit));
	//affichage
	afficheProduit(leProduit);
	//fermeture du fichier
	fichierProduit.close();
}

enrProduit produitFromClavier()
{
	enrProduit leProduit;
	cout<<"Saisie d'un nouveau produit"<<endl;
	cout<<"Libellé :";
	cin>>leProduit.libelleProduit;
	cout<<"Prix:";
	cin>>leProduit.prix;
	cin.ignore();
	leProduit.noProduit=1;
	return leProduit;
}
void modifProduit(long numero, enrProduit nouveauProduit)
{
 	//ouverture du fichier en lecture
	fstream fichierProduit;
	fichierProduit.open(NOMFICHIER,ios::out | ios::in);//pas en création(sinon ecrasé
	//positionnement tête d'écriture au bon endroit
	fichierProduit.seekp((numero-1)*sizeof(enrProduit));
	//écriture du nouveau produit à la place de l'ancien
	fichierProduit.write((char*)&nouveauProduit,sizeof(enrProduit));
	//fermeture
	fichierProduit.close();
 
}
int main (void)
{
	ajoutProduit(produitFromClavier());
	cout<<"Voici le fichier entier"<<endl;
	affFichier();
	cout<<"Voici le deuxième produit"<<endl;
	afficheUnProduit(2);
	enrProduit p;
	//c'est comme ça qu'on met qlq chose dans les vieilles chaînes azt.
	strcpy(p.libelleProduit,"citrouille");
	p.noProduit=12;
	p.prix=3;
	modifProduit(1,p);
	cout<<"Et maintenant le fichier entier modifié"<<endl;
	affFichier();


}

Exercices sur les fichiers à accès direct

Ecrire un programme permettant la gestion (ajout, modification, suppression, consultation) d'un fichier adhérent. Pour chaque adhérent seront renseigné: le numéro (entier), le nom, le prénom, la date d'adhésion, et l'email. Le programme permettra la consutation d'un adhérent connaissant son numéro ou son nom et son prénom.

Les index

Un index est une table à deux colonnes permettant un accés direct à une information contenue dans un fichier. Dans la première colonne se trouve la clef et dans la deuxième on trouvera la position de l'enregistrement dans le fichier ainsi ont saura que le produit "ssHf142X" et l'enregistrement n°"4881" du fichier produit.dat.

Les fichiers indexs sont triés par valeur de clef croissante afin de trouver rapidement la valeur de la clef recherchée (par dichotomie par exemple).

Un index est dit "unique" quand à une valeur de la clef ne correspond qu'un seul enregistrement.

Il peu y avoir plusieurs index pour un même fichier: un pour retrouver les produits par leur libellé et un pour retrouver les produits par leur codeProduit.

L'accés aux bases de données

Nous allons apprendre ici à nous connecter à un moteur de base de donnée postgres en utilisant l'api native fournie par le moteur.

Un petit coup de google postgresql c api nous renseigne de suite:http://www.postgresql.org/docs/8.2/interactive/libpq.html.

Le principe est simple: connection exécution des requêtes exploitation des résultats fermeture de la connexion.

Un exemple:

/*
 * =====================================================================================
 *
 *       Filename:  exempleCPostgresql.cpp
 *
 *    Description:  illustration accés à une base de données
 *
 *        Version:  1.0
 *        Created:  13.04.2007 09:18:31 CEST
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:   (gthom), 
 *        Company:  BTS Informatique de gestion Lycée Dominique Villars Gap
 */

#include <iostream>
#include <iomanip>
#include "libpq-fe.h"
using namespace std;
void affResultat(PGconn *connexion,string requete)
{
  		PGresult *curseur = PQexec(connexion, requete.c_str());
		ulong nombreDeChamps = PQnfields(curseur);
		//obtention et affichage des noms de champs
		for (long numeroChamp = 0; numeroChamp < nombreDeChamps; numeroChamp++)
		{
			cout<<setw(15)<< PQfname(curseur, numeroChamp);
		}
		cout<<endl;
		//obtention affichage des valeurs des champs pour tous les tuples
		for (long numeroLigne = 0; numeroLigne < PQntuples(curseur); numeroLigne++)
		{
			for (long numeroChamp = 0; numeroChamp < nombreDeChamps; numeroChamp++)
			{
				cout<<setw(15)<<PQgetvalue(curseur, numeroLigne, numeroChamp);
			}
			cout<<endl;
		}

		PQclear(curseur);

}
int main()
{
	string chaineDeConnexion;
	PGconn     *connexion;
	chaineDeConnexion = "user=gthom password=benvoyons!!! dbname = dbvin";
	connexion = PQconnectdb(chaineDeConnexion.c_str());
	if (PQstatus(connexion) != CONNECTION_OK)
	{
		cerr<<"La connexion a la base a échoué pour la raison suivante: "<<PQerrorMessage(connexion)<<endl;
	}
	else//connexion réalisée
	{
		//select * sur la table vin
	        affResultat(connexion,"select * from vin");
		//un insert maintenant:
		string requete;
		requete="insert into vin values(12,'MU',2007)";
		PGresult *resultat=PQexec(connexion,requete.c_str());
		PQclear(resultat);
		//reselect 
		affResultat(connexion,"select * from vin");
	}
	PQfinish(connexion);
}