Introduction à l’algorithmique L1 MPCIE Organisation du cours Cours / TD : 35h - 2 Cours d'1h20 par semaine TP : 20h - 9 TP de 2h + 1 contrôle TP, à partir de la deuxième semaine (bâtiment G, 1er étage) - Apporter son cours en TP - Se munir d'une clef USB pour sauvegarder votre travail à la fin de chaque TP - Travail sur machine en dehors des TP conseillé Évaluation - 2 contrôles continus communs ("CCC") : CCC1 vers la Toussaint, CCC2 fin décembre - 1 contrôle continu TP ("CCTP") en décembre - 1 note de TD ("CCTD") calculée à partir d'au moins deux contrôles continus TD - Coefficients : CCC1 x2 ; CCC2 x2 ; CCTP x1 ; CCTD x1 Études en informatique à l'université d'Angers Discipline informatique Théorique analyse numérique, théorie de l'information, théorie des langages, automates, … Scientifique résolution de problèmes complexes, bio-informatique, cryptologie, intelligence artificielle, … Méthodologique analyse, langages, génie logiciel, … Technologique composants, mémoires, périphériques, … Systèmes architecture, réseaux, systèmes d'exploitation, … Applications informatique de gestion, bureautique, conception assistée par ordinateur, automatique, robotique, informatique médicale, GPS, internet, jeux vidéo, … Discipline informatique ENIAC, 1945 30 tonnes, 160 m² au sol, 5000 additions par seconde 2010-2020 Algorithmique et programmation Objectif du cours Apprentissage de l'algorithmique des et méthodes de programmation Qu'est-ce qu'un algorithme - suite finie d'opérations élémentaires permettant de résoudre un problème donné - vient du mathématicien et astronome perse Muhammad ibn al-Khawarizmi, le père de l'algèbre, qui formalisa au IXe siècle la notion d'algorithme - l'algorithme le plus célèbre est l'algorithme d'Euclide (vers 300 avant J.-C.) permettant de calculer le PGCD de deux nombres dont on ne connait pas la factorisation Étudions : - le déroulement de l'algorithme d'Euclide avec 24 et 9 - l'écriture de l'algorithme d'Euclide en pseudo-code - un algorithme déterminant si un nombre est premier Algorithmique et programmation Étapes de conception d'un programme informatique 1 – identifier le problème : quelle(s) donnée(s), quel(s) résultat(s) ? 2 – organiser les actions : écrire l'algorithme (pseudo-code, organigramme) - réfléchir aux informations à manipuler - analyser le problème et le décomposer éventuellement en sous-problèmes - rendre l'algorithme compréhensible et efficace - penser à l'utilisateur 3 – Traduire cet algorithme en langage de programmation 4 – Compiler le programme pour qu'il puisse être exécutable Un langage de programmation permet à un humain d'écrire un code pouvant être analysé par une machine puis transformé en un programme informatique. Un programme informatique est une suite d'opérations prédéterminées pouvant être exécutées par une machine. PASCAL Langage informatique utilisé en L1 : PASCAL C, C++, JAVA sont probablement les principaux langages de programmation à connaitre pour un informaticien et à apprendre lors d'un cursus informatique, mais : - Le langage C est relativement technique et plus difficile à aborder lorsque les bases de l'algorithmique ne sont pas connues - C++ et JAVA sont des langages objet, faisant appel à un paradigme de programmation plus avancé Le langage PASCAL est celui qui dispose de la syntaxe la plus claire et la plus proche du langage dit "algorithmique", même s'il est bien moins puissant que le langage C. Il a été mis au point par Pr. Niklaus Wirth dans les années 1970 dans un but pédagogique, et est en constante évolution depuis. Tous les algorithmes que nous mettrons au point cette année pourront être écrits directement en PASCAL. Principaux langages étudiés au cours de la licence (parcours informatique) L1 : PASCAL, HTML , Javascript L2 : C, JAVA, SQL, CAML, PHP L3 : C++, Assembleur Variables et constantes Une variable est un identificateur associant un nom à une valeur ou un objet. Le nom d'une variable ne doit comporter que des lettres non accentuées, des chiffres (sauf en première position) et des tirets bas. Il ne peut comporter d'espaces, de signes de ponctuation, de signes arithmétiques ou de caractères spéciaux. En PASCAL, on ne tient pas compte de la casse (majuscules / minuscules). Ce n'est pas le cas dans la plupart des autres langages de programmation. Une constante est une valeur définie au début du programme et qui reste inchangée durant toute son exécution. Les instructions de base Une affectation est une opération (instruction) permettant d'attribuer une valeur à une variable. En PASCAL, elle est symbolisée par le signe := L'identifiant de la variable est à gauche du signe d'affectation. La valeur ou plus généralement l'expression est à droite du signe d'affectation. x := 5 y2 := y + 2 * z i := i + 1 x prend la valeur 5 (au symbole x est désormais associé la valeur 5, jusqu'à ce que cette variable soit modifiée) y + 2z donne y2 (l'expression y + 2*z est évaluée et sa valeur est "rangée" dans la variable de nom y2) i prend pour valeur i+1 (i est actualisée : on ajoute 1 à la précédente valeur contenue dans la variable i) Les instructions de base L'instruction basique de lecture interrompt le programme, attend que l'utilisateur entre une valeur au clavier et stocke la valeur en mémoire dans la variable désignée en paramètres. En PASCAL : mot-clé readln suivi de la ou les variables entre parenthèses. readln(x) readln(nom,prenom,age) L'instruction basique d'écriture affiche le contenu de l'expression en paramètre. Une expression peut être une valeur, le contenu d'une variable, le résultat d'un calcul, ou la concaténation de plusieurs expressions. En PASCAL : mot-clé write suivi de l'expression entre parenthèses, ou des expressions séparées par des virgules. Une chaine de caractère doit être délimitée par des apostrophes. Remplacer write par writeln permet de passer à la ligne après l'affichage. writeln(19) write('Bonjour le monde!') write(age) writeln('Je sais que 9*9 = ',9*9) writeln() Théoriquement, toute instruction de lecture doit être précédée d'une instruction d'écriture informative. Les instructions de base En PASCAL, les instructions sont séparées par un délimiteur : le point-virgule writeln('Programme évolué de voyance par ordinateur'); write('Déclinez l''identité de la personne (nom, prénom) : '); readln(nom,prenom); write('Quel est son âge : '); readln(age); write('En quelle année sommes nous ? '); readln(annee); writeln('Ce même jour en 2020, ',prenom,' ',nom,' aura ',2020 – annee + age,' ans') Les types de base Un type définit les valeurs que peut prendre une donnée (en particulier une variable) et les opérateurs qui peuvent lui être appliqués. Types de base en programmation : - Entiers : sous-ensemble de Z ; en PASCAL : integer - Réels : sous-ensemble de D ; en PASCAL : real - Booléens : deux valeurs possibles, vrai et faux ; en PASCAL : boolean (true / false) - Caractères : lettres, chiffres, ponctuation… ; en PASCAL : char En PASCAL, une valeur de type caractère doit être mentionnée entre apostrophes. Opérateurs de calcul disponibles pour les types de base : - Entiers : + ; – ; * ; div ; mod - Réels : + ; – ; * ; / Connaitre les tables de vérité des opérateurs booléens - Booléens : and ; or ; not Opérateurs de comparaison (le résultat est un booléen) : - Entiers, réels, caractères : = ; <= ; < ; >= ; > ; <> - Booléens : = ; <> Premier programme PASCAL Un programme PASCAL débute par le mot-clé program suivi du nom du programme. Ce nom ne doit plus être réutilisé dans la suite du programme. Toutes les constantes utilisées dans le programme, et les variables utilisées dans le programme principal doivent être déclarées auparavant. La déclaration des constantes est initiée par le mot-clé const. La déclaration des variables est initiée par le mot-clé var. Le type de chaque variable doit être précisé lors de la déclaration. Les constantes ne sont pas typées. Le corps du programme principal débute par le mot-clé begin et termine par end suivi d'un point. program Calcul_TVA ; var prixTTC, prixHT, tauxTVA : real ; begin write('Quel est le prix TTC ? ') ; readln(prixTTC) ; write('Quel taux de TVA s'applique en % ? ') ; readln(tauxTVA) ; tauxTVA := tauxTVA / 100 ; prixHT := prixTTC / (1 + tauxTVA) ; writeln('Le prix HT est de ',prixHT) ; writeln('Le montant de la TVA est de ',prixTTC * tauxTVA) end. Premier programme PASCAL Un programme PASCAL débute par le mot-clé program suivi du nom du programme. Ce nom ne doit plus être réutilisé dans la suite du programme. Toutes les constantes utilisées dans le programme, et les variables utilisées dans le programme principal doivent être déclarées auparavant. La déclaration des constantes est initiée par le mot-clé const. La déclaration des variables est initiée par le mot-clé var. Le type de chaque variable doit être précisé lors de la déclaration. Les constantes ne sont pas typées. Le corps du programme principal débute par le mot-clé begin et termine par end suivi d'un point. program Calcul_TVA ; var prixTTC, prixHT, tauxTVA : real ; Avec un meilleur affichage begin write('Quel est le prix TTC ? ') ; readln(prixTTC) ; write('Quel taux de TVA s'applique en % ? ') ; readln(tauxTVA) ; tauxTVA := tauxTVA / 100 ; Nombre minimal de caractères affichés (avec alignement à droite) prixHT := prixTTC / (1 + tauxTVA) ; writeln('Le prix HT est de ',prixHT:4:2) ; writeln('Le montant de la TVA est de ',(prixTTC * tauxTVA):4:2) end. Précision de l'arrondi (chiffres après la virgule) Premier programme PASCAL Un programme PASCAL débute par le mot-clé program suivi du nom du programme. Ce nom ne doit plus être réutilisé dans la suite du programme. Toutes les constantes utilisées dans le programme, et les variables utilisées dans le programme principal doivent être déclarées auparavant. La déclaration des constantes est initiée par le mot-clé const. La déclaration des variables est initiée par le mot-clé var. Le type de chaque variable doit être précisé lors de la déclaration. Les constantes ne sont pas typées. Le corps du programme principal débute par le mot-clé begin et termine par end suivi d'un point. program Calcul_TVA ; var prixTTC, prixHT, tauxTVA : real ; begin write('Quel est le prix TTC ? ') ; readln(prixTTC) ; write('Quel taux de TVA s'applique en % ? ') ; readln(tauxTVA) ; tauxTVA := tauxTVA / 100 ; prixHT := prixTTC / (1 + tauxTVA) ; writeln('Le prix HT est de ',prixHT) ; writeln('Le montant de la TVA est de ',prixTTC * tauxTVA) end. La présentation du code est importante. La plupart des espaces (hormis celles séparant les mots-clés, variables ou valeurs), les tabulations et les sauts de ligne n'ont aucun effet sur le programme mais sont parfois indispensables pour la lisibilité du code. Premier programme PASCAL Un programme PASCAL débute par le mot-clé program suivi du nom du programme. Ce nom ne doit plus être réutilisé dans la suite du programme. Toutes les constantes utilisées dans le programme, et les variables utilisées dans le programme principal doivent être déclarées auparavant. La déclaration des constantes est initiée par le mot-clé const. La déclaration des variables est initiée par le mot-clé var. Le type de chaque variable doit être précisé lors de la déclaration. Les constantes ne sont pas typées. Le corps du programme principal débute par le mot-clé begin et termine par end suivi d'un point. program Calcul_TVA ; const tauxTVA = 0.196 ; var prixTTC, prixHT : real ; begin write('Quel est le prix TTC ? ') ; readln(prixTTC) ; prixHT := prixTTC / (1 + tauxTVA) ; writeln('Le prix HT est de ',prixHT) ; writeln('Le montant de la TVA est de ',prixTTC * tauxTVA) end. Version avec TVA connue Premier programme PASCAL Un programme PASCAL débute par le mot-clé program suivi du nom du programme. Ce nom ne doit plus être réutilisé dans la suite du programme. Toutes les constantes utilisées dans le programme, et les variables utilisées dans le programme principal doivent être déclarées auparavant. La déclaration des constantes est initiée par le mot-clé const. La déclaration des variables est initiée par le mot-clé var. Le type de chaque variable doit être précisé lors de la déclaration. Les constantes ne sont pas typées. Le corps du programme principal débute par le mot-clé begin et termine par end suivi d'un point. Commentaire de fin de ligne program Calcul_TVA ; Avec commentaires const tauxTVA = 0.196 ; // On fixe la TVA à 19,6% var prixTTC, prixHT : real ; {Début du programme principal} Bloc de commentaire begin write('Quel est le prix TTC ? ') ; readln(prixTTC) ; prixHT := prixTTC / (1 + tauxTVA) ; writeln('Le prix HT est de ',prixHT) ; writeln('Le montant de la TVA est de ',prixTTC * tauxTVA) end. La conditionnelle Les instructions d’affectation, de lecture et d’écriture sont des instructions séquentielles. Une instruction conditionnelle permet d’exécuter ou non un bloc d’instructions selon le résultat d’un test (choix binaire). if <condition> then <instruction1> else <instruction2> Conditionnelle complète (if… then…else) Si la condition est vérifiée, alors on exécute l’instruction 1, sinon on exécute l’instruction 2 if <condition> then <instruction1> Conditionnelle incomplète (if… then) Si la condition est vérifiée, alors on exécute l’instruction 1 [sinon on ne fait rien] Un bloc d’instructions (suite d’instructions séparées par des points-virgules et encadrées par begin et end) peut remplacer une simple instruction. if <condition> then begin <instruction1> ; <instruction2> end else <instruction3> Bloc d’instructions La conditionnelle Comme une conditionnelle est elle-même une instruction, il peut y avoir une ou plusieurs conditionnelles à l’intérieur d’une conditionnelle. On parle de conditionnelles imbriquées. if <condition1> then if <condition2> then <instruction1> else <instruction2> else <instruction3> En PASCAL, le point-virgule est un séparateur d’instructions. Il ne faut donc jamais mettre un point-virgule juste devant le mot-clé else. Une condition est une expression booléenne, dont la valeur est soit vraie, soit fausse. X not X X = true X = false (note >= 0) and (note <= 20) not ((note >=0) and (note<=20)) (note < 0) or (note > 20) (i < valeurMax) and (not trouve) Programmes à écrire : 1 – Parité d’un nombre 2 – Calcul booléen avec l’opérateur XOR Une condition peut-être de la forme : (<condition1>) <and/or> (<condition2>) not (<condition>) La conditionnelle Il faut éviter d’imbriquer un trop grand nombre de conditionnelles (problèmes de lisibilité à partir de 3 / 4 niveaux. L’instruction case…of permet d’éviter certaines imbrications de conditionnelles, et permet de traiter directement des choix qui ne sont plus binaires. Elle est réservée à des conditions bien précises (égalité variable - constantes). case <variable> of <ensembleDeValeurs1> : <instruction1> ; <ensembleDeValeurs2> : <instruction2> ; … <ensembleDeValeursN> : <instructionN> else <instruction0> end - un ensemble de valeurs est une valeur constante, ou plusieurs valeurs constantes séparées par des virgules - le else est facultatif - chaque instruction peut être un bloc d’instructions Exercice : écrire un programme qui donne le nombre de jours dans un mois. La conditionnelle program appreciation_automatique ; var note : integer ; begin writeln(’Quelle est la note obtenue ? ’) ; readln(note) ; case note of 20 : writeln(’Parfait !’) ; 18,19 : writeln(’Excellent’) ; 16,17 : writeln(’Très bien’) ; 14,15 : writeln(’Bien’) ; 10..13 : writeln(’Passable’) ; 0..9 : begin writeln(’Insuffisant’) ; writeln(’Il aurait fallu travailler !’) end else writeln(’Note invalide’) end end. Instruction répétitive Une boucle permet d’effectuer un traitement à plusieurs reprises. Il existe plusieurs types de boucles : - la boucle TANT QUE - la boucle REPETER (ou boucle JUSQU’À CE QUE) - la boucle POUR (extension de la boucle TANT QUE) Principe de la boucle TANT QUE : TANT QUE la condition est vraie : - on effectue l’instruction (ou le bloc d’instructions) - on revient au début de la boucle Lorsque la condition est fausse, on passe à l’instruction suivante. while <condition> do <instruction> while <condition> do begin <instruction1> ; <instruction2> end Instruction répétitive program tours_de_boucle ; var n : integer ; begin n := 0 ; while n < 3 do begin writeln('Un tour... ') ; n := n + 1 end ; writeln('Fini !') end. Exercices : 1 – Quel est l’affichage produit par le programme tours_de_boucle ? 2 – Écrire l’algorithme d’Euclide en PASCAL (pgcd de deux nombres entiers) Instruction répétitive program tours_de_boucle ; var n : integer ; begin n := 0 ; while n < 3 do begin writeln('Un tour... ') ; n := n + 1 end ; writeln('Fini !') end. Exercices : 1 – Quel est l’affichage produit par le programme tours_de_boucle ? 2 – Écrire l’algorithme d’Euclide en PASCAL (pgcd de deux nombres entiers) Instruction répétitive La boucle TANT QUE : while <condition> do <traitement> • La condition doit finir par devenir fausse (on répète le traitement tant que la condition est vraie) • Si la condition est fausse à la première exécution, le traitement n’est jamais réalisé. La boucle RÉPÉTER : repeat <traitement> until <condition> • En PASCAL, la boucle RÉPÉTER est de type RÉPÉTER…JUSQU’À • La condition doit finir par devenir vraie (on répète le traitement jusqu’à ce que la condition soit vraie, i.e. tant que la condition est fausse) • Le traitement est réalisé au moins une fois, car le test est effectué après. repeat writeln(’saisir la note’); readln(note) until (note >= 0) and (note <= 20) Remarque : pas de begin/end car le bloc d’instructions à répéter est déjà encadré par repeat et until. Instruction répétitive Propriété : TANT QUE et RÉPÉTER ont le même pouvoir expressif. Preuve : varbool := false; repeat <traitement> until <condition> while not varbool do begin <traitement> varbool := <condition> end if <condition> then while <condition> do <traitement> repeat <traitement> until not <condition> Instruction répétitive La boucle POUR (for) La boucle POUR permet d’effectuer un traitement à plusieurs reprises en incrémentant ou décrémentant automatiquement une variable entière. for <nomVarBoucle> := <exprInf> to <exprSup> do <traitement> Boucle POUR croissante for <nomVarBoucle> := <exprSup> downto <exprInf> do <traitement> Boucle POUR décroissante • <nomVarBoucle> est une variable de type entier (integer) qui ne doit théoriquement jamais être modifiée dans le traitement. • <exprInf> et <exprSup> sont des expressions entières (variables, constantes, résultats d‘un calcul). • <traitement> est une instruction ou une suite d’instructions séparées par begin / end. sommeChiffres := 0; sommeChiffres := 0; for i := 1 to 9 do for i := 9 downto 1 do sommeChiffres := sommeChiffres + i; sommeChiffres := sommeChiffres + i; Instruction répétitive Une boucle POUR croissante (for...to...do) exécute un traitement pour chaque valeur entière comprise entre deux bornes, dans l’ordre croissant (la variable de boucle prend successivement chacune de ces valeurs). for i:=1 to 5 do write(i,' ') 1 2 3 4 5 Une boucle POUR décroissante (for...downto...do) fait la même chose dans l’ordre inverse (la variable de boucle prend successivement chaque valeur de l’intervalle dans l’ordre décroissant). for i:=5 downto 1 do write(i,' ') 5 4 3 2 1 Une boucle POUR est un cas particulier d'une boucle TANT QUE : for i:= MIN to MAX do <traitement> Quelques cas particuliers : i:= MIN; while (i<=MAX) do begin <traitement>; i:=i+1 end; i:=i-1 for i:= N1 to N2 do <traitement> Si N1 = N2, une seule itération avec i=N1 Si N1 > N2, aucune itération (mais correct) for i:= N1 downto N2 do <traitement> Si N1 = N2, une seule itération avec i=N1 Si N1 < N2, aucune itération (mais correct) Instruction répétitive program sommeEntiers; var n,i,somme : integer; begin writeln('Somme des n premiers entiers'); repeat writeln('Entrez n (> 0)'); readln(n) until n > 0; somme:=0; for i:=1 to n do somme:=somme+i; writeln('La somme des ',n,' premiers entiers est ',somme) end. Tableaux Un tableau est une structure de données regroupant un ensemble de variables de même type. Exemple de tableau d’entiers de dimension 8, indicé de 1 à 8 5 0 2 19 -5 2 1 8 T[1] T[2] T[3] T[4] T[5] T[6] T[7] T[8] La variable T est de type tableau d’entiers indicé de 1 à 8. On accède aux valeurs du tableau par T[1], T[2], …, T[8]. L’indice doit être une expression entière (constante, variable, calcul). Tableaux Déclaration d’une variable de type tableau : Syntaxe : var <NomVar> : array [<const1>..<const2>] of <type>; Cette syntaxe est fonctionnelle mais déconseillée dans le cas général. Lors de l’utilisation de types structurés comme des tableaux, il est préférable de commencer par définir le type lui-même (par exemple : type tableau d’entiers indicé de 1 à 8). On pourra alors utiliser plusieurs variables correspondant à ce même type. Déclaration d’un type structuré : Syntaxe : type <NomType> = <typeStructuré>; Exemple : type TabEntier = array [1..8] of integer; var T1, T2 : TabEntier; Tableaux Utilisation d’un tableau : Chaque T[i] se comporte comme une variable classique. T[i+1]:=5 readln(T[3]) writeln(’La ’,x,’e valeur est ’,T[x]) if T[T[1]+T[2]] = T[1] + T[2] then writeln(’coup de chance’) Les instructions de lecture, écriture peuvent s’appliquer à chacun des éléments mais pas au tableau tout entier. readln(T) writeln(T) Il faut saisir ou afficher les éléments un par un, en utilisant une boucle. Tableaux program reaffichage; const Nmax=100; {limite de taille du tableau} type Tent = array[1..Nmax] of integer; {déclaration du type Tent} var T : Tent; {le tableau} n : integer; {nombre d’éléments à saisir} i : integer; {indice pour parcourir le tableau} begin write(’Combien de valeurs (<’,Nmax,’) ? ’); readln(n); i:=1; while i<=n do begin write(’Donner le ’,i,’eme element: ’); readln(T[i]); i:=i+1 end; writeln(’Vous venez de saisir les valeurs suivantes : ’); i:=1; while i<=n do begin write(T[i],’ ’); i:=i+1 end end. Tableaux program reaffichage; const Nmax=100; {limite de taille du tableau} La taille du tableau est constante type Tent = array[1..Nmax] of integer; {déclaration du type Tent} var T : Tent; {le tableau} n : integer; {nombre d’éléments à saisir} La taille utile du tableau peut varier i : integer; {indice pour parcourir le tableau} begin write(’Combien de valeurs (<’,Nmax,’) ? ’); readln(n); i:=1; while i<=n do begin write(’Donner le ’,i,’eme element: ’); readln(T[i]); i:=i+1 end; writeln(’Vous venez de saisir les valeurs suivantes : ’); i:=1; while i<=n do begin write(T[i],’ ’); i:=i+1 end end. Tableaux program reaffichage; const Nmax=100; {limite de taille du tableau} type Tent = array[1..Nmax] of integer; {déclaration du type Tent} var T : Tent; {le tableau} n : integer; {nombre d’éléments à saisir} i : integer; {indice pour parcourir le tableau} begin write(’Combien de valeurs (<’,Nmax,’) ? ’); readln(n); Utilisation de la boucle for for i:=1 to n do begin write(’Donner le ’,i,’eme element: ’); readln(T[i]) end; writeln(’Vous venez de saisir les valeurs suivantes : ’); for i:=1 to n do write(T[i],’ ’); end. Tableaux program minTableau; const TAILLEMAX = 1000; type tabEntiers = array[1..TAILLEMAX] of integer; var n, i, min : integer; T : tabEntiers; begin {Saisie des valeurs} repeat writeln('Combien de valeurs à saisir ? (entre 1 et ',TAILLEMAX,')'); readln(n) until (n >= 1) and (n <= TAILLEMAX); for i:=1 to n do readln(T[i]); {Calcul puis affichage du minimum} min:=T[1]; for i:=2 to n do if min > T[i] then min:=T[i]; writeln('Valeur minimum : ',min) end. Tableaux à deux dimensions program saisie_matrice; const Lmax=100; Cmax=100; type matrice = array[1..Lmax,1..Cmax] of real; var M : matrice; n1,n2 : integer; i,j : integer; begin write(’Combien de lignes (<’,Lmax,’) ? ’); readln(n1); write(’Combien de colonnes (<’,Cmax,’) ? ’); readln(n2); i:=1; while i<=n1 do begin j:=1; while j<=n2 do begin write(’Donner l’’element [’,i,’,’,j,’] : ’); readln(M[i,j]); j:=j+1 end; i:=i+1 end {...traitement éventuel sur les données} end. Chaines de caractères Une chaine de caractère (en anglais : string) est un type structuré similaire à un tableau de caractères, et représentant une suite de caractères. Il est prédéfini dans la plupart des langages de programmation et associé à des fonctions spécifiques qui permettent de les manipuler plus simplement. Déclaration : var <NomVar> : string var <NomVar> : string[<const2>] La taille n’est pas précisée (valeur par défaut : 255 caractères) La taille maximale de la chaine est précisée Le nombre de caractères d’une chaine est accessible via la fonction length(<NomVar>). Elle représente sa taille utile. D’autres fonctions permettant de manipuler les chaines seront vues plus tard. Contrairement aux tableaux, les chaines de caractères peuvent être lues et affichées au même titre que les caractères qui les composent. s B o n j o u r S[1] S[2] S[3] S[4] S[5] S[6] S[7] length(S) = 7 Chaines de caractères program exemple_chaines; var s,nom : string; tel : string[10]; begin write(’Comment vous appelez-vous ?’); readln(nom); s := ’Bonjour’; writeln(s,’ ’,nom); writeln(’L’’initiale de votre nom est ’,nom[1]); writeln(’Votre nom est composé de ’,length(nom),’ lettres’) writeln(’Entrez votre numéro de téléphone’); readln(tel); {…} end. Opérations de base sur les chaines : Concaténation : ‘Bon’ + ‘jour’ ‘Bonjour’ Comparaison : ‘Un’ < ‘Deux’ false Tous les opérateurs de comparaison habituels sont disponibles : < ; > ; <= ; >= ; = ; <> Sous-programmes Un langage possède un nombre d’instructions limitées. Comment créer de nouvelles instructions ? La plupart des problèmes sont compliqués à résoudre et nécessitent d’être décomposés en sous-problèmes. Comment définir et utiliser des sous-programmes permettant de résoudre des sousproblèmes ? Un sous-programme est un bloc d’instructions séparé du bloc principal permettant de résoudre un sous-problème. On peut appeler un sous-programme dans le programme principal ou dans un autre sous-programme. Décomposition Pour résoudre un problème, on isole chaque sous-problème en déterminant ses entrées (données) et ses sorties (résultats). Un sous-problème est un problème et peut être décomposé. Un sous-programme peut donc utiliser d’autres sous-programmes. Sous-programmes Déclaration d’un sous-programme En PASCAL, la déclaration d’un sous-programme comprend : • sa catégorie (fonction ou procédure) • son nom • ses paramètres formels Elle est suivie par la déclaration de ses variables locales et un bloc d’instructions. Les variables locales déclarées dans un sous-programme ne sont pas visibles hors du sousprogramme. Appel / exécution d’un sous-programme Un sous-programme est exécuté par le programme principal ou un autre sous-programme par appel de son nom et de ses paramètres effectifs. Sous-programmes Nature des paramètres Une donnée est une valeur transmise au sous-programme et utilisée par celui-ci. Une donnée n’est jamais modifiée par le sous-programme. Un résultat est une valeur que le sous-programme transmet au programme ou sous-programme qui l’appelle. Une donnée modifiée est à la fois donnée et résultat. Il s’agit d’une donnée que le sousprogramme peut modifier dans le but d’être retransmise au programme qui l’appelle. Les paramètres résultats et données modifiées sont des variables, non initialisées (résultats) ou initialisées (données modifiées). Catégories de sous-programmes Une fonction : sous-programme typé qui retourne un résultat à partir d’un certain nombre de données (pas de données modifiées ni de paramètre résultat qui peut-être considéré comme la fonction elle-même). Une procédure : sous-programme non typé qui utilise un nombre libre de données, résultats et données modifiées, mais ne retourne pas à proprement parler un résultat. Sous-programmes : fonctions Une fonction calcule une valeur à partir de 0, 1 ou plusieurs données en paramètre. Déclaration d’une fonction. function nomFonction(donnee1:type1; donnee2:type2; … ; donneeN:typeN):typeResultat; var …; {déclaration des variables locales} begin … {bloc d’instructions} end; Les paramètres sont uniquement des données, et le résultat n’est pas considéré comme un paramètre. Pour retourner un résultat, la fonction doit contenir au moins une instruction de type nomFonction:=…; En PASCAL, dans le bloc d’instruction de la fonction, le nom de la fonction s’utilise comme une variable du type de la fonction.. Sous-programmes : fonctions Appel d’une fonction (dans un autre bloc d’instructions) … nomFonction(val1,val2,…,valN)…; • une fonction appelée doit être préalablement déclarée • une fonction doit être appelée à l’intérieur d’une instruction (elle ne constitue pas une instruction en tant que telle). Par exemple : x := mafonction(a,b,c) avec x du même type que mafonction(p1,p2,p3) et le ième paramètre effectif même type que le ième paramètre formel de la fonction. Lors de l’appel, la fonction s’exécute avec comme paramètres (données) les valeurs des paramètres effectifs. Après exécution de la fonction, sa valeur calculée (résultat) remplace l’appel de la fonction dans l’instruction où elle a été effectuée. L’appel d’une fonction correspond à une expression dont on évalue la valeur. Sous-programmes : fonctions program testmin; function min(x: integer; y: integer):integer; begin if x<y then min:=x else min:=y; end; var a, b: integer; begin write(‘Entrer deux valeurs: ’); readln(a); readln(b); writeln(‘Le min est : ’,min(a,b)); end. Sous-programmes : fonctions Important • L’ordre des paramètres doit être bien respecté lors de l’appel de la fonction • On ne modifie jamais les paramètres dans une fonction • Il n’y a pas de lecture des données dans la fonction ; elles sont passées en paramètres • Il n’y a pas à afficher le résultat dans la fonction Attention à la distinction entre paramètres formels et paramètres effectifs Paramètres formels lors de la déclaration : f:NN f(x) = x² Paramètres effectifs lors de l’exécution : f(3) f(a) avec a=5 f(x) avec x=1 Sous-programmes : procédures Une procédure peut être considérée comme une fonction ne renvoyant pas de valeur. En PASCAL, des paramètres peuvent être modifiés uniquement dans des procédures (données modifiées et résultats). Une procédure peut également avoir des données en paramètres, non modifiables. L'appel à une procédure est une instruction en tant que telle. Déclaration d’une procédure procedure nomProc(param1:type1; var param2:type2; …); var …; {déclaration des variables locales} begin … {bloc d’instructions} end; Les paramètres peuvent être des données, des données modifiées ou des résultats. Les données modifiées et résultats sont précédés par le mot-clé var. Une procédure n'a pas de type associé. Il ne doit jamais y avoir d'instruction du genre nomProc:=…; Sous-programmes : procédures Appel d’une procédure (dans un autre bloc d’instructions) nomProc(val1,val2,…); • une procédure appelée doit être préalablement déclarée • les données en paramètres doivent être des expressions (valeur, variable, résultat d'un calcul ou d'une fonction) correspondant aux types déclarés • les données modifiées et résultats (var lors de la déclaration, mais pas lors de l'appel) correspond obligatoirement à une variable correspondant au type déclaré • l'ordre des paramètres doit être bien respecté lors de l'appel de la procédure Sous-programmes : procédures program testajoute; procedure ajoute(var x: integer; y: integer); begin x := x+y; end; var a, b: integer begin readln(a); readln(b); ajoute(a, b); writeln(a, b); end. Sous-programmes : synthèse Procédure ou fonction ? • des données doivent être modifiées : PROCÉDURE • des données vont être saisies ou modifiées : PROCÉDURE • un ensemble de résultats va être produit : PROCÉDURE • calculer un résultat à partir d'un ensemble de données : FONCTION • pouvoir utiliser le sous-programme dans une expression : FONCTION Décomposition Les sous-programmes permettent de séparer des tâches indépendantes. Il faut en particulier séparer les interactions avec l'utilisateur des opérations de calcul. Un sous-programme qui réalise un calcul pour produire un ou plusieurs résultats n'a pas à interagir avec l'utilisateur pour lui demander des informations. Un sous-programme réalise un traitement à partir de ses paramètres, et non sur des valeurs demandées à l'utilisateur. La demande d'information ou l'affichage des résultats se fera dans des sous-programmes dédiés. Réutilisation Les sous-programmes peuvent être utilisés plusieurs fois au cours de l'exécution du programme, ou même jamais. Sous-programmes : exemple Températures hebdomadaires On souhaite réaliser un programme calculant, à partir des relevés de températures sur une semaine de deux villes, laquelle a la température moyenne la plus élevée. Définir un type permettant de stocker les températures hebdomadaires d'une ville Écrire un sous-programme calculant la moyenne des températures de la semaine Écrire un sous-programme permettant la saisie des températures hebdomadaires d'une ville Écrire un sous-programme déterminant, parmi deux villes, celle qui a la température moyenne la plus élevée Écrire le programme principal permettant de réaliser les traitements Sous-programmes : exemple Définir un type permettant de stocker les températures hebdomadaires d'une ville const NBJOURS=7; type TableauTemp=array[1..NBJOURS] of real; Sous-programmes : exemple Écrire un sous-programme calculant la moyenne des températures de la semaine function moyenne(t: TableauTemp): real; var somme: real; i: integer; begin somme := 0; i := 1; while i<= NBJOURS do begin somme := somme + t[i]; i := i+1; end; moyenne := somme / NBJOURS; end; Sous-programmes : exemple Écrire un sous-programme permettant la saisie des températures hebdomadaires d'une ville function jour(j:integer):string; begin case j of 1: jour:='dimanche'; 2: jour:='lundi'; 3: jour:='mardi'; 4: jour:='mercredi'; 5: jour:='jeudi'; 6: jour:='vendredi'; 7: jour:='samedi' end end; procedure saisie(var t: TableauTemp); var i: integer; begin for i:=1 to NBJOURS do begin writeln(’Temperature de ’,jour(i)); readln(t[i]) end end; Sous-programmes : exemple Écrire un sous-programme déterminant, parmi deux villes, celle qui a la température moyenne la plus élevée function moyennePlusElevee(v1: string; t1: TableauTemp; v2: string; t2: TableauTemp): string; begin if moyenne(t1) > moyenne(t2) then moyennePlusElevee := v1 else moyennePlusElevee := v2; end; Sous-programmes : exemple Écrire le programme principal permettant de réaliser les traitements var t1, t2: TableauTemp; v1, v2: string; begin writeln(’Ville 1’); readln(v1); saisie(t1); writeln(’Ville 2’); readln(v2); saisie(t2); write(moyennePlusElevee(v1,t1,v2,t2),’ a une temperature plus elevee’); end. Annexe : Conversion binaire / décimal Pour représenter un nombre entier naturel, il faut disposer de symboles appelés chiffres. Tout nombre entier N peut être exprimé dans la base b à l’aide de b chiffres distincts allant de 0 à b-1 sous la forme : k 1 N b ai b i , où chaque ai est un chiffre. i 0 k est un nombre de chiffres suffisant pour écrire N dans la base b. Dans la base b, N s’écrit ak-1ak-2…a1a0. 197510 = 1 x 1000 + 9 x 100 + 7 x 10 + 5 = 1 x 103 + 9 x 102 + 7 x 101 + 5 x 100 chiffres {0, …, 9} Compter en base 2 : 0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, … Compter en base 3 : 0, 1, 2, 10, 11, 12, 20, 21, 22, 100, 101, 102, 110, 111, 112, 120, … Compter en base 10 : 0, 1, 2, 3, …, 9, 10, 11, 12, 13, …, 99, 100, 101, 102, 103, … Compter en base 16 : 0, 1, 2, …, 9, A, B, C, D, E, F, 10, 11, 12, …, 1F, 20, 21, …, FF, 100, … Annexe : Conversion binaire / décimal Conversion d’un nombre de la base 2 vers la base 10 (binaire décimal) : 110012 = 1 x 24 + 1 x 23 + 0 x 22 + 0 x 21 + 1 x 20 = 1610 + 810 + 110 = 2510 20 21 22 23 24 25 26 27 28 29 210 211 212 213 214 215 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 Table des puissances de 2 Conversion d’un nombre de la base 10 vers la base 2 (décimal binaire) : Il suffit d’effectuer des divisions euclidiennes successives du nombre par 2, et d’écrire les restes dans l’ordre inverse. 13 1 2 6 0 2 3 1 2 1 1 2 0 Annexe : Conversion binaire / décimal Conversion d’un nombre de la base 2 vers la base 10 (binaire décimal) : 110012 = 1 x 24 + 1 x 23 + 0 x 22 + 0 x 21 + 1 x 20 = 1610 + 810 + 110 = 2510 20 21 22 23 24 25 26 27 28 29 210 211 212 213 214 215 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 Table des puissances de 2 Conversion d’un nombre de la base 10 vers la base 2 (décimal binaire) : Il suffit d’effectuer des divisions euclidiennes successives du nombre par 2, et d’écrire les restes dans l’ordre inverse. 13 1 2 6 0 2 3 1 2 1 1 2 0 1310 = 11012 (= 8+4+1) somme de puissances de 2 Annexe : Conversion binaire / décimal Conversion d’un nombre de la base 2 vers la base 10 (binaire décimal) : 110012 = 1 x 24 + 1 x 23 + 0 x 22 + 0 x 21 + 1 x 20 = 1610 + 810 + 110 = 2510 20 21 22 23 24 25 26 27 28 29 210 211 212 213 214 215 1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 Table des puissances de 2 Conversion d’un nombre de la base 10 vers la base 2 (décimal binaire) : Il suffit d’effectuer des divisions euclidiennes successives du nombre par 2, et d’écrire les restes dans l’ordre inverse. 13 1 2 6 0 2 3 1 2 1 1 2 0 1310 = 11012 (= 8+4+1) somme de puissances de 2 N 167 83 41 20 10 5 2 1 Q 83 41 20 10 5 2 1 0 R 1 1 1 0 0 1 0 1 Le chiffre (bit en base 2) le plus significatif est le reste de la dernière division. Le chiffre (bit) le moins significatif est le reste de la première division. 16710 = 101001112 (= 128+32+4+2+1)