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

Gilles Thomassin

Julien Legrand

Ce document est plaçé sous licence LGPL


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

Les premiers pas
Prologue
Hello world
Exercices sur la compilation
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 alternatives simples
Exercices sur les stuctures alternatives simples
Structure alternative multiple
Exercices sur les stuctures alternatives multiples
Les structures répétitives
Choix du type de boucle
Boucle 0,N
Boucle 1,N
Boucle n passages
Exercices d'initiation sur les boucles
Exercices sur les boucles : saisie contrôlée
Les tableaux
Introduction: pourquoi les tableaux
Ce qu'il faut savoir sur les tableaux
Algorithmes de base sur les tableaux
Exercices de base sur les tableaux
Exercices sur les tableaux surdimentionnés.
Exercices approfondis sur les boucles
Compléments d'affichage et de saisie
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 sous-programmes
Introduction
Les fonctions
Exercices sur les fonctions.
Les procédures
Valeurs par défaut des paramètres
Paramètres par valeur et par référence
Quelques exercices sur le passage de paramètres dans les procédures.
Les structures
Introduction aux structures
Exemple de stucture
S'en sortir avec les types structurés
Déclaration de variables d'un type structuré
Les types des champs d'une structure peuvent être aussi des structures
Les tableaux d'enregistrement
Exercices sur les structures
Les fichiers textes
Introduction sur les fichiers
Le principe d'utilisation des fichiers
Lire un fichier entier
Ecrire dans un fichier texte
Algorithmes de base sur les fichiers textes:
Problématique des accés concurrents
Projet -- unification des compétences système et développement : gestion des interfaces réseau en C++
La réalisation du projet
Lecture de la configuation IP.
Modification la configuation IP.
Passer d'une configuration IP à une autre.
Modification la configuation IP v2.
Passer d'une configuration IP à une autre v2.

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 (condition) {}
11. do..while
12. Affichage d'un rectangle de 3 * 4 étoiles.
13. Afficher un caractère d'après son code ASCII
14. Cadrer un affichage avec des tabulations
15.
16. setprecision
17. Affichage du 4ième caractère d'une chaîne
18. Déclaration et accès aux cases d'un tableau.
19. Utilisation d'une constante pour déclarer la taille d'un tableau
20. fonction sans paramètre
21. 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.

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.

Travail à faire : Dans votre répertoire personnel, créez un répertoire "IG1_C++". 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 "01_projetHello" placez vous à l'intérieur, et à l'aide de gvim ou à défaut vim, 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 jlegrand jlegrand 13447 aoû 10 09:10 a.out*
-rw-r--r--  1 jlegrand jlegrand 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 "01_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.

	[jlegrand@bigserv projetHello]$ ./a.out
	Bienvenue dans la communauté des développeurs
	Appuyer sur une touche suivie de Entrée pour continuer
	a
	[jlegrand@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

Travail à faire : 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.
	

Consignes: Vous restez dans le dossier 01_projetHello. 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. Vous restez dans le dossier 01_projetHello. Le fichier source s'appellera exo2.cpp. L'exécutable obtenu s'appellera gpl2.

A retenir :

  • La compilation se fait comme ceci: g++ -o "nom de l'exécutable " "nom du fichier source"
  • Lorsqu'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 (ou arguments) 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.

Travail à faire : Editez, compilez et exécutez ce programme.

A 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.
  • main est doit toujours être suivis par ( ), même si on n'écrit rien entre les parenthèses.

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 indique de sens de "déplacement" de la chaîne de caractères "bonjour" : vers cout (l'écran).

Toute instruction se termine par un ";" en anglais: "semicolon". Oublier le ";" provoquera une erreur 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.
  • erreur: expected `;' before «nb2»
    , suffisamment explicite, encore que insiqué sur la ligne suivante.
  • ou un autre message d'erreur indiqué sur la ligne suivante

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ère) 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
#include <iostream>
using namespace 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 les caractères ex: 's'
  • string pour les chaînes de caractères ex: "Bonjour"
  • bool pour les booléens ex: 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 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.

Organiser la saisie d'information

La saisie d'information suppose l'affichage préalable d'un message qui renseigne l'utilisateur sur 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()
	{
		string nomClient;
		cout<<"Votre nom :";
		cin>>nomClient;
		cout<<endl<<"Bonjour "<<nomClient;
	}	
	

Exercices de base

Travail à faire : Créez un dossier nommé 02_projetVariables dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

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

exercice 2 : 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

exercice 3 : 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).

exercice 4 : Ecrire le programme piscinePlus qui demande à l'utilisateur la largeur, la longueur et les profondeurs aux deux extrémités 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. Pour calculer le volume de la piscine, il faut utiliser la profondeur moyenne de celle-ci.

exercice 5 : Réaliser une nouvelle version du programme ci-dessus, nommée piscineCout permettant de calculer le cout de remplissage de la piscine. On peut estimer à 2,60 euros le coût au mètre cube de l'eau.

exercice 6 : Ecrire le programme horaire 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;

exercice 7 : Ecrire un programme voyageEnTrain qui demande à l'utilisateur l'heure de dépard 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 certaines conditions. Ou alors on peut répéter un groupe d'instructions 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(<condition>)
{
	<bloc1...>
}
else
{
	<bloc2...>
}
						

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

Elle se lit comme ceci : si la proposition logique <condition> 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 simples

Travail à faire : Créez un dossier nommé 03_projetAlternativesSimples dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

exercice 1 : Ecrire le programme triNoms qui demande à l'utilisateur deux noms et les lui affiche dans l'ordre alphabétique.

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

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

exercice 4 : Ecrire le programme triNombre qui demande à l'utilisateur 3 réels et les lui affiche dans l'ordre croissant.

exercice 5 : Ecrire le programme facturation qui calcule le 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 19,6%.

exercice 6 : Ecrire le programme delta 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; 

exercice 7 : Ecrire le programme nuancier 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).

exercice 8 : Ecrire le programme bissextile qui détermine si une année saisie par l'utilisateur est une année bissextile. Une année est bissextile si elle divisible par 4, sauf si elle est divisible par 100 à moins qu'elle soit divisible par 400.

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

Exercice 10 : Ecrire le programme dureeMois 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<<"Sauf erreur de votre part, le nombre tapé est 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, et ce jusqu'à la prochaine instruction break; ou à défaut jusqu'à la fin du switch 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é.

Exercices sur les stuctures alternatives multiples

Travail à faire : Créez un dossier nommé 03_projetAlternativesMultipes dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

exercice 1 : La voyelle 'y' n'a pas été prise en compte dans l'exemple ci-dessus. Reprenez et rectifiez le programme voyelles en conséquence.

exercice 2 : Le programme codageHumain permet de donner le code numérique correspondant à la description d'un humain : 2 bits pour la taille (très grand, grand, normal, petit), 2 bit pour les cheveux (clairs, foncés, colorés, aucun), 2 bits pour les yeux (bleus, verts, marrons), 1 bit pour le sexe (Homme, Femme). A vous de documenter votre programme pour qu'il soit facile de comprendre votre codage. Vous devez donc saisir, en saisie contrôlée et non en saisie ouverte, les caractéristiques puis afficher le code résultant.

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 (si le nombre de répétition appartient à [1..n])
			On utilisera la boucle do {...} while(...); 
				//on passe au moins une fois dans la boucle
		FinSi
	FinSi
						

Boucle 0,N

Syntaxe: while (condition logique d'arrêt) {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.

La condition logique d'arrêt doit répondre à la question : continuer tant que ??? Elle peut utiliser les tous les opérateurs logiques étudiés avec les alternatives.

Exemple 10. Boucle while (condition) {}

long dividande, diviseur;
cout<<"Ce programme affiche le résultat de la division entière d'un dividande par un diviseur (sans les opérateurs / et %)";
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 de soustraire le diviseur au dividande, on le fait. Résultat compte le nombre de soustractions que l'on a pu 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 {bloc d'instructions} while(condition logique d'arrêt)

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.

La condition logique d'arrêt doit répondre à la question : continuer tant que ??? Elle peut utiliser les tous les opérateurs logiques étudiés avec les alternatives.

Exemple 11. do..while

Obtention du nombre 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 lancers
	nombreDeLancers=0;
	do
	{
		nombreDeLancers++; //incrémentation du nb de lancer de dé
		nombreAleatoire=rand();//tirage au hasard d'une nombre réel de l'intervalle [0 .. 1 [
		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 n passages

Syntaxe: for ( initialisation ; arrêt ; évolution ){bloc d'instructions} initialisation est l'instruction d'initialisation du compteur de la boucle. arrêt est la condition logique portant sur le compteur permettant d'arrêter la boucle. Cette condition répond à la question répéter tant que ??? évolution est l'insctruction permettant de faire évoluer le compteur (incrémantation, décrémentation, saut de 2, ...).

Utilisation : la boucle for est à utiliser lorsque l'on connait dès 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 d'initiation sur les boucles

Travail à faire : Créez un dossier nommé 04_projetRepetitive dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

Exercice 01 : Ecrivez le programme tenPrems, qui affiche les 10 premiers entiers.

Exercice 02 : Ecrivez le programme tenPremsPairs, qui affiche les 10 premiers entiers pairs.

Exercice 03 : Ecrivez le programme rectangle; qui affiche un rectangle d'étoiles de 10 lignes de 7 étoiles.

Exercice 04 : Ecrivez le programme triangle qui affiche ceci :

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

Exercice 05 : Ecrivez le programme cone qui affiche ceci :

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

Exercice 06 : Ecrivez le programme coneVariable qui affiche un cone comme dans l'exercice précédent, sauf que le nombre d'étoiles impair de la base sera saisi par l'utilisateur.

Exercice 07 : Ecrivez le programme coneVariableControle qui affiche un cone comme dans l'exercice précédent, mais on contrôlera que le nombre d'étoiles de la base appartient à l'intervalle [1..79] et est impaire. La saisie resa recommencée tant qu'elle n'est pas conforme.

Exercice 08 : Ecrivez le programme fleche qui affiche un cone comme dans l'exercice précédent, au dessus d'un tronc de 10*5 étoiles, toujours en contrôlant que le nombre d'étoiles de la base appartient à l'intervalle [5..79] et est impaire. La saisie resa recommencée tant qu'elle n'est pas conforme.

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

Exercice 09 : Ecrivez le programme tableMultiplication 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 : saisie contrôlée

Exercice 10 : Reprenez le programme 03_projetAlternativesMultipes/codageHumain et ajouter un contrôle sur chaque saisie : la saisie recommence tant que l'utilisateur ne saisit pas une valeur cohérente.

Exercice 11 : Reprenez le programme tableMultiplication. Modifiez le de façon à ce que le programme marque une pause après l'affichage de la table, puis efface l'écran et redemande à l'utilsiateur quelle table afficher. Pour quitter, l'utilisateur devra saisir une valeur remarquable, que vous lui indiquerez et que vous intègrerez dans la contrpole de saisie.

Exercices approfondis sur les boucles

Exercice 12 : Ecrivez le programme moyenne qui calcule la moyenne de n notes. Le nombre de notes est demandé au préalable à l'utilisateur.

Exercice 13 : Ecrivez le programme moyennePlus 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.

Exercice 14 : Ecrivez le programme bin2dec qui converti un nombre binaire en décimal. Le nombre binaire est saisi comme un entier.

Exercice 15 : Ecrivez le programme ASCII qui affiche le contenu de la table ASCII (à partir du caractère n°32). Vous affichez le code ASCII, suivi du caractère correspondant.

Exemple 13. Afficher un caractère d'après son code ASCII

	char caractere;
	caractere=48;
	cout<<endl<<"Le caractère de code ASCII 48 est "<<car<<endl; 

Exercice 16 : Ecrivez le programme ASCIIRangée qui fait la même chose que précédemment, mais qui 10 caractères précédé de leur code ASCII par ligne, espacés d'une tabluation.

Exemple 14. Cadrer un affichage avec des tabulations

	cout<<endl<<"début \t milieu \t fin"<<endl; 

Exercice 17 : Ecrivez le programme testIntMax qui affiche les 10 nombres entiers de type int après 32 760. D'après ce qui a été dit en cours sur les variables de type int, que concluez-vous ?

Exercice 18 : Ecrivez le programme compareIntLong qui affiche les 10 nombres entiers de type int puis long après 2 147 483 640. Qu'en déduisez-vous ?

Exercice 19 : Ecrivez le programme valeursIntExtremes qui affiche les 10 nombres entiers de type int avant 2 147 483 640 et après 2 147 483 640. Qu'en déduisez-vous ?

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 cases. Ce nombre de cases 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ées sur les variables sont donc reproductibles sur les cases d'un tableau.

Exemple 18. Déclaration et accès aux cases d'un tableau.

	//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 toutes 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 et gestion du nombre de cases remplies

Suppression d'un element dans un tableau

Insertion dans un tableau trié

Exercices de base sur les tableaux

Travail à faire : Créez un dossier nommé 06_projetTableaux dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

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

Exercice 2 : 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. Le programme s'appelle alors noteMax.

Exercice 3 : En partant de l'exercice n°1, afficher le nb de note au dessus ou égales à la moyenne et le nombre de note en dessous de la moyenne. Le programme s'appelle alors noteStat.

Exercice 4 : Compléter le programme obtenu à l'exercice n°2 pour afficher le nom des élèves ayant obtenu la meilleure note. Ce programme s'appelle alors noteMaxNom.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.

Exercice 5 : ecrivez le programme nomMois qui affiche le 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.

Exercices sur les tableaux surdimentionnés.

Dans la suite des exercices, les tableaux seront surdimensionnés et on gérera dans une variable à part le nombre de cases remplies.

On a vu précédemment qu'il était possible de déclarer un tableau en fixant le nombre de cases qui le composent. Ce nombre de cases maximum doit être géré durant le programme, notamment au moment d'ajouter des éléments dans le tableau, pour éviter de sortir de la zone mémoire qui lui est allouée, ce qui provoque une erreur de segmentation. Toute modification de ce nombre de cases entraine le besoin de modifier en plusieurs points les programmes écrits. Il peut être alors judicieux d'utiliser une constante (sorte de variable dont on ne peut pas changer la valeur) pour déclarer et gérer la taille maximale du tableau.

Exemple 19. Utilisation d'une constante pour déclarer la taille d'un tableau

	//inclusion des bibliothèques
	#include ...
	
	//programme principal
	int main()
	{

		//déclaration des constantes
		#define tailleMax 25

		//déclaration du tableau de nom
		string tabNoms [ tailleMax ];

		...

	}

				

La constante tailleMax peut également être affichée, comparée à d'autres valeurs, variables ou constantes, etc.

Travail à faire :

Exercice 6 : Ecrire le programme gestionNotesEleves 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 (d'après son nom) 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.

Exercice 7 : Faites le programme tirageLoto qui fait saisir et stocke les tirages du loto (hors numéro chance), puis qui classe les numéros en fonction de leur fréquence de tirage. Un menu devra proposer à l'utilisateur de saisir un tirage ou de consulter les statistiques.

Compléments d'affichage et de saisie


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 15. 

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 16. 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 à une dimension.

On peut accéder individuellement à chaque caractère de la chaîne en précisant entre [ ] 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 17. 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

Travail à faire : Créez un dossier nommé 05_projetChaines dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

Exercice 01 : Ecrivez le programme chaineEclatee qui demande à l'utilisateur de saisir une chaîne de caractères et la lui réaffiche avec un seul caractère par ligne.

Exercice 02: Ecrivez le programme ChaineALEnvers qui demande à l'utilisateur de saisir une chaîne de caractère et la lui réaffiche du dernier au premier caractère.

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

Exercice 04 : Faites le programme bin2dec qui convertit un nombre binaire saisi dans une chaine en nombre décimal.

Exercice 05 : Faites le programme jeuDuPendu 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. Vous devez mettre à profit les formatages d'affichage. Un efois le programme terminé, si vous avez le temps, vous pouvez dessiner le pendu, qui se complète au fur et à mesure de la progression.

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 ou encore programmation procédurale. 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é d'un nombre passé en paramètre. Notre fonction renvoie un réél, elle est donc du type réel. déclaration:

				double moitie(double leNombre);
				

implémentation:

				double moitie(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é de 12 est:"<<moitie(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 20. 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, chacun étant typé, comme dans l'exemple suivant:

Exemple 21. 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);
			}
			

Seul l'odre des paramètres indique la correspondance entre ceux déclarés dans la fonction appelés les paramètres formels et ceux utilisés lors de l'appel de la fonction appelés les paramètres effectifs. Il n'est pas nécessaire que les paramètres formels et effectifs correspondant aient le même nom.

Exercices sur les fonctions.

Travail à faire : Créez un dossier nommé 07_projetFonctions dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

Exercice 1 : ecrire le programme somme qui met en oeuvre une fonction somme qui renvoie la somme de ses deux paramètres.

Exercice 2 : ecrire le programme sommePlus qui met en oeuvre une fonction somme qui renvoie la somme de ses trois paramètres.

Exercice 3 : ecrire le programme min qui met en oeuvre une fonction min qui renvoie le plus petit de ses quatre paramètres.

Exercice 4 : ecrire le programme length qui met en oeuvre une fonction nombreDeCaracteres qui prend en paramètre une chaîne de caractères et renvoie la taille de celle-ci en caractères.

Exercice 5 : ecrire le programme inverseNb qui met en oeuvre une fonction inverse qui renvoie l'inverse mathématique d'un nombre passé en paramètre.

Exercice 6 : ecrire le programme inverseString qui met en oeuvre une fonction inverse qui renvoie l'inverse d'une chaîne passée en paramètre.

Exercice 7 : ecrire le programme stringToDouble qui met en oeuvre 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 dont le type est void. main est une procédure.

Valeurs par défaut des paramètres

Une valeur par défaut est spécifiée 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 à la fermeture 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érent, 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 dans les procédures.

Exercice 8 : ecrire le programme classement qui met en oeuvre une fonction qui range dans l'ordre croissant deux doubles passés en paramètres.

Exercice 9 : ecrire le programme trieTableau qui met en oeuvre une fonction qui trie un tableau de 50 chaînes passé en paramètre.

Exercice 10 : ecrire le programme appendTableau qui met en oeuvre une fonction qui ajoute à un tableau de chaînes passé en paramètre une chaîne saisie par l'utilisateur sans la fonction. Pensez à gérer les indicateurs classiques sur les tableaux surdimensionnés.

Les structures


Introduction aux structures

Pour l'instant, on utilisait des types prédéfinis pour nos variables. double, long, 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

Travail à faire : Créez un dossier nommé 08_projetStructures dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

Exercice 1 : réalisez le programme coordonneeMilieu qui déclare une structure permettant de stocker les coordonnées (numériques) d'un point dans un repère. Deux de ces points sont alors déclarés et saisis. Le porgramme doit enfin calculer un troisième point, milieu du segment délimité par les deux points saisis. Les coordonnées de ce point seront affichées.

Exercice 2 : écrivez le programme date qui déclare, saisie et affiche la structure nécessaire à la définition d'une date.

Exercice 3 : dans le programme eleves, établissez 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 : écrivez le programme classe, qui permet de stocker tous les élèves d'une classe, tels que présentés dans l'exercice 3. Les élèves seront stockés dans un tableau surdimensionné. Le programme devra permettre d'ajouter un élève, de le supprimer, de trier le tableau et d'en afficher le contenu global : numéro, nom, prénom et date de naissance de chaque élève.

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>
using namespace std;
int main()
{
	ifstream monFichier("./clients.txt");//ouverture en lecture du fichier physique "./clients.txt"
	string ligneLue;
	while(monFichier>>ligneLue)	//tant que l'obtention de la ligne est possible
	{
	cout<<ligneLue<<endl;			//on affiche la ligne obtenue
	}
	monFichier.close(); //fermeture du fichier 
}
			

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. L'algorithme de lecture plus efficace devient alors :

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
	bool lectureReussie;
	ifstream monFichier("./clients.txt");//ouverture en lecture du fichier physique "./clients.txt"
	string ligneLue;
	
	lectureReussi=getline (monFichier,ligneLue); //transfert de la ligne lue du fichier vers ligneLue. 
	//La fonction getLine renvoie un booléen indiquant la réussite de la lecture.
	while(lectureReussie)	//peut également s'écrire while (lectureReussi == true)
	{
		cout<<ligneLue<<endl;			//on affiche la ligne obtenue
		lectureReussi=getline (monFichier,ligneLue); 
	}
	monFichier.close(); //fermeture du fichier 
}
			

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>
using namespace std;
int main()
{
	ofstream monFichierCreation("./clients.txt");//ouverture en création du fichier physique "./clients.txt"
	string premiereligneAEcrire="Raoul;Flaubert;3 rue des violettes;05320;Tallard\n";
	string deuxiemeligneAEcrire="Gertrude;Quelvieuxnom;6 place du four;05110;la Saulce\n";

	//l'ajout du caratère d'échappemet \n permet d'écrire l'enregistrement suivant 
	//sur la ligne suivante dans le fichier texte , plutot qu'à la suite.

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

Algorithmes de base sur les fichiers textes:

Travail à faire : Créez un dossier nommé 09_projetFichiers dans IG1_C++. Dans les exercices ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

Exercice 1 : reprenez le programme donné ci-dessus en exemple, et nommez le creation. Vérifier la création et le bon contenu du fichier clients.txt.

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 2 : en vous basant sur le programme cité en exemple de lecture plus haut, écrivez le programme lectureInTableau, qui lit le fichier clients.txt, qui utilise la fonction split pour stocker les éléments lus dans chaque ligne dans un tableau, pour finir par les afficher. Bien entendu, c'est à vous d'écrire la procédure split, qui reçoit comme paramètres le tableau à remplir et la chaîne à splitter.

  • Une structure : la fonction split peut remplir une strucrture, mais cette fonction sera alors spécifique au programme. Les strcutures n'étant jamais de forme générique.

    Exercice 3 : écrivez le programme lectureInStruct, qui lit le fichier clients.txt, qui utilise la fonction splitInStruct pour stocker les éléments lus dans chaque ligne dans une structure, pour finir par les afficher. Bien entendu, c'est à vous d'écrire la fonction splitInStruct, qui reçoit comme paramètre la chaîne à splitter.

Exercice 4 : voici deux fichiers textes, de stucture implicite : fichier elevesGoupeA.txt

			amblard;elsa;F;23/05/1991
			deliancourt;fabien;H;08/05/1989
			rey;antony;H;27/10/1990

fichier elevesGoupeB.txt

			kupelian;frédéric;H;02/10/1989
			lacoutiere;paloma;F;28/11/1990
			reynaud;yoann;H;31/08/1988

Vous devez écrire le programme fusion, qui crée un fichier classe.txt, en fusionnant les deux fichiers, à l'instar d'un tri par interclassement pour les tableaux.

Exercice 5 : écrire le programme recherche qui affiche les données correspondant au nom de l'étuiant saisi par l'utilisateur. Ce porgramme utilise le fichier classe.txt créé dans l'exercice 4.

Problématique des accés concurrents

le gros problème avec les fichiers reste la gection des accès concurrents : lorsque plusieurs instances du programme, probablement utilisées par plusieurs personnes, souhaitent travailler en même temps sur le même fichier. Or un fichier ne peu être ouvert qu'une seule fois, à la fois... Au moins trois solutions peuvent alors être envisagées :
  • Ne jamais garder le fichier ouvert plus longtemps qu'il n'est nécessaire. Il fait alors l'ouvrir et le fermer pour chaque lecture ou écriture.
  • Faire un appareillage de tableaux : transférer le contenu du ou des fichiers dans un ou plusieurs tableaux de structures en début de programme, et faire l'inverse en fin de programme. Le problème de cette méthode reste la synchonisation des travaux des différentes occurrences du même programme : si deux utilisateurs souhaitent apporter des moficiations différentes à un même enregistrement ; le premier modifie le nom du client et le second son numéro de téléphone. Lorsque le premier va tranférer son tableau client dans le fichier correspondant, ses mises à jours seront répercutées. Lorsque le second va tranférer son tableau client dans le fichier correspondant, ses mises à jours seront répercutées, mais la version du nom du client sera celle qu'il connaît, celle qui n'a pas été modifiée par le premier. cette solution n'est donc pas idéale.
  • La dernière solution consiste à utiliser un système qui sait gérer les accès concurrents : les bases de données.

Projet -- unification des compétences système et développement : gestion des interfaces réseau en C++


La réalisation du projet

Créez un dossier nommé 10_theProjetOfIG1 dans IG1_C++. Dans les éléments du projet ci-dessous, le nom indiqué pour chaque programme servira pour le programme source .cpp et pour le programme l'exécutable généré lors de la compilation.

Lecture de la configuation IP.

Vous devez écrire le programme maConfigIP qui affiche la configuration IP du poste en cours : son adresse IP et son masque, dans une écriture décimale longue (255. . . ).

Vous devez écrire une procédure splitMask qui accepte en paramètres un tableau de 4 entiers et une chaine contenant l'écriture longue d'un masque de réseaeu. Chaque cellule du tableau se verra affectée la valeur de chaque octet du masque de réseau passé en paramètre.

Vous devez utiliser une fonction maskToCIDR qui accepte en paramètre une chaine contenant l'écriture longue du masque et ui renvoi un entier contenant le nombre de bits du masque.

Quelques astuces pour arriver au bout :

  • la commande shell pour afficher la configuration IP est ifconfig
  • les intefaces réseaux sont nommées ainsi :! ethx, où x est le numéro de l'interface rj45, wifix ou x est le numéro de l'interface wifi. D'autre noms peuvent apparaître comme athx (identique au wifi), ...
  • la commande c++ : system("clear"); permet au programme c++ d'exécuter la commande clear dans le shell.
  • vous devez utiliser la commande shell permettant de récupérer l'affichage proposé par ifconfig dans un fichier texte.

Modification la configuation IP.

Vous devez écrire le programme NewIPv1 qui saisit l'interface et la nouvelle configuration IP temporaire sous sa forme CIDR.

Quelques astuces pour arriver au bout :

  • la commande shell pour modifier la configuration IP est ifconfig <nomInterface> <ConfigIP_CIDR> up
  • Pour que le programme fonctionne, il faudra l'éxécuter avec les droit d'administrateur.

Passer d'une configuration IP à une autre.

Vous devez écrire le programme IPSwitcher qui gère une liste de configuration IP pour vos interfaces. Toutes les interfaces disponibles sont récupérées dans le shell. Toutes les configurations créées sont numérotées séquentiellement et enregistrées dans un fichier texte. L'idée est de pouvoir facilement passer d'une configuration à une autre, ce qui est plus que pratique pour tester des configurations réseau.

Modification la configuation IP v2.

Ce travail est obligatoire pour ceux qui veulent faire l'option Dev.Vous devez écrire le programme NewIPv2 qui travaille exactement comme NewIPv1, sauf que les paramètres à utiliser ne sont plus saisis mais reçu directement du shell.

Explications : la fonction int main() peut accepter deux arguments :int main(int argc, char** argv)

  • argc (argument count) renvoie le nombre d'arguments reçus par le programme.

  • argv (arguments values) renvoi un tableau de chaines contenant tous les arguments reçu par le programme.

    argc vaut au minimum 1. Dans ce cas, argv[0] renvoie le nom du programme lui-même, qui est bien le premier argument saisi pour lancer le programme. Si vous saisissez ./NewIPv2, argv[0] renvoie ./NewIPv2

Il est donc simple de récupérer les deuxième et troisème argument, s'ils existent, qui devraient contenir le nom et l'interface à modifier et l'adresse CIDR à utiliser. Il est toutefois conseillé de tranférer ces arguments dans des variables string avant de s'en servir.

Au moment d'utiliser le programme ainsi créé, il fautra saisir quelque chose comme : sudo NewIPv2 eth0 172.16.49.250/20.

Passer d'une configuration IP à une autre v2.

Ce travail est obligatoire pour ceux qui veulent faire l'option Dev.Vous devez écrire le programme IPSwitcherv2, qui reprend exactement IPSwitcher. Toutefois, vous devez gérer la possibilité de lui fournir en paramètre (depuis le shell, comme vu dans l'exercice précédent) deux argument le nom de l'interface et le numéro de la configurationà utiliser. Ainsi, la modification sera apportée, mais sans rien saisir d'auitre;, d'où un usage plus rapide.