• Aucun résultat trouvé

TP Programmation C/C++ Structures fondamentales d’algorithmie

N/A
N/A
Protected

Academic year: 2022

Partager "TP Programmation C/C++ Structures fondamentales d’algorithmie"

Copied!
30
0
0

Texte intégral

(1)

Structures fondamentales d’algorithmie

© 2017 tv <[email protected]>v.1.1

Sommaire

Un programme informatique 3

Objectifs du programmeur . . . 3

Entrées et sorties . . . 3

Objets, types et valeurs . . . 4

Nommer une variable . . . 5

Expressions et instructions . . . 6

Conditionner une action . . . 7

Les variables booléennes . . . 9

Itérer une action . . . 11

Exercices : Un parcours semé d’embûches 13 Dans le fourré . . . 13

Vendanges . . . 15

Course avec les enfants . . . 16

Bornes kilométriques . . . 17

Bagarre générale . . . 18

Calculatrice . . . 19

Graduation de thermomètres . . . 19

Calcul des dénivelées . . . 20

Concours de tir à la corde . . . 20

Type d’arbres . . . 21

L’espion est démasqué ! . . . 22

Moyenne des notes . . . 23

Tarif du bateau . . . 23

La roue de la fortune . . . 24

Bilan 25

Annexe 0 : printf() et scanf() 26

Annexe 1 : erreurs du débutant 27

(2)

Annexe 2 : opérations sur les nombres réels 29

Les objectifs de ce tp sont de comprendre et mettre en oeuvre des variables dans les struc- tures fondamentales d’algorithmie : enchaînements, alternatives, itérations. Les exercices sont extraits du site www.france-ioi.org.

Les critères d’évaluation de ce tpsont :

– le minimum attendu : on doit pouvoir fabriquer un exécutable et le lancer ! – le programme doit énoncer ce qu’il fait et faire ce qu’il énonce !

– le respect des noms de fichiers

– le nommage des variables ainsi que leurs types, l’utilisation de constantes – le code est fonctionnel

– la simplicité du code

(3)

Un programme informatique

Un programme informatique (simple) est souvent structuré de la manière suivante :

Un traitement est tout simplement l’action de produire des sorties à partir d’entrées : les vrais programmes ont donc tendance à produire des résultats en fonction de l’entrée qu’on leur fournit.

Objectifs du programmeur

Le métier de programmeur consiste à écrire des programmes qui : – donnent des résultats corrects

– sont simples – sont efficaces

L’ordre donné ici est très important : peu importe qu’un programme soit rapide si ses résultats sont faux.

De même, un programme correct et efficace peut être si compliqué et mal écrit qu’il faudra le jeter ou le récrire complètement pour en produire une nouvelle version. N’oubliez pas que les programmes utiles seront toujours modifiés pour répondre à de nouveaux besoins.

Un programme (ou une fonction) doit s’acquitter de sa tâche de façon aussi simple que possible.

Nous acceptons ces principes quand nous décidons de devenir des professionnels. En termes pratiques, cela signifie que nous ne pouvons pas nous contenter d’aligner du code jusqu’à ce qu’il ait l’air de fonctionner : nous devons nous soucier de sa structure. Paradoxalement, le fait de s’intéresser à la structure et à la

“qualité du code” est souvent le moyen le plus facile de faire fonctionner un programme.

En programmation, les principes à respecter s’expriment par des règles de codage et des bonnes pratiques.

+ Exemples :

Règle de codage: les valeurs (comme 10 pour unmaximum ou 3.14pour pi) dans une expression doivent être déclarées comme des constantes. En C, les constantes s’écrivent en majuscules.

Bonne pratique: Un programme (ou une fonction) ne doit pas dépasser 15 lignes deC/C++(accolades exclues).

Entrées et sorties

Pour l’instant, nos programmes se limiteront à lire des entrées en provenance du clavierde l’utilisateur et de produire des résultats en sortie sur l’écran de celui-ci.

Pour lire des entrées saisies au clavier (l’entrée standardstdin), on utilisera :

(4)

– scanf()en C ou C++

– cinen C++

- Ne vous préoccuper pas des saisies invalides. Pour écrire des programmes qui fonctionnent et qui sont simples, il est plus prudent pour l’instant de supposer que l’on fait face à un utilisateur « parfait ». Par exemple, lorsque on souhaite lire un entier, l’utilisateur « parfait » saisit un entier !

Pour afficher des résultats à l’écran (la sortie standard stdout), on utilisera : – printf()en C ou C++

– couten C++

- Evidemment, il existe d’autres types d’entrées/sorties (fichier, réseau, base de données, ...) pour les programmes. Nous les verrons plus tard.

Objets, types et valeurs

Pour pouvoir lire quelque chose, il faut dire où le placer ensuite. Autrement dit, il faut un “endroit” dans la mémoire de l’ordinateur où placer les données lues. On appelle cet “endroit” un objet.

Un objet est une région de la mémoire, dotée d’un typequi spécifie quelle sorte d’information on peut y placer. Un objet nommé s’appelle une variable.

+ Exemples :

– les entiers sont stockés dans des objets de typeint

– les réels sont stockés dans des objets de type float oudouble

– les chaînes de caractèressont stockées dans des objets de type string en C++

– etc ..

Vous pouvez vous représenter un objet comme “une boite” (une case) dans laquelle vous pouvez mettre une valeur dutype de l’objet :

Représentation d’objets

- Il est fondamentalement impossible de faire quoi que ce soit avec un ordinateur sans stocker des données en mémoire (on parle ici de la RAM).

Une instruction qui définit une variable est ... une définition!

(5)

- Une déclaration est l’action de nommer quelque chose et une définition de la faire exister. Les déclarations (situées dans des fichiers .h) sont utilisées pendant la phase de compilation et les définitions (dans les fichiers .cpp) sont indispensables à l’édition des liens pour fabriquer un exécutable.

Une définition peut (et généralement doit) fournir unevaleur initiale. Trop de programmes informatiques ont connu des bugs dûs à des oublis d’initialisation de variables. On vous obligera donc à le faire systématiquement. On appelle cela “respecter une règle de codage“. Il en existe beaucoup d’autres.

int nombreDeTours = 100; // Correct 100 est une valeur entière

string prenom = "Robert"; // Correct "Robert" est une chaîne de caractères // Mais :

int nombreDeTours = "Robert"; // Erreur : "Robert" n’est pas une valeur entière

string prenom = 100; // Erreur : 100 n’est pas une chaîne de caractères (il manque les guillemets)

Initialisation de variables

- Le compilateur se souvient du type de chaque variable et s’assure que vous l’utilisez comme il est spécifié dans sa définition.

Le C++ dispose de nombreux types. Toutefois, vous pouvez écrire la plupart des programmes en n’en utilisant que cinq :

int nombreDeTours = 100; // int pour les entiers

double tempsDeVol = 3.5; // double pour les nombres en virgule flottante (double précision) string prenom = "Robert"; // string pour les chaînes de caractères

char pointDecimal = ’.’; // char pour les caractères individuels ou pour des variables entières sur 8 bits (un octet)

bool ouvert = true; // bool pour les variables logiques (booléenes) Les types usuels en C++

- Le type string n’existe pas en langage C. Pour manipuler des chaînes de caractères en C, il faudra utiliser des tableaux que l’on verra plus tard.

#include <stdbool.h> /* pour le type bool en C */

int nombreDeTours = 100; // int pour les entiers

double tempsDeVol = 3.5; // double pour les nombres en virgule flottante (double précision) char prenom[] = "Robert"; // un tableau de caractères pour stocker les chaînes de caractères char pointDecimal = ’.’; // char pour les caractères individuels ou pour des variables

entières sur 8 bits (un octet)

bool ouvert = true; // bool pour les variables logiques (booléenes) Les types usuels en C

Nommer une variable

Un nom de variable est un nom principal (surtout pas un verbe) suffisamment éloquent, éventuellement complété par :

– une caractéristique d’organisation ou d’usage – un qualificatif ou d’autres noms

On utilisera la convention suivante :un nom de variable commence par une lettre minuscule puis les différents mots sont repérés en mettant en majuscule la première lettre d’un nouveau mot.

(6)

Exemples : distance, distanceMax,consigneCourante, etatBoutonGaucheSouris, nbreDEssais, ...

Certaines abréviations sont admises quand elles sont d’usage courant : nbre(ou nb), max, min, ...

Les lettres i,j,k utilisées seules sont usuellement admises pour les indices de boucles.

Un nom de variable doit être uniquement composé de lettres, de chiffres et de "souligné" (_). Les noms débutant par le caractère "souligné" (_) sont réservés au système, et à la bibliothèque C.

Les noms débutants par un double "souligné" (__) sont réservés aux constantes symboliques privées (#define...) dans les fichiers d’en-tête (.h).

Il est déconseillé de différencier deux identificateurs uniquement par le type de lettre (minuscule/majus- cule). Les identificateurs doivent se distinguer par au moins deux caractères, parmi les 12 premiers, car pour la plupart des compilateurs seuls les 12 premiers symboles d’un nom sont discriminants.

Les mots clés du langage sont interdits comme noms.

- l’objectif de respecter des règles de codage est d’augmenter la lisibilité des programmes en se rapprochant le plus possible d’expressions en langage naturel.

Expressions et instructions

La brique de base la plus élémentaire d’un programme est une expression. Une expression calcule une valeur à partir d’un certain nombre d’opérandes. Cela peut être une valeur littérale comme 10, ’a’, 3.14, "rouge" ou lenom d’une variable.

On utilise aussi des opérateurs dans une instruction : // calcule une aire

int longueur = 40;

int largeur = 20;

int aire = longueur * largeur; // * est l’opérateur multiplication

- Il existe de nombreux opérateurs : les opérateurs arithmétiques (+, -, *, / et %), les opérateurs relationnels (<, <=, >, >=, ==et!=), les opérateurs logiques&&(et),||(ou) et!(non), les opérateurs bits à bits & (et), | (ou) et ~ (non) ...

(7)

De manière générale, un programme informatique est constitué d’unesuite d’instructions.

Il y a plusieurs sortes d’instructions : les déclarations, les instructions d’expression, les instructions conditionnelles, les instructions itératives (boucles), etc ...

Une instruction d’expression est une expression suivie d’un point-virgule (;). Le point-virgule (;) est un élément syntaxique permettant au compilateur de “comprendre” ce que l’on veut faire dans le code (comme la ponctuation dans la langue française).

Dans les programmes comme dans la vie, il faut souvent choisir entre plusieurs possibilités. Le C/C++

propose plusieurs instructions conditionnelles: l’instruction if (choisir entre deux possibilités) ou l’instruction switch (choisir entre plusieurs possibilités).

Il est rare de faire quelque chose une seule fois. C’est pour cela que tous les langages de programmation fournissent des moyens pratiques de faire quelque chose plusieurs fois (on parle de traitement itératif).

On appelle cela une boucleou une itération.

Le C/C++ offrent plusieurs instructions itératives: la boucle while (et sa variante do ... while) et la boucle for.

Conditionner une action

La célèbre attraction du train fou est interdite aux moins de 10 ans. On souhaite écrire un programme qui demande à l’utilisateur son âge et qui, si la personne a moins de 10 ans, affiche le texte « Accès interdit » ; ce qui peut se rédiger comme cela :

Variable age : Entier age <- Lire un entier Si age < 10

Ecrire "Accès interdit"

Cela se traduit en C : int age;

scanf("%d", &age);

if (age < 10) {

printf("Accès interdit\n");

}

On écrit donc le mot-clef if, la traduction en anglais de «si», puis on met entre parenthèses la condition à tester, à savoirage < 10. On n’oublie pas de de mettre des accolades.

Ainsi, l’accès est interdit à un enfant de 8 ans :

$ ./tester-age 8

Accès interdit

À l’opposé, le programme n’affiche rien pour un âge de 13 ans :

$ ./tester-age 13

Pour exprimer la condition du « si » dans le programme, on a utilisé le symbole <, qui est l’opérateur de comparaison strictement inférieur. De manière symétrique, l’opérateur > permet de tester si un nombre

(8)

est strictement supérieur à un autre. Lorsqu’on veut tester si un nombre est inférieur ou égal à un autre, on utilise le symbole <=. De manière symétrique, le symbole >= permet de tester si un nombre est supérieur ou égal à un autre.

Par exemple, le code suivant permet de tester si la température de l’eau a atteint 100 degrés : int temperature;

scanf("%d", &temperature);

if (temperature >= 100) {

printf("L’eau bout !");

}

Pour finir, le symbole == permet de tester l’égalité et la différence avec!= . Evidemment, il ne faut surtout pas confondre avec l’opérateur = qui permet d’effectuer une affectation.

La notion de base est donc simple mais il est également facile d’utiliser if de façon trop simpliste.

Voici un exemple simple de programme de conversion cm/inch qui utilise une instructionif : int main()

{

const double conversion = 2.54; // nombre de cm pour un pouce (inch) int longueur = 1; // longueur (en cm ou en in)

char unite = 0; // ’c’ pour cm ou ’i’ pour inch

cout << "Donnez une longueur suivi de l’unité (c ou i):\n";

cin >> longueur >> unite;

if (unite == ’i’)

cout << longueur << " in == " << conversion*longueur << " cm\n";

else

cout << longueur << " cm == " << longueur/conversion << " in\n";

}

Conversion cm/inch (version 1)

En fait cet exemple semble seulement fonctionner comme annoncé. Ce programme dit que si ce n’est pas une conversion en inch c’est forcément une conversion en cm. Il y a ici une dérive sur le comportement de ce programme si l’utilisateur tape ’f’ car il convertira des cm en inches ce qui n’est probablement pas ce que l’utilisateur désirait. Un programme doit se comporter de manière sensée même si les utilisateurs ne le sont pas.

Voici une version améliorée en utilisant une instruction if imbriquée dans une instruction if : if (unite == ’i’)

cout << longueur << " in == " << conversion*longueur << " cm\n";

else if (unite == ’c’)

cout << longueur << " cm == " << longueur/conversion << " in\n";

else

cout << "Désolé, je ne connais pas cette unité " << unite << endl;

Conversion cm/inch (version 2)

De cette manière, vous serez tenter d’écrire des tests complexes en associant une instruction if à chaque condition. Mais, rappelez-vous, le but est d’écrire du code simple et non complexe.

En réalité, la comparaison d’unité à ’i’ et à ’c’ est un exemple de la forme de sélection la plus courante : une sélection basée sur la comparaison d’une valeur avec plusieurs constantes. Le C/C++ fournit pour cela l’instruction switch.

(9)

int main() {

const double conversion = 2.54; // nombre de cm pour un pouce (inch) int longueur = 1; // longueur (en cm ou en in)

char unite = 0; // ’c’ pour cm ou ’i’ pour inch

cout << "Donnez une longueur suivi de l’unité (c ou i):\n";

cin >> longueur >> unite;

switch (unite) {

case ’i’:

cout << longueur << " in == " << conversion*longueur << " cm\n";

break;

case ’c’:

cout << longueur << " cm == " << longueur/conversion << " in\n";

break;

default:

cout << "Désolé, je ne connais pas cette unité " << unite << endl;

break;

} }

Conversion cm/inch (version 3)

L’instruction switch utilisée ici sera toujours plus claire que des instructions if imbriquées, surtout si l’on doit comparer à de nombreuses constantes.

Vous devez garder en mémoire ces particularités quand vous utilisez un switch :

– la valeur utilisée pour le switch()doit être un entier, un charou une énumération (on verra cela plus tard). Vous ne pourrez pas utiliser unstring par exemple.

– les valeurs des étiquettes utilisées dans lescase doivent être des expressions constantes (voir plus loin).

Vous ne pouvez pas utiliser de variables.

– vous ne pouvez pas utiliser la même valeur dans deux case – vous pouvez utiliser plusieurs casemenant à la même instruction

– l’erreur la plus fréquente dans un switch est l’oubli d’un break pour terminer un case. Comme ce n’est pas une obligation, le compilateur ne détectera pas ce type d’erreur.

Les variables booléennes

En C/C++ le programme suivant : if (prix < 10)

{

printf("Pas cher");

}

peut aussi s’écrire :

#include <stdbool.h> /* nécessaire en C */

bool estPasCher = (prix < 10);

if (estPasCher) {

(10)

printf("Pas cher");

}

La variable estPasCher est appelée une variable booléenneou un booléen de type bool car elle ne peut être que vraie ou fausse, ce qui correspond en C/C++ aux valeurs true (pour vrai) et false (pour faux).

- N’oublier pas que le type bool est natif en C++. Par contre en C, il faut inclure stdbool.h pour pouvoir l’utiliser.

Une maladresse classique avec les booléens est de faire quelque chose comme ceci : int prix;

scanf("%d", &prix);

bool estCher = (prix > 100) if (estCher == true)

{

printf("C’est cher !");

}

Le code est correct mais on n’a pas besoin de tester si quelque chose est égal à true ou false , si ce quelque chose est lui même déjà true oufalse!

On écrira donc : if (estCher) {

printf("C’est cher !");

}

// ou :

if (!estCher) {

printf("Pas cher"));

}

Il est bien sûr possible d’utiliser des opérateurs booléens (les opérateurs && et ||) pour combiner des conditions et les valeurs booléennes sont également utilisables.

Voici quelques extraits de code à titre d’exemple : bool estSenior = (age >= 60);

bool estJeune = (age <= 25) && (age >= 12);

bool reductionPossible = (estSenior || estJeune);

if (reductionPossible) {

printf("Réduction!");

}

while (motDePasse != secret || agePersonne <= 3) {

printf("Accès refusé : mauvais mot de passe ou personne trop jeune\n");

scanf("%d %d", &agePersonne, &motDePasse);

}

(11)

while (nbPersonnes <= nbMax && temperature <= 45) {

printf("Portes ouvertes\n");

nbPersonnes = nbPersonnes + 1;

scanf("%d", &temperature);

}

Itérer une action

Le premier programme jamais exécuté sur un ordinateur à programme stocké en mémoire (l’EDSAC) est un exemple d’itération. Il a été écrit et exécuté par David Wheeler au laboratoire informatique de Cambridge le 6 mai 1949 pour calculer et afficher une simple liste de carrés comme ceci :

0 0 1 1 2 4 3 9 4 16 ...

98 9604 99 9801

Ce premier programme n’a pas été écrit en C/C++ mais le code devait ressembler à ceci : // Calcule et affiche une liste de carrés

#include <iostream>

using namespace std;

int main() {

int i = 0; // commencer à 0

// tant que i est inférieur strict à 100 : on s’arrête quand i a atteint la valeur 100 while (i < 100)

{

cout << i << ’\t’ << i * i << ’\n’; // affiche i et son carré séparés par une tabulation

++i; // on incrémente le nombre et on recommence }

return 0;

}

Le premier programme jamais écrit (version while)

Les accolades ({}) délimitent le corps de la boucle : c’est-à-dire le bloc d’instructions à répéter. La condition pour la répétition est exprimée directement dans le while. La boucle while s’exécutera 0 ou n fois.

Il existe aussi une boucle do ... while à la différence près que cette boucle sera exécutéeau moins une fois.

(12)

// faire do

{

cout << i << ’\t’ << i * i << ’\n’; // affiche i et son carré séparés par une tabulation ++i; // on incrémente le nombre et on recommence

}

while (i < 100); // tant que i est inférieur strict à 100 La boucle do .. while

Donc écrire une boucle est simple. Mais cela peut s’avérer dangereux :

– Que se passerait-il si i n’était pas initialisé à 0? Voilà une première raison qui démontre que les variables non initialisées sont une source d’erreurs courante.

– Que se passerait-il si on oubliait l’instruction ++i? On obtient une boucle infinie (un programme qui ne “répond” plus). Il faut éviter au maximum d’écrire des boucles infinies. Il est conseillé d’éviter ce type de boucle :while(1) ouwhile(true) qui sont des boucles infinies.

Itérer sur une suite de nombres est si courant en C/C++ que l’on dispose d’une instruction spéciale pour le faire. C’est l’instruction forqui très semblable à while sauf que la gestion de la variable de contrôle de boucle est concentrée sur une seule ligne plus facile à lire et à comprendre. Il existe toujours une instruction while équivalente à une instruction for.

L’instruction for concentre : une zone d’initialisation, une zone de condition et une zone d’opération d’incrémentation. N’utilisezwhile que lorsque ce n’est pas le cas.

// Calcule et affiche une liste de carrés

#include <iostream>

#include <cmath>

using namespace std;

int main() {

// exécute le bloc d’instructions de la boucle : // avec i commençant à 0 (initialisation)

// tant que i est inférieur strict à 100 (condition)

// en incrémentant i après chaque exécution du bloc d’instruction (opération d’

incrémentation)

for (int i = 0; i < 100; i++)

cout << i << ’\t’ << pow(i, 2) << ’\n’; // affiche i et son carré séparés par une tabulation

return 0;

}

Le premier programme jamais écrit (version for)

+ Ici, on utilise la fonction puissance (pow) de la bibliothèque mathématique. Pour cela, il faut inclure math.h en C ou cmath en C++ puis effectuer l’édition des liens avec l’option -lm (ce qui est fait par défaut maintenant).

(13)

Exercices : Un parcours semé d’embûches

En l’an 2132, une planète habitée a été découverte aux confins de la galaxie, et baptisée Algoréa. Dix ans plus tard, vous êtes envoyé(e) en mission autour de cette planète dans le but d’établir un tout premier contact avec ses habitants. Malheureusement, la comète Hal a percuté votre vaisseau alors que vous vous approchiez d’Algoréa. Vous avez été contraint(e) de vous éjecter en urgence dans une capsule de sauvetage. Vous atterrissez sur la planète avec pour seul bagage un robotde maintenance.

Isolé(e) sur ce globe lointain, vous allez donc rencontrer ses habitants, découvrir leurs coutumes et créer des liens afin d’entamer une relation pacifique en attendant que la prochaine mission vienne vous récupérer. Vous allez pour cela profiter des capacités de votre robot ! Celui-ci est accompagné d’un manuel, qui vous sera bien utile dans votre parcours. Ce robot est capable d’imprimer du texte, d’afficher des caractères sur un écran, de se déplacer et de bouger des objets.

Vous remarquez aussi que le manuel propose de programmer le robot à l’aide de langages, en écrivant du code sur un clavier. Une fois votre choix effectué, vous vous dirigez vers un site qui semble abriter la vie.

Grâce à votre robot, vous allez pouvoir :

– enchaîner des suites d’instructions : Dans le fourré

– répéter (itérer) des instructions : Vendanges, Course avec les enfants

– effectuer des actions sous conditions : Bornes kilométriques, Bagarre générale, Concours de tir à la corde, ,Type d’arbres, L’espion est démasqué !

– lire des entrées et produire des résultats en sortie :Calculatrice, Graduation de thermomètres, Calcul des dénivelées, Moyenne des notes, Tarif du bateau, Roue de la fortune

- Les langages C/C++ nécessitent un certain niveau de maîtrise. Il faut donc pratiquer intensément. Il n’est pas rare que les débutants commettent quelques erreurs évitables ... L’Annexe n°1 (page 27) recense les erreurs fréquentes des débutants.

Dans le fourré

Sur l’étroit chemin qui mène à la montagne, vous parvenez à une énorme porte qui vous empêche de passer. Les villageois vous ont prévenu que la clé de cette porte demeure dans le fourré qui se trouve juste à côté. Celui-ci est organisé selon des cases avec des pièges et des buissons, dont on vous a fourni le plan.

Cependant, vous n’êtes pas sûr que le plan soit tout à fait exact et vous redoutez les pièges du fourré.

Vous décidez donc d’envoyer votre robot chercher la clé pour vous.

+ Ce que doit faire votre programme :

Votre programme doit diriger votre robot dans la grille suivante :

(14)

Le robot se trouve initialement à l’entrée du fourré et doit atteindre la case où se trouve la clé sans passer par les cases où se trouvent des buissons infranchissables ni celles qui contiennent un piège . Vous n’avez pas besoin de programmer le chemin retour.

Afin que vous puissiez manipuler le robot, nous avons créé un module appelé « robot ».

Pour disposer de ces instructions en C, vous devez inclure la ligne suivante en haut de votre programme :

#include "robot.h"

Pour déplacer le robot dans le fourré, nous proposons les quatre instructions suivantes : – Aller en haut ;

– Aller en bas ; – Aller à gauche ; – Aller à droite.

Chacune demandant au robot de se déplacer d’une case dans une direction sur la grille.

En C, vous devrez les écrire comme suit : allerHaut();

allerBas();

allerGauche();

allerDroite();

- Notez bien que le robot ne tourne pas : il se déplace de case en case sur la grille, vers le haut, le bas, la gauche ou la droite.

+ Exemple :

Pour vous aider, voici en guise d’exemple un programme qui envoie le robot dans un buisson en trois déplacements.

#include <stdio.h>

#include "robot.h"

int main() {

allerHaut();

allerHaut();

allerGauche();

}

main.c

$ make

$ ./fourre 1234567 1 BBBBBBB 2 B P B 3 B B BPB 4 BRP C B 5 B BBBBB 1234567 1 BBBBBBB 2 B P B 3 BRB BPB

(15)

4 B P C B 5 B BBBBB

Le robot est entré dans un buisson !

- Pour fabriquer le programme, vous devez d’abord taper la commande make.

Question 1. Écrire le programme dans le fichier main.c. Tester et valider.

Vendanges

Par cette belle journée d’automne, vous accompagnez les villageois qui partent faire les vendanges. Vous remarquez tout de suite un homme faisant de manière répétitive des allers-retours entre les cueilleurs et la charrette qui doit être remplie à ras bord avant la fin de la journée. Cet homme tombe de fatigue et vous lui proposez de terminer le chargement. Bien évidemment, vous allez utiliser votre robot pour effectuer cette tâche à votre place.

+ Ce que doit faire votre programme : Le champ est représenté ci-dessous :

Le robot est initialement tout à gauche, là où se trouve le grand tas de raisins. Il devra, 20 fois : – ramasser des raisins pour remplir la hotte de ramassage ;

– se rendre à la charrette ;

– déposer le contenu de la hotte ; – revenir au point de départ.

Vous disposez des quatre opérations suivantes :

– int lirePosition() : Affiche et retourne la position du robot – int allerGauche(): Aller à gauche et retourne la position du robot – int allerDroite(): Aller à droite et retourne la position du robot

– int rammasser() : Ramasse du raisin sur le tas et retourne 1 si du raisin a été rammasé sinon 0 – int deposer(): Dépose du raisin sur la charette et retourne 1 si du raisin a été déposé sinon 0

A chaque fois que du raisin a été déposé quelque part, la fonction deposer()affiche l’état de la situation : T 1 2 3 4 5 6 7 8 9 10 11 12 13 14 C

19 . . . 01

Vous disposez aussi de la fonction afficherJeu() qui affichera à tout moment l’état de la situation : T 1 2 3 4 5 6 7 8 9 10 11 12 13 14 C

20 . . . 00

+ Exemples :

#include <stdio.h>

#include "robot.h"

(16)

int main() {

lirePosition();

afficherJeu();

return 0;

}

main.c

Pour fabriquer et tester le programme :

$ make Ou

$ make cheat

$ ./vendanges position : 0 (T)

T 1 2 3 4 5 6 7 8 9 10 11 12 13 14 C

20 . . . 00

Question 2. Écrire le programme dans le fichier main.c. Tester et valider.

Course avec les enfants

C’est l’heure du cours de sport et les enfants font une petite course à laquelle vous décidez d’inscrire votre robot. Le principe est simple : il faut aller chercher le premier anneau, revenir le déposer derrière la ligne, puis aller chercher le second anneau et le ramener, et ainsi de suite ... jusqu’à ce que le dixième anneau ait été ramené derrière la ligne, le but du jeu étant d’aller le plus vite possible (sans tricher bien sûr !).

+ Ce que doit faire votre programme :

Votre robot doit partir de la case de gauche (en orange, marquée D), aller chercher les anneaux (les ronds sur fond bleu) dans l’ordre (de gauche à droite) et les ramener un par un à gauche de la case de départ (en vert, marquée R).

-1 00 01 02 03 04 05 06 07 08 09 10 00 D 1 1 1 1 1 1 1 1 1 1

Vous disposez des quatre opérations suivantes :

– int lirePosition() : Affiche et retourne la position du robot – int allerGauche(): Aller à gauche et retourne la position du robot – int allerDroite(): Aller à droite et retourne la position du robot

– int rammasserAnneau(): Ramasse un anneau et retourne 1 si un anneau a été rammasé sinon 0 – int deposerAnneau() : Dépose un anneau et retourne 1 si un anneau a été déposé sinon 0

(17)

A chaque fois qu’un anneau a été déposé quelque part, la fonction deposerAnneau() affiche l’état de la situation :

01 D 0 1 1 1 1 1 1 1 1 1

Vous disposez aussi de la fonction afficherJeu() qui affichera à tout moment l’état de la situation.

+ Exemples :

#include <stdio.h>

#include "robot.h"

int main() {

lirePosition();

afficherJeu();

return 0;

}

main.c

Pour fabriquer et tester le programme :

$ make Ou

$ make cheat

$ ./anneaux position : 0 (D)

R D 01 02 03 04 05 06 07 08 09 10 00 D 1 1 1 1 1 1 1 1 1 1

Question 3. Écrire le programme dans le fichier main.c. Tester et valider.

Bornes kilométriques

Le long de la route sur laquelle vous marchez se trouvent des bornes. Sur chaque borne est écrit le nombre de kilomètres séparant la position actuelle du bout de la route. Si la borne numéro zéro se trouve derrière vous, alors les numéros augmentent au fur et à mesure que vous avancez. Au contraire, si la borne zéro se trouve devant vous, alors les numéros diminuent au fur et à mesure que vous avancez.

Vous avez noté le numéro de la borne de laquelle vous êtes parti(e) ce matin, ainsi que le numéro de la borne à laquelle vous êtes arrivé(e) ce soir. Vous souhaitez calculer la distance que vous avez parcourue dans la journée.

+ Ce que doit faire votre programme :

Votre programme doit lire deux entiers, correspondant à deux numéros de bornes kilométriques, et il doit afficher la distance séparant ces deux bornes. Notez que le résultat doit être un nombre positif ou nul.

+ Exemples :

$ gcc bornes-kilometriques.c -o bornes-kilometriques Ou :

$ g++ bornes-kilometriques.c -o bornes-kilometriques

(18)

$ ./bornes-kilometriques 152

189

Distance : 37

$ ./bornes-kilometriques 814

786

Distance : 28

Question 4. Écrire le programme bornes-kilometriques.c.

Question 5. Tester les 2 exemples donnés ci-dessus. Quel est le test qui manque pour valider le programme ?

Bagarre générale

À peine arrivé dans le village, voilà qu’une bagarre générale est sur le point d’éclater ! Tout en vous mettant à l’abri, vous tâchez de savoir ce qui se passe. On vous explique que le village est principalement composé de deux grandes familles rivales qui ne se supportent pas. Tout sujet étant une source de discorde possible, ils avaient décidé que les superficies de leurs champs respectifs ne devaient pas être trop différentes afin de ne pas attiser la jalousie de la famille opposée. Mais voilà que le patriarche des Arignon suspecte qu’un des champs des Evaran est trop grand ! Vous décidez de les aider ; mais la tâche ne sera pas facile, chacun gardant jalousement secrète la superficie réelle de ses champs.

+ Ce que doit faire votre programme :

Votre programme devra lire deux entiers, la superficie d’un champ des Arignon et la superficie d’un champ des Evaran. Si l’un des champs est plus grand d’au moins 10 m2 (strictement) que l’autre champ, alors il faudra afficher le texte « La famille X a un champ trop grand », « X » devant bien sûr être remplacé par « Arignon » ou « Evaran » selon le cas.

+ Exemples :

$ ./bagarre-generale 42

54

La famille Evaran a un champ trop grand

$ ./bagarre-generale 10

20

- Dans le second exemple, il n’y a rien à afficher.

Question 6. Écrire le programme bagarre-generale.c.

Question 7. Tester les 2 exemples donnés ci-dessus. Quel est le test qui manque pour valider le programme ?

(19)

Calculatrice

Vous êtes dans la boutique du plus grand marchand de la ville, à la recherche d’un certain nombre d’ingrédients. Malheureusement pour vous, c’est la période du grand inventaire et cela peut durer très longtemps ! Vous décidez de les aider en programmant une calculatrice.

+ Ce que doit faire votre programme :

Votre programme devra lire deux nombres entiers et une lettre représentant l’opération à effectuer (’s’

pour la somme et ’p’ pour le produit) et affichera le résultat de l’opération.

+ Exemples :

$ ./calculatrice 5 4 s

9

$ ./calculatrice 2 3 p

6

Question 8. Écrire le programme calculatrice.c. Tester et valider.

Graduation de thermomètres

Les habitants du village utilisent beaucoup de thermomètres différents : certains pour l’été, d’autres pour l’hiver, d’autres pour la température de l’eau, etc. Ce qui change d’un thermomètre à l’autre, ce sont les valeurs de la température minimale et de la température maximale lisibles sur la graduation. Les habitants aimeraient pouvoir imprimer facilement la graduation des températures possibles pour chaque thermomètre.

+ Ce que doit faire votre programme :

Étant données deux températures entièrestempMin et tempMax, votre programme doit afficher toutes les températures comprises entre les deux bornes incluses.

+ Attention, la saisie des deux bornes peut être inversée. Vous devez vous assurer que tempMin et tempMax soient valides avant d’afficher les graduations.

+ Exemples :

$ ./graduation-thermometres 9

14 9 10 11 12 13 14

$ ./graduation-thermometres 14

9 9 10 11

(20)

12 13 14

Question 9. Écrire le programme graduation-thermometres.c.

Calcul des dénivelées

Aujourd’hui c’est l’étape de montagne et vous allez devoir franchir plusieurs cols. Vous allez passer votre temps à monter, descendre, remonter, redescendre, etc... Vous décidez de noter les différentes variations d’altitudes, afin de pouvoir calculer à la fin de la journée quelle est la dénivelée totale que vous avez montée ainsi que la dénivelée totale que vous avez descendue (les deux valeurs peuvent être différentes car vous ne retournez pas à votre point de départ).

+ Ce que doit faire votre programme :

Votre programme lira d’abord un entier représentant le nombre de montées et descentes que vous avez réalisées. Pour chaque montée ou descente, il faut ensuite lire un entier représentant la variation d’altitude, cet entier étant strictement positif dans le cas d’une montée et strictement négatif dans le cas d’une descente (il n’y a rien à compter pour les tronçons qui sont bien à plat). Votre programme devra afficher l’altitude totale montée puis l’altitude totale descendue (ces deux nombres sont positifs).

+ Exemples :

$ ./calcul-denivelees 5

4 7 -6 -3 2

altitude totale montée : 13 altitude totale descendue : 9

Question 10. Écrire le programme calcul-denivelees.c en utilisant une boucle Tant Que(while).

Tester et valider.

Concours de tir à la corde

Vous avez passé la nuit dans une auberge. Au petit matin, un championnat de tir à la corde y est organisé.

Vous ne souhaitez pas participer, mais l’aubergiste insiste pour que vous soyez impliqué dans l’événement.

Vous décidez alors de vous engager dans les paris qui se font sur les deux équipes qui concourent.

Le championnat oppose deux équipes, contenant chacune autant de joueurs. Pour donner de l’allure et pimenter les paris, au début du championnat, tous les joueurs sont présentés, avec leur poids, avant d’aller tenir leur côté de la corde. Il est d’abord présenté un membre de la première équipe, puis de la deuxième, puis de la première, puis de la deuxième etc. jusqu’à ce que tous les joueurs soient passés. Afin de vous faire un premier pronostic, vous calculez le poids total de chaque équipe, avec votre robot.

+ Ce que doit faire votre programme :

Votre programme devra lire un premier entier : le nombre de membres nbMembres qui constituent une équipe. Ensuite, il devra lire les poids (en kilogrammes), au totalnbMembres × 2, sachant que le premier

(21)

poids est celui d’un joueur de la 1re équipe, le deuxième poids celui d’un joueur de la 2e équipe, le troisième la 1re équipe, le quatrième la 2e équipe, etc.

Après avoir calculé le poids total de chaque équipe, vous devrez afficher le texte « L’équipe X a un avantage » (en remplaçant X par la valeur 1 ou 2), en considérant qu’une équipe est avantagée si elle a un poids total supérieur à celui de l’autre ou « Aucune équipe a un avantage » si les deux totaux sont identiques.

Vous afficherez ensuite le texte « Poids total pour l’équipe 1 : » suivi du poids de l’équipe 1, puis « Poids total pour l’équipe 2 : » suivi du poids de l’équipe 2 (voir l’exemple ci-dessous).

+ Exemples :

$ ./tir-corde 3

40 80 50 50 60 10

L’équipe 1 a un avantage

Poids total pour l’équipe 1 : 150 Poids total pour l’équipe 2 : 140

- Chaque équipe est composée de trois joueurs. Ceux de la première pèsent 40, 50 et 60 kg, tandis que ceux de la seconde font 80, 50 et 10 kg. Cela fait 150 kg opposés à 140 kg.

Question 11. Écrire le programme tir-corde.c en utilisant une bouclePour (for).

Question 12. Tester et valider le programme. Combien de tests faut-il effectuer ?

Type d’arbres

Alors que vous traversez une forêt vous ne pouvez vous empêcher d’admirer la végétation autour de vous et notamment les nombreuses espèces d’arbres. Malgré votre intérêt, vous êtes très mauvais botaniste et avez beaucoup de mal à identifier les différents arbres. Une personne que vous croisez vous donne quelques indications et vous décidez d’écrire un programme qui vous donnera le nom de l’arbre en fonction de ses caractéristiques.

+ Ce que doit faire votre programme : Il existe 4 types d’arbres :

– le "Tinuviel" fait moins de 5 mètres de haut et ses feuilles sont composées de plus de 8 folioles – le "Calaelen" fait plus de 10 mètres de haut et ses feuilles sont composées de plus 10 folioles – le "Falarion" fait moins de 8 mètres de haut et ses feuilles sont composées de moins de 5 folioles – le "Dorthonion" fait plus de 12 mètres de haut et ses feuilles sont composées de moins de 7 folioles Votre programme lira deux entiers, la hauteur et le nombre de folioles de l’arbre, et affichera le nom de l’arbre correspondant.

- Toutes les inégalités sont à prendre au sens large, c’est-à-dire que "moins" signifie "moins ou égal" ou et "plus" signifie "plus ou égal".

+ Exemples :

(22)

$ ./type-arbre 12

12

Calaelen

$ ./type-arbre 4

9

Tinuviel

$ ./type-arbre 9

4

Inconnu

Question 13. Écrire le programme type-arbre.c. Tester et valider.

Question 14. Faut-il vraiment tester tous les cas ?

L’espion est démasqué !

Grâce à un certain nombre d’informateurs plus ou moins fiables, le chef de la police a recueilli des indications qui devraient lui permettre enfin de démasquer cet espion qui lui échappe depuis des semaines.

La population de la ville étant relativement importante, il vous demande votre aide afin d’automatiser un peu les choses. Vous devez estimer la probabilité qu’une personne soit un espion.

+ Ce que doit faire votre programme :

Votre programme doit lire le signalement d’une personne sous la forme de cinq entiers : sa taille en centimètres, son âge en années, son poids en kilogrammes, un entier valant 1 si la personne possède un cheval et 0 sinon, et un entier valant 1 si la personne à les cheveux bruns et 0 sinon.

On veut déterminer pour cette personne à quel point elle correspond aux 5 critères suivants : – il aurait au moins 34 ans ;

– il aurait une taille supérieure ou égale à 178 cm et inférieure ou égale à 182 cm ; – il pèserait strictement moins de 70 kg ;

– il n’a pas de cheval ; – il a les cheveux bruns.

- Lorsque cela n’est pas précisé explicitement, les inégalités sont au sens large (c’est-à-dire que "moins"

signifie "moins ou égal" ou et "plus" signifie "plus ou égal").

Vous devez vérifier tous les critères. S’ils sont vérifiés tous les 5, vous devez afficher « Très probable ». Si seulement 3 ou 4 sont vérifiés, vous devez afficher « Probable ». Si aucun n’est vérifié, vous devez afficher

« Impossible », et dans les autres cas, vous devez afficher « Peu probable ».

+ Exemples :

$ ./espion-demasque 180

40 65 0 1

Très probable

(23)

- Vous utiliserez des variables booléenes. Vous pouvez aussi faire preuve de simplicité dans le calcul des critères.

Question 15. Écrire le programme espion-demasque.c. Tester et valider.

Moyenne des notes

Des écoliers d’une école voisine aiment bien calculer la moyenne qu’ils vont avoir sur leur bulletin de notes avant de le recevoir. Cependant, ils ont beaucoup de notes, et ils aimeraient donc pouvoir utiliser un petit programme pour calculer leur moyenne sans se fatiguer.

Le nombre de notes dépend non seulement des matières, mais aussi des possibles absences de chacun.

Aussi, le programme doit être capable de calculer la moyenne d’un nombre arbitraire de notes. C’est pourquoi vous concevez un programme auquel il faut d’abord fournir le nombre de notes dont il faut faire la moyenne, puis fournir les notes elles-mêmes (une par une).

+ Ce que doit faire votre programme :

Votre programme doit d’abord lire un premier entier, qui décrit le nombre de notes obtenues. Ensuite, il doit lire chacune de ces notes, qui sont également des nombres entiers. Enfin, il doit afficher la moyenne (avec 2 chiffres après la virgule), les notes minimum et maximum de toutes ces notes.

+ Exemples :

$ ./moyenne-notes 3

10 11 13

Moyenne : 11.33 Minimum : 10 Maximum : 13

- Il est fortement conseillé de lire l’Annexe n°2 (page 29) qui évoque les problèmes concernant les nombres réels (float et double).

Question 16. Écrire le programme moyenne-notes.c.

Tarif du bateau

Vous venez d’apprendre qu’un concert de rock va se dérouler ce soir dans la ville située de l’autre côté du lac. Vous avez tout juste le temps d’y arriver en prenant le bateau. Cependant, vous n’êtes pas le seul à vouloir y aller, et il y a une longue queue pour acheter les tickets pour la traversée.

Comme il n’y a qu’une seule personne qui s’occupe à la fois de vendre les tickets et d’aider les gens à monter sur le bateau, vous vous rendez vite compte que vous allez certainement arriver en retard. La vente des tickets est particulièrement lente car il faut demander aux gens leur âge pour savoir s’ils doivent payer plein tarif ou bien tarif réduit.

Vous proposez que votre robot s’occupe de la vente des billets et que la personne responsable du bateau s’occupe uniquement d’aider les gens à monter sur le bateau. Il va donc vous falloir programmer votre robot assez vite pour arriver à temps au concert.

+ Ce que doit faire votre programme :

Votre programme doit lire l’âge d’une personne et le nombre de traversées indiqué sur sa carte et afficher soit « Tarif réduit », soit « Tarif plein », soit « Gratuit » suivant les cas. Vous avez le droit à une

(24)

réduction si vous avez entre 12 et 25 ans (pour les jeunes) ou si vous avez plus de 60 ans (pour lres seniors) mais, si vous n’avez pas de réduction et que vous faites plus de 50 traversées par an, alors vous avez le droit à une traversée gratuite.

+ Exemples :

$ ./tarif-bateau 27

10

Tarif plein

$ ./tarif-bateau 22

15

Tarif réduit

Question 17. Écrire le programme tarif-bateau.c.

Question 18. Tester et valider le programme. Indiquer les tests effectués.

La roue de la fortune

Lors de l’examen final à la fin de leurs études, la tradition veut que les élèves tirent un sujet au hasard.

Tirer un numéro dans un chapeau n’étant pas très amusant, ils utilisent une roue comme celle-ci, qu’ils peuvent faire tourner dans un sens ou dans l’autre.

Les enseignants, par expérience, arrivent toujours à estimer de combien de "zones" la roue va tourner et peuvent aller chercher le sujet et revenir, pendant que la roue tourne encore. Il faut, pour cela, calculer rapidement sur quelle zone le curseur va s’arrêter, en fonction du nombre de zones dont la roue va tourner.

A vous de jouer !

+ Ce que doit faire votre programme :

Votre programme doit commencer par lire un entier nbZones. Sachant que la roue va tourner denbZones zones, vous devez calculer (puis afficher) sur quelle zone le curseur va arriver.

Ainsi, si la route tourne de +2 zones alors le curseur arrive sur la zone 2, et si la roue tourne de-2 zones, alors le curseur arrive sur la zone 22.

+ Exemples :

(25)

$ ./roue-fortune 25

1

$ ./roue-fortune -50

22

- L’opérateur modulo% retourne le reste de la division euclidienne. Cet opérateur est très utilisé en informatique (nombre pair ou impair, multiple d’un nombre, intervalle, tampon circulaire ...). Le modulo sur 6 donnera toujours un nombre compris entre 0 et 5 par exemple :

0 % 6 retourne 0 1 % 6 retourne 1 2 % 6 retourne 2 6 % 6 retourne 0 7 % 6 retourne 1 8 % 6 retourne 2 ...

Question 19. Écrire le programme roue-fortune.c.

Question 20. Tester et valider le programme. Indiquer les tests effectués.

Bilan

Vous avez découvert les notions suivantes :

– lire des entrées et produire des résultats en sortie – enchaîner des suites d’instructions

– répéter (itérer) des instructions

– manipuler des variables et faire des opérations avec – effectuer des actions sous conditions

Conclusion : parce qu’il est clair que vous débutez à peine votre carrière de programmeur, n’oubliez pas qu’écrire de bons programmes, c’est écrire des programmes corrects, simples et efficaces.

Rob Pike (ancien chercheur des Laboratoires Bell et maintenant ingénieur chez Google) :

« Règle n°4 : Les algorithmes élégants comportent plus d’erreurs que ceux qui sont plus simples, et ils sont plus difficiles à appliquer. Utilisez des algorithmes simples ainsi que des structures de données simples.»

Cette règle n°4 est une des instances de la philosophie de conception KISS (Keep it Simple, Stupid dans le sens de « Ne complique pas les choses ») ou Principe KISS, dont la ligne directrice de conception préconise de rechercher la simplicité dans la conception et que toute complexité non nécessaire devrait être évitée.

(26)

Annexe 0 : printf() et scanf()

Il exste trois flux de base pour chaque programme : – stdin (0) : Entrée standard (par défaut le clavier) – stdout (1) : Sortie standard (par défaut l’écran)

– stderr (2) : Sortie erreur (par défaut l’écran également)

- En C, un flux est un canal destiné à transmettre ou à recevoir de l’information. Il peut s’agir de fichier ou de périphériques.

Pour afficher des résultats à l’écran, il faudra écrire sur le flux stdout. Pour cela, on utilise généralement la fonction printf() (déclarée dans stdio.h) :

#include <stdio.h>

printf("Hello World!\n");

// ce qui correspond à :

fprintf(stdout, "Hello World!\n");

// ou :

write(1, "Hello World!\n"); // 1 étant le descripteur de stdout Pour afficher une erreur, il est recommandé de la faire dans le flux stderr : // En C/C++

fprintf(stderr, "Ceci est une erreur.\n");

// En C++

cerr << "Ceci est une erreur.\n";

- Si on ne désire pas l’affichage des messages d’erreur d’un programme, il suffit de rediriger son flux stderr vers le périphérique null. Par exemple pour le programme a.out :

$ ./a.out 2> /dev/null

La fonction printf()(ainsi que sprintf() et fprintf()prend en argument une chaîne de format qui spécifie les types de ses autres arguments. La chaîne de format deprintf() est riche en possibilités, car elle indique non seulement le type des arguments mais aussi la manière de les écrire. Par exemple, vous pouvez choisir le nombre de chiffres après la virgule d’un nombre flottant. Chaque code spécial de la chaîne de format est précédé d’un %. Si vous voulez écrire le symbole %, vous devez l’écrire deux fois : %%. printf("%d\n", 42); // affichage d’un entier

printf("Taux de réussite : %.1f %%\n", 92.9); // Taux de réussite : 92.9 %

Chaque code spécial est découpé en plusieurs sections (les sections entre crochets sont facultatives) :

%[largeur][.precision]type

1. Largeur : nombre minimum de caractères à écrire, printf()complètera si nécessaire par des espaces sur la gauche, la valeur est alignée à droite.

2. Précision : nombre de chiffres après la virgule à écrire pour les nombres flottants, précédé d’un point.

La valeur est automatiquement arrondie : le dernier chiffre est incrémenté s’il y a besoin.

3. Type : le type de la valeur à écrire Voici les différents types utilisables :

(27)

%d int entier 32 bits en décimal

%u unsigned int entier 32 bits non signé en décimal

%x int entier 32 bits en hexadécimal (en minuscules et %X en majuscules)

%lld long long int entier 64 bits

%f float oudouble avec par défaut 6 chiffres après la virgule

%g float oudouble en utilisant la notation 1.234e5 quand cela est approprié

%c char caractère unique

%s char* chaîne de caractères

%p void* l’adresse mémoire en hexadécimal + man 3 printf

La fonction scanf() permet de lire des données sur l’entrée standard (stdin). Cette fonction prend comme premier argument une chaîne de format, qui indique combien de variables vous souhaitez lire, et de quel type. Ensuite vous donnez passer en arguments des pointeurs sur les variables qui recevront le résultat, dans l’ordre de la chaîne de format.

Prenons le cas le plus simple :

#include <stdio.h>

// lire un entier et le placer dans la variable n : int n;

scanf("%d", &n); // ne pas oubliez le & qui donne l’adresse de la variable n, c’est nécessaire ici pour que la fonction puisse modifier la variable passée en argument // lire deux entiers :

int a, b;

scanf("%d %d", &a, &b);

- La lecture des chaînes de caractère (avec scanf() en C/C++ ou cin en C++) se termine sur ce qu’on appelle un espace blanc (whitespace), c’est-à-dire le caractère espace, une tabulation ou un caractère de retour à la ligne (généralement la touche Enter ). Notez que les espaces sont ignorés par défaut. Sous Linux, vous pouvez indiquer la fin d’un flux (EOF) en combinant les touches Ctrl + d qui indiquera qu’il n’y a plus de saisie. Vous pouvez aussi stopper le programme avec Ctrl + z ou l’interrompre avec Ctrl + c .

La chaîne de format se compose de codes spéciaux indiquant le type des valeurs à lire. Chaque code est précédé du symbole %. Il en existe une multitude, nous nous contenterons ici de ceux dont vous aurez besoin :

%d int entier 32 bits en décimal

%lld long long int entier 64 bits

%f float nombre réel simple précision

%lf double nombre réel double précision

%c char caractère unique

%s char* chaîne de caractères + man 3 scanf

Annexe 1 : erreurs du débutant

, Le bug du débutant n°1 : il ne faut pas mettre un; après unif car cela exécuterait une instruction nulle si expression est vraie. Cela donne un comportement défectueux :

(28)

int a = 0;

if(a != 0); /* c’est sûrement un bug involantaire */

printf("bug : a n’est pas nul et pourtant a = %d !\n", a);

, Le bug du débutant n°2 : il ne faut pas confondre l’opérateur ’=’ (d’affectation) avec l’opérateur ’==’ (comparaison d’égalité). Cela risque de donner un comportement défectueux :

int a = 0;

if(a = 0) /* c’est sûrement un bug involantaire */

printf("a = %d : a est égal à 0\n", a);

else printf("bug : a n’est pas égal à 0 et pourtant a = %d !\n", a);

, Le bug du débutant n° 3 : il faut penser à déterminer si unbreak est nécessaire dans uncase. Le code suivant le prouve :

a = 1;

switch (a) {

case 1: printf("a = %d : a est égal à 1\n", a); /* ne faudrait-il pas un break ? */

case 2: printf("bug : a = %d : a est égal à 2 !\n", a);

}

Vous obtiendrez :

a = 1 : a est égal à 1

bug : a = 1 : a est égal à 2 !

, Le bug du débutant n°4 : il ne faut pas mettre un; après le while car cela exécuterait une instruction nulle si expression est vraie. Le code suivant sera dans uneboucle infinie sans afficher aucun message

"Salut" :

long compteur = 15;

while (compteur > 0); // c’est sûrement un bug involantaire {

printf("Salut\n");

compteur = compteur - 1;

} // ici non plus ne pas mettre de ;

, Le bug du débutant n°5 : il ne faut pas mettre un;à la fin d’un forcar cela exécuterait une instruction nulle si expression est vraie. Le code suivant n’affichera qu’un seul message "Salut" car le for boucle dans le vide :

long compteur;

for (compteur = 0; compteur < 15; compteur++); // c’est sûrement un bug involantaire {

printf("Salut\n");

}

,Le bug du débutant n°6 :il ne faut pas oublier les accolades{}à la suite d’une instruction conditionnelle if/elseou itérative for/whilesinon vous n’exécuterez qu’un seule instruction au lieu de plusieurs. Par exemple :

Si temperature >= 100 Écrire "L’eau bout !"

Écrire "Préparons le thé"

Il ne faut pas coder :

(29)

if (temperature >= 100) printf("L’eau bout !\n");

printf("Préparons le thé\n");

Si la témpérature est égale ou supérieure à 100, ce code affichera : L’eau bout !

La bonne traduction de l’algorithme est la suivante : if (temperature >= 100)

{

printf("L’eau bout !\n");

printf("Préparons le thé\n");

}

Annexe 2 : opérations sur les nombres réels

La bibliothèque C standard contient une série de fonctions de calcul sur les flottants (racine carrée, logarithme, sinus, etc.), que l’on peut utiliser en incluant le fichier math.h :fabs(), floor(), fmod(), exp(), log(), log10(), sqrt(x), pow(), sin(x), cos(x), tan(), ...

Une des différences majeures entre le traitement des entiers et des flottants est la perte de précision. Avec les entiers, les calculs sont toujours exacts, du moment que l’on ne dépasse pas la capacité des entiers.

Avec les flottants, chaque opération (addition, multiplication, etc.) induit une perte de précision. Il existe deux types de flottants en C/C++ : float et double. Les double (codés sur 8 octets) ont une meilleur précision que les float (codés sur 4 octets). Il donc est conseillé de toujours utiliser des double afin de garder la meilleure précision possible, le seul intérêt des float est qu’ils prennent deux fois moins de place en mémoire.

Si vous calculez : 1e10 + 1e-10 = 1.00000000000000000001e10, l’ordinateur arrondira à 1.00000000000000e10

= 1e10 (15 chiffres pour undouble). On a donc des cas où A + B = A même si B != 0. Il faut également faire attention à l’ordre des calculs. Par exemple A + (B - C) peut être différent de (A + B) - C. Si A = 1e-10, B = 1e10, C = 1e10, on a A + (B - C) = A + 0 = 1e-10 mais (A + B) - C = B - C = 0.

À cause des pertes de précision, les flottants sont rarement exactement égaux à leur valeur approchée, surtout si l’on utilise des fonctions comme la racine carrée, le sinus, ...

Prenons par exemple le code suivant : double x = 2.;

x = sqrt(x); // Racine carrée de x x = x * x; // x^2

if (x == 2.)

printf("OK\n");

On s’attend à voir ce programme écrire OK. Il n’en est rien ! À cause des pertes de précision, x n’est pas égal à 2 à la fin du programme, mais à un nombre presque égal à 2 et différent de 2, comme 2.0000000000000004.

On ne peut donc pas tester l’égalité entre deux nombres réels.

Pour déterminer si deux nombres réels sont égaux, il faut commencer par calculer la différence des deux nombres. Si la différence est très proche de zéro, c’est-à-dire si la valeur absolue de la différence est très petite, alors on considère que les nombres sont égaux.

(30)

Concrètement, pour comparer x et y, on commence par définir une constante très petite que l’on nomme traditionnellement epsilon, et on teste si |x - y| < epsilon. La fonction fabs() calcule la valeur absolue.

#include <math.h>

const double epsilon = 1e-10;

double x = 2.;

x = sqrt(x); // Racine carrée de x x = x * x; // x^2

if (fabs(x - 2.) < epsilon) printf("OK\n");

// pour tester si x est égal à zéro, il faut faire : if (fabs(x) < epsilon)

printf("x est égal à 0 !\n");

Références

Documents relatifs

[r]

[r]

The study focuses on phonological, orthographical, lexical, syntactical, semantic, pragmatic and tex- tual aspects and reveals the overwhelming influence of French, English and

[r]

[r]

Q 2 Il écrit ensuite sur une même ligne la suite croissante S 2 des n entiers naturels consécutifs en partant de l'entier 1 auquel il affecte le signe &#34;+&#34; puis il

Un code pour le cadenas est donc un nombre constitué de 6 chires, chacun d'entre eux provenant d'une des roues. (Les réponses aux questions suivantes devront être précisément

Zaidou tire une boule au hasard et gagne s’il sort une boule blanche.. • Djelan dit &#34;J’ai une chance sur deux