IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Algorithmes et programmation en Pascal


précédentsommairesuivant

I. Les variables en Pascal

I-1. Premiers programmes

I-1-1. Le programme bonjour

Un programme est une suite d'instructions, certaines étant des mots clés. Ce programme affiche la chaîne de caractères Bonjour à l'écran :

 
Sélectionnez
PROGRAM bonjour;
BEGIN
	writeln ('Bonjour');
END.

Le compilateur est un logiciel qui lit (analyse) un programme et le traduit en code machine, directement exécutable par le processeur de l'ordinateur.

I-1-2. Commentaires dans un programme

On place un {commentaire} dans un programme au-dessus ou à coté d'une instruction.
Le commentaire n'est pas pris en compte à la compilation. Il sert à rendre le programme plus clair à la lecture, à noter des remarques, etc :

 
Sélectionnez
{ Edouard Thiel - 21/01/2003 }
PROGRAM bonjour;
BEGIN
{ Affiche Bonjour à l'écran }
   writeln ('Bonjour');
END.

I-1-3. Utilisation d'une variable entière

Une variable est une zone dans la mémoire vive de l'ordinateur, dotée d'un nom et d'un type. Le nom de la variable permet d'accéder au contenu de la zone mémoire ; le type spécifie la nature de ce qui peut être stocké dans la zone mémoire (entier, réel, caractère, etc).
On a coutume de représenter une variable par une boîte ; dessous on met le nom, au dessus le type, et dans la boîte le contenu.
Exemple avec une variable de nom a et de type entier :

 
Sélectionnez
PROGRAM var_entiere;
VAR
    a : integer; { Déclaration }
BEGIN
    a := 5; { Affectation }
    writeln ('valeur de a = ', a); { Affichage : a = 5 }
END.

La structure de ce programme est en 3 parties : le nom du programme, la partie déclarations, et le corps du programme, qui est une suite d'instructions.
La partie déclaration crée les variables (les boîtes) ; leur contenu est indéterminé (on met un ' ?' dans chaque boîte). La taille de la zone mémoire de chaque variable est adaptée au type (par exemple 1 octet pour un caractère, 4 octets pour un entier, etc).

I-1-4. Trace et tableau de sortie

La trace d'un programme est obtenue en plaçant des writeln pour que le programme affiche les valeurs des variables à l'exécution. Cela sert pour mettre au point un programme en TP.
Le tableau de sortie d'un programme est un tableau avec une colonne par variable, où l'on écrit l'évolution des variables pendant le déroulement du programme.
Demandé en TD et examen.

I-1-5. Lecture au clavier d'une valeur

 
Sélectionnez
PROGRAM lit_ecrit;
VAR
   a : integer;
BEGIN
   write ('Entrez un entier : '); { pas de retour chariot }
   readln (a); { Lecture }
   writeln ('valeur de a = ', a);
END.

I-2. Identificateur

Sert à donner un nom à un objet.
Syntaxe
On appelle lettre un caractère de 'a'..'z' ou 'A'..'Z' ou '_'.
On appelle digit un caractère de '0'..'9'.
Un identificateur Pascal est une suite de lettres ou de digit accolés, commençant par une lettre.
Exemples
x, y1, jour, mois, annee, NbCouleurs, longueur_ligne.
Remarques

  • Il n'y a pas de différence entre minuscules et majuscules.
  • On n'a pas le droit de mettre d'accents, ni de caractères de ponctuation.
  • Un identificateur doit être différent des mots clés (begin, write, real, . . .)

On se sert des identificateurs pour : le nom du programme, les noms de variables, les noms de constantes, les noms de types.

I-3. Types prédéfinis

Un type décrit un ensemble de valeurs et un ensemble d'opérateurs sur ces valeurs.

I-3-1. Type entier : integer

Entier signé en complément à deux sur 16 ou 32 bits, selon machine et compilateur : 16 pour Turbo Pascal, 32 pour Delphi.
Sur 16 bits, à valeur dans -32768 ... + 32767 (-215 ... + 215 - 1).
Sur 32 bits, à valeur dans -2147483648 ... +2147483647 (-231 ... +231 - 1).
Opérateurs sur les entiers :

  • abs(x) valeur absolue de jxj.
  • pred(x) x - 1.
  • succ(x) x + 1.
  • odd(x) true si x est impair, false sinon.
  • sqr(x) le carré de x.
  • + x identité.
  • - x signe opposé.
  • x + y addition.
  • x - y soustraction.
  • x * y multiplication.
  • x / y division, fournissant un résultat de type réel.
  • x div y dividende de la division entière de x par y.
  • x mod y reste de la division entière, avec y non nul.

Remarques

  • Attention, les opérateurs /, div et mod, produisent une erreur à l'exécution si y est nul.
  • Lorsqu'une valeur (ou un résultat intermédiaire) dépasse les bornes au cours de l'exécution, on a une erreur appelée débordement arithmétique.

I-3-2. Type réel : real

Leur domaine de définition dépend de la machine et du compilateur utilisés. On code un réel avec une certaine précision, et les opérations fournissent une valeur approchée du résultat dit juste. Il faut donc se méfier.
Sous Delphi, writeln(0.3); affiche 0.2999999... Ce n'est pas un bug ; simplement, 0.3 n'est pas représentable en base 2. En effet, en base 2 il s'écrit 0,01001 :

base 10 0,3 0,6 1,2 0,4 0,8 1,6 ...
base 2 0 0 1 0 0 1 ...

Exemples de real
0.0 ; -21.4E3(= -21,4 x 103 = -21400) ;1.234E-2 (= 1,234 x 102)

  • Opérateurs sur un argument x réel : abs(x), sqr(x), +x, -x.
  • Si l'un au moins des 2 arguments est réel, le résultat est réel pour : x - y, x + y, x * y.
  • Résultat réel que l'argument soit entier ou réel : x / y (y doit être non nul) ; fonctions sin(x), cos(x), exp(x), ln(x), sqrt(x) (square root, racine carrée).
  • Fonctions prenant un argument réel et fournissant un résultat entier : trunc(x) (partie entière), round(x) (entier le plus proche). Si le résultat n'est pas représentable sur un integer, il y a débordement.

I-3-3. Type caractère : char

Le jeux des caractères comportant les lettres, les digits, l'espace, les ponctuations, etc, est codé sur un octet non signé.
Le choix et l'ordre des 256 caractères possible dépend de la machine et de la langue. Sur PC, on utilise le code ASCII, où 'A' est codé par 65, 'B' par 66, 'a' par 97, ' ' par 32, '{' par 123, etc.
Le code ascii est organisé comme suit : de 0 à 31, sont codés les caractàres de contrôle (7 pour le signal sonore, 13 pour le saut de ligne, etc). De 32 à 127, sont codés les caractères et ponctuations standards et internationaux. Enfin de 128 à 255, sont codés les caractères accentués propres à la langue, et des caractères semi-graphiques.

  • Les opérateurs sur les chars sont :

ord(c) numéro d'ordre dans le codage ; ici code ascii .
chr(a) le résultat est le caractère dont le code ascii est a.
succ(c) caractère suivant c dans l'ordre ascii , chr(ord(c)+1)
prec(c) caractère précédent c dans l'ordre ascii.
Remarque Il y a erreur à l'exécution si le caractère n'existe pas. Exemple

 
Sélectionnez
PROGRAM caracteres;
VAR
	c, d : char;
	a : integer;
BEGIN
	c := 'F';
	a := ord(c); { 70 }
	writeln ('Le code ascii de ', c, ' est ', a);
	a := 122;
	c := chr(a); { 'z' }
	writeln ('Le caractere de code ascii ', a, ' est ', c);
	c := 'j';
	d := succ(c); { 'k' }
	writeln ('Le caractere suivant ', c, ' est ', d);
END.

Exercice Afficher les caractères de code ascii de 32 a 255 (-> sur éecran et sur imprimante, les résultats sont parfois différents). Divers { On peut remplacer chr(32) par #32, mais pas chr(i) par #i. { Le caractère apostrophe se note ''''.

  • Une suite de caractères telle que 'Il y a' est une chaîne de caractères ; il s'agit d'un objet de type string, que l'on verra plus loin.

I-3-4. Type booléen : boolean

Utilisé pour les expressions logiques.
Deux valeurs : false (faux) et true (vrai).

  • Opérateurs booléens : not (négation), and (et), or (ou).

Exemple

 
Sélectionnez
{ Declaration }
petit, moyen, grand : boolean;
{ Instructions }
petit := false;
moyen := true;
grand := not (petit or moyen);

Table de vérité de ces opérateurs

x y not x x and y x or y
true true false true true
true false false false true
false true true false true
false false true false false
  • Opérateurs de comparaison (entre 2 entiers, 2 réels, 1 entier et 1 réel, 2 chars, 2 booléens) :
    <, >, <=, >=, = (égalité, à ne pas confondre avec l'attribution :=), <> (différent). Le résultat d'une comparaison est un booléen.
    On peut comparer 2 booléens entre eux, avec la relation d'ordre false < true.
  • En mémoire, les booléens sont codés sur 1 bit, avec 0 pour false et 1 pour true. De là les relations d'ordre. Les opérateurs booléens not, and, or s'apparentent approximativement à (1 - x), X, +.

I-4. Déclarations

I-4-1. Constantes

Une constante est désignée par un identificateur et une valeur, qui sont fixés en début de programme, entre les mots clés CONST et VAR.
La valeur ne peut pas être modifiée, et ne peut pas être une expression.
Syntaxe

 
Sélectionnez
identificateur = valeur_constante;
{ou}
identificateur : type = valeur_constante;

Dans la première forme, le type est sous-entendu (si il y a un point, c'est un réel, sinon un entier ; si il y a des quotes, c'est un caractère (un seul) ou une chaîne de caractères (plusieurs).
Exemple

 
Sélectionnez
PROGRAM constantes;
CONST
	faux = false;
	entier = 14; { constantes NOMMEES }
	reel = 0.0;
	carac = 'z';
	chaine = 'hop';
	pourcent : real = 33.3; { seconde forme avec type }
VAR
{ variables }
BEGIN
{ instructions }
END.

I-4-2. Variables et affectation

Une variable représente un objet d'un certain type ; cet objet est désigné par un identificateur. Toutes les variables doivent être déclarées après le VAR.
Syntaxe

 
Sélectionnez
identificateur : type ;

On peut déclarer plusieurs variables de même type en même temps, en les séparant par des virgules (voir exemple ci-dessous).
A la déclaration, les variables ont une valeur indéterminée. On initialise les variables juste apràs le BEGIN (on ne peut pas le faire dans la déclaration). Utiliser la valeur d'une variable non initialisée est une erreur grave !
Exemple

 
Sélectionnez
VAR
a, b, c : integer;
BEGIN
{ Partie initialisation }
  b := 5;
{ Partie principale }
  a := b + c; { ERREUR, c n'est pas affecte' }
END.

L'opération identificateur := expression; est une affectation. On n'a pas le droit d'écrire id1 := id2 := expr , ni expr := id ni expr1 := expr2 .

I-5. Expressions

Une expression désigne une valeur, exprimée par composition d'opérateurs appliqués à des opérandes, qui sont : des valeurs, des constantes, des variables, des appels à fonction ou des sous-expressions.

Exemple . Etant donné une variable x, une constante max et une fonction cos(), chaque ligne contient une expression :

 
Sélectionnez
5
x + 3.14
2 * cos(x)
(x < max) or (cos(x-1) > 2 * (x+1))

I-5-1. Syntaxe

Certains opérateurs agissent sur 2 opérandes :

 
Sélectionnez
operande1 operateur_binaire operande2

et d'autres agissent sur 1 opérande :

 
Sélectionnez
operateur_unaire operande
  • Les opérateurs binaires sont :
    - opérateurs de relation = <> <= < > >= - opérateurs additifs + - or - opérateurs multiplicatifs * / div mod and
  • Les opérateurs unaires sont :
    - opérateurs de signe + - - opérateur de négation not
  • Les parenthèses sont un opérateur primaire, elles peuvent encadrer tout opérande.
  • Une fonction est aussi un opérateur primaire, elle agit sur l'opérande placé entre parenthèses à sa droite. Certaines fonctions ont plusieurs paramètres, séparés par des virgules.

I-5-2. Type des expressions bien formées

Une expression doit être < bien formée > pour que l'on puisse trouver sa valeur. Par exemple, 3 * 'a' - true n'est pas bien formée, et la compilation Pascal échouera.
Dans la partie 3, Types prédéfinis, on a déjà dit quels opérateurs sont applicables sur quels types. Mais il y a encore d'autres règles, dont le simple bon-sens ! L'expression bien formée a un type, qui dépend des règles d'évaluation de l'expression.
Exemple
Soit r un réel, i un entier, e une constante entière, c un caractère. L'expression (round(r+1) > (i/e)) or (c < 'a') est bien formée, et sont type est booléen comme on le montre ici :

operation

Remarque Le fait qu'une expression est bien formée n'implique pas que son évaluation est sans erreur, ce qui peut être le cas ici si e est nul.

I-5-3. Règles d'évaluation

L'expression a + b * c est évaluée a + (b * c) et non pas (a + b) * c : ceci parce que le * est prioritaire par rapport à +.
On classe les différents opérateurs par ordre de priorité, les opérateurs de plus forte priorité étant réalisés avant ceux de plus faible priorité.
Lorsque deux opérateurs sont de priorité égale, on évalue de gauche à droite. Par exemple a + b - c est évalué (a + b) - c, et non pas a + (b - c). Voici la table des priorités classées par ordre décroissant, les opérateurs sur une même ligne ayant une priorité égale.

() fonction() primaire
+ - not unaire
* / div mod and multiplicatif
+ - or additif
= <> < <= >= > relation



Remarque Est-ce que l'expression a < b or c <= d est bien formée ? Quel est son type ? Réponse : non ! Écrire une telle expression booléenne sans parenthèses est une erreur classique.
En effet dans la table de priorités, l'opérateur or a une priorité plus élevée que les opérateurs < et <=, et donc l'expression sera évaluée a < (b or c) <= d , ce qui est faux.
L'expression bien formée est ici (a < b) or (c <= d) .

I-6. Nouveaux types

On a vu les types pré-déclarés boolean, integer, real et char. Nous verrons par la suite comment créer de nouveau types. Nous commençons par les plus simples, le type intervalle et le type énuméré.

I-6-1. Type intervalle

C'est un sous-ensemble de valeurs consécutives d'un type hôte.
Syntaxe N..M
où N et M sont des constantes du même type, et sont les bornes inférieures et supérieures de l'intervalle, N et M inclus.
Exemple

 
Sélectionnez
VAR
pourcentage : 0 .. 100; { le type hote est integer }
digit : '0' .. '9'; { le type hote est char }
reponse : false .. true; { le type hote est boolean }

Remarques

  • Il faut impérativement que le type hôte soit codé sur un entier (signé ou non, sur un nombre de bits quelconque). On dit alors que ce type hôte est un type ordinal.
  • Ainsi les types integer, char et boolean sont des types ordinaux.
  • Seul un type ordinal admet les opérateurs pred, succ et ord (le précédent, le successeur et le numéro d'ordre dans le codage).
  • Par contre le type real n'est pas ordinal, et donc on ne pas créer un type intervalle avec des réels, il n'y a pas de notion de < réels consécutifs >.
  • Un autre cas de type non ordinal est le type string pour les chaînes de caractères, qui n'est pas codé sur un mais sur plusieurs entiers. On ne peut donc pas déclarer 'aaa'..'zzz'.

Bonne habitude Utiliser des constantes nommées pour borner les intervalles : de la sorte on pourra consulter ces valeurs pendant le programme, et ces bornes ne seront écrites qu'une seule fois.
Exemple

 
Sélectionnez
CONST
  PMin = 0;
  PMax = 100;
VAR
  pourcentage : PMin .. PMax;
BEGIN
  writeln ('L''intervalle est ', PMin, ' .. ', PMax);
END.

I-6-2. Type énuméré

Il est fréquent en programmation que l'on aie à distinguer plusieurs cas, et que l'on cherche à coder le cas à l'aide d'une variable. Exemple

 
Sélectionnez
VAR
   feux : 0..3; { rouge, orange, vert, clignotant }
BEGIN
{ ... }
   if feux = 0
   then Arreter
   else if feux = 1
   then Ralentir
   else if feux = 2
{ ... }
END.

Ceci est très pratique mais dans un programme un peu long cela devient rapidement difficile à comprendre, car il faut se souvenir de la signification du code. D'où l'intérêt d'utiliser un type énuméré, qui permet de donner un nom aux valeurs de code :

 
Sélectionnez
VAR
feux : (Rouge, Orange, Vert, Clignotant);
BEGIN
{ ... }
if feux = Rouge
then Arreter
else if feux = Orange
then Ralentir
else if feux = Vert
{ ... }
END.
  • En écrivant cette ligne, on déclare en même temps :
    - la variable feux, de type énuméré (toujours codée sur un entier),
    - et les constantes nommées Rouge, Orange, Vert et Clignotant.
  • A ces constantes sont attribuées les valeurs 0, 1, 2, 3 (la première constante prend toujours la valeur 0).
    - On ne peut pas choisir ces valeurs soi-même, et ces identificateurs ne doivent pas déjà exister.
    - L'intérêt n'est pas de connaître ces valeurs, mais d'avoir des noms explicites.
  • Le type énuméré étant codé sur un entier, il s'agit d'un type ordinal et on peut :
    - utiliser les opérateurs pred, succ et ord (exemple : pred(Orange) est Rouge, succ(Orange) est Vert, ord(Orange) est 1).
    - déclarer un type intervalle à partir d'un type énuméré (exemple : Rouge..Vert).

I-6-3. Déclarer un type

Créer un type, c'est bien, mais le nommer, c'est mieux. On déclare les noms de types entre les mots clés TYPE et VAR. Syntaxe

 
Sélectionnez
nom_du_type = type;

Exemple

 
Sélectionnez
TYPE
couleurs_feux_t = (Rouge, Orange, Vert, Clignotant);
VAR
feux : couleurs_feux_t;

De la sorte couleurs_feux_t est un nom de type au même titre que integer ou char. Exemple complet

 
Sélectionnez
PROGRAM portrait;
CONST
  TailleMin = 50; { en cm }
  TailleMax = 250;
TYPE
  taille_t = TailleMin .. TailleMax;
  couleurs_t = (Blond, Brun, Roux, Bleu, Marron, Noir, Vert);
  cheveux_t = Blond .. Roux;
  yeux_t = Bleu .. Vert;
VAR
  taille_bob, taille_luc : taille_t;
  cheveux_bob, cheveux_luc : cheveux_t;
  yeux_bob, yeux_luc : yeux_t;
BEGIN
  taille_bob := 180;
  cheveux_bob := Brun;
  yeux_bob := Noir;
END.

Remarque Observez bien les conventions d'écriture différentes que j'ai employées pour distinguer les constantes des types et des variables ; cela aussi aide à la lecture.

I-6-4. Type enregistrement

Il s'agit simplement de regrouper des variables V1, V2, . . . de différents types T1, T2, . . . dans une variable < à tiroirs >. Syntaxe

 
Sélectionnez
Record
V1 : T1;
V2 : T2;
{ ... }
End;

Soit r une variable de ce type ; on accéde aux différents champs de r par r.V1, r.V2, . . . Reprenons l'exemple du programme portrait.

 
Sélectionnez
{ ... }
TYPE
{ ... }
  personne_t = Record
  taille : taille_t;
  cheveux : cheveux_t;
  yeux : yeux_t;
 End;
VAR
  bob, luc : personne_t;
BEGIN
  bob.taille := 180;
  bob.cheveux := Brun;
  bob.yeux := Noir;
  luc := bob;
END.

Remarque La seule opération globale sur un enregistrement est : recopier le contenu de r2 dans r1 en écrivant : r2 := r1;
Ceci est équivalent (et plus efficace) que de copier champ à champ ; en plus on ne risque pas d'oublier un champ.
Il y a une condition : les 2 variables doivent être exactement du même type.

Intérêt de ce type
Il permet de structurer très proprement des informations qui vont ensemble, de les recopier facilement et de les passer en paramètres à des procédures (on y reviendra).

Remarque générale
Lorsqu'on crée un type T2 à partir d'un type T1, ce type T1 doit déjà exister ; donc T1 doit être déclaré avant T2.


précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2010 Edouard Thiel. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.