Section courante

A propos

Section administrative du site

Tableaux et enregistrements

Cette page présente les types de données contenant des collections organisées de données dans un ordre défini.

Un «tableau» est une collection d'éléments de données du même type. Les programmes utilisent des tableaux dans des situations où un format de données standard est répété plusieurs fois. Par exemple, les nombres représentant le produit national brut pour toutes les années de 1900 à 1980 peuvent être placés dans un tableau.

Un «enregistrement» est une collection d'éléments de données ayant différents types. Les programmes utilisent des enregistrements dans des situations où diverses données sont étroitement associées. Par exemple, toutes les informations sur un employé donné (nom, salaire et habilitation de sécurité) peuvent être placées dans un seul enregistrement.

Enfin, cette page présente le type «enregistrement variant», étant une extension du type enregistrement. Un enregistrement de variante vous permet d'utiliser différents formats de données pour accéder à la même zone de mémoire, ce qui vous permet de créer un enregistrement contenant différents types d'informations à différents moments.

Chacune des sections principales de cette page présente un type de données, montre comment le déclarer, puis montre comment accéder à ses composantes.

Tableaux

Un tableau est une collection d'éléments partageant le même type de données et un nom de variable commun. Vous accédez à un élément du tableau en spécifiant la position de l'élément. Une valeur entière ou ordinale indique la position et est appelée un «indice» ou «index».

Le Pascal vous permet de déclarer des tableaux de n'importe quel type. Vous pouvez même déclarer des tableaux de tableaux, étant essentiellement des tableaux à deux dimensions. Vous pouvez déclarer des tableaux avec n'importe quel nombre de dimensions. Les tableaux multidimensionnels ont de nombreuses applications et apparaissent souvent dans les programmes Pascal. Par exemple, un programme nécessitant une grille utilisera un tableau à deux dimensions, et un programme cartographiant un espace à trois dimensions utilisera un tableau à trois dimensions. Les tableaux les plus simples sont unidimensionnels. Ils consistent en une séquence linéaire d'éléments.

Déclarer des tableaux

Dans de nombreux langages de programmation (tels que C), les tableaux doivent toujours commencer à un numéro d'index particulier (tel que 0 ou 1). En Pascal, cependant, vous pouvez définir les limites d'un tableau avec presque n'importe quel type ordinal :

ARRAY[IndexType] OF ElementType

Pour déclarer un tableau multidimensionnel, vous déclarez un type d'index pour chaque dimension :

ARRAY [IndexType, IndexType ...] OF type

IndexType peut être n'importe quel type ordinal sauf LongInt ou des sous-intervalle de LongInt. Le plus souvent, les programmes utilisent des sous-intervalles dans les déclarations de tableau. Les limites inférieure et supérieure de la sous-gamme donnent l'index le plus bas et le plus élevé et déterminent également la taille du tableau. Par exemple :

  1. Type
  2.  income_per_year=Array[1977..1989] of LongInt;
  3.  class_size=Array[1..12] of Integer;
  4.  grid=Array[-5..5, -10..10] of Real;

Comme vous pouvez le voir, même les nombres négatifs peuvent servir de limites de tableau. Parce que Pascal est si structuré, vous pouvez utiliser de nombreuses sous-gammes d'entiers et types énumérés différents pour indexer les tableaux. Par exemple :

  1. Type
  2.  pay=LongInt;
  3.  rank=(_private, sergeant, lt, captain, major, general);
  4.  officers=lt..general;
  5.  letters='A'..'Z' ;
  6.  my_arr=Array[1..10] of Real;
  7.  
  8. Var
  9.  low_pay:Array[_private..sergeant] of pay;
  10.  high_pay:Array[officers] of pay;
  11.  ascii_code:Array[letters] of Word;
  12.  big_arr:Array[letters] of my_arr;

Le dernier exemple ci-dessus, big_arr, est en réalité un tableau à deux dimensions et équivaut à la déclaration suivante, spécifiant explicitement les intervalles des deux dimensions :

  1. big_arr:Array[letters, 1..10] of Real;

Gardez à l'esprit la différence entre le type d'index d'un tableau et le type d'élément. L'élément entre parenthèses définit le type d'index du tableau et est significatif des manières suivantes :

Les éléments sont déclarés par le type de données à la fin de la déclaration du tableau. Comme mentionné ci-dessus, vous pouvez utiliser n'importe quel type de données, y compris l'un des types de données avancés mentionnés plus loin dans cette page. Chaque élément du tableau a ce type d'élément.

Accéder aux éléments du tableau

Pour faire référence à un élément d'un tableau, utilisez la syntaxe :

Name[Index]

dans lequel Name est le nom de la variable tableau et Index a le type d'index utilisé pour déclarer le tableau. Si le type d'index est un sous-intervalle, Index doit se trouver dans l'intervalle spécifiée ou le programme produit des erreurs. Considérez les déclarations suivantes :

  1. Var
  2.  trio:Array[1..3] of Word;
  3.  income:Array[1980..1983] of LongInt;

Dans l'exemple ci-dessus, les éléments de trio sont appelés :

  1. trio[1]
  2. trio[2]
  3. trio[3]

Les éléments de income sont appelés :

  1. income[1980]
  2. income[1981]
  3. income[1982]
  4. income[1983]

Chacun des éléments ci-dessus a le type de données déclaré pour le tableau - Word dans le cas du trio et LongInt dans le cas de income. Vous pouvez faire référence à un élément dans n'importe quel contexte valide pour une variable simple du même type. Vous pouvez modifier un élément, le transmettre à une procédure ou affecter sa valeur à une autre variable. Les déclarations suivantes sont toutes valides :

  1. trio[1]:=50;
  2. trio[2]:=trio[1] div 2;
  3. WriteLn('Le résultat est : ', trio[1]+trio[2]);

L'index de tableau peut être une variable ainsi qu'une constante. En fait, la puissance des tableaux en programmation provient en grande partie de l'utilisation d'index de variables. Le code suivant utilise une variable de boucle pour initialiser efficacement un large tableau de nombres aléatoires :

  1. Var
  2.  i:Integer;
  3.  big_arr:Array[1..1000] of Word;
  4. Begin
  5.  For i:=1 TO 1000 do big_arr[i]:=Random(100);

Pour faire référence à un élément d'un tableau multidimensionnel, utilisez la syntaxe :

Name[Index, Index...]

dans lequel chaque index est du type et d'intervalle de l'index correspondant dans la déclaration de tableau. Par exemple, le code suivant utilise une boucle imbriquée pour initialiser efficacement un tableau à deux dimensions de nombres aléatoires :

  1. Var
  2.  i,j:Integer;
  3.  results:Array[1..max_row,1..max_col] of Word;
  4.  
  5. BEGIN
  6.  For i:=1 to max_row do For j:=1 to max_col do results[i,j]:=Random(100);

La directive {$R+} oblige le programme à vérifier les index hors limites au moment de l'exécution. Utilisez la directive {$R+} pendant le développement du programme, mais vous pouvez désactiver la directive ({$R-}) une fois que vous avez terminé l'écriture et le débogage. Cela permet au programme de s'exécuter plus rapidement.

Déclarer des tableaux constants

Pour déclarer un tableau constant, définissez d'abord le type de tableau, puis déclarez le tableau et les valeurs initiales dans une instruction CONST. Comme indiqué dans les exemples ci-dessous, suivez le type de tableau avec un signe égal (=) et une liste de valeurs initiales entre parenthèses. Séparez les éléments par des virgules. Les tableaux multidimensionnels nécessitent des niveaux supplémentaires de parenthèses. Par exemple, dans un tableau à deux dimensions, placez des parenthèses autour des valeurs de chaque ligne.

  1. Const
  2.  max_row=5;
  3.  grid_size=2;
  4.  
  5. Type
  6.  small_int_arr=Array[1..max_row] of Integer;
  7.  hex_digit_arr=Array[1..16] of Char;
  8.  grid_xy=1..grid_size;
  9.  char_grid_type=Array[grid_xy, grid_xy] of Char;
  10.  
  11. CONST
  12.  topic_index:small_int_arr=(11,12,13,14,15);
  13.  hex:hex_digit_arr =('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
  14.  default_state:char_grid_type =(('a','j'),('W','T'));

Passage de tableaux en tant que paramètres

Cette section décrit comment passer un tableau entier à une procédure ou une fonction. Notez qu'il n'y a aucune restriction sur la façon dont vous passez des éléments individuels, pouvant être passés comme de simples variables du même type.

Pour passer un tableau en tant que paramètre, définissez d'abord le tableau en tant que type indépendant. Déclarez ensuite la fonction pour qu'elle prenne un paramètre de ce type prédéfini, et passez une valeur de ce même type à la fonction. Cette exigence est nécessaire pour que Pascal s'assure que le tableau est passé correctement.

Le code suivant illustre comment réussir la transmission d'un tableau :

  1. Type
  2.  res_arr=Array[1..20] of Integer;
  3.  
  4. Var
  5.  results:res_arr; { résultats est une variable de type res_arr }
  6.  {=====init_arr=====}
  7.  { init_arr accepte une variable de type res_arr et l'initialise }
  8. Procedure init_arr(Var new_arr:res_arr);Begin
  9. End;
  10.  
  11. BEGIN
  12.  { appelez init_arr, en lui passant la variable de résultats de type res_arr }
  13.  init_arr(results);

Vous n'avez pas besoin de prédéfinir un type de chaîne pour transmettre une chaîne de caractères. Cependant, si l'option Var-String Checking (dans la boîte de dialogue des directives du compilateur dans le menu Options) est active (valeur par défaut), la longueur de la chaîne de caractères que vous transmettez doit correspondre exactement à la longueur de la chaîne attendue par la procédure. Par exemple, si la procédure print_str est déclarée comme ceci :

  1. Procedure print_str(data_str:String[20]);

alors vous ne pouvez transmettre que des chaînes de caractères de type STRING[20].

Si Var-String Checking est désactivé, vous pouvez passer des chaînes aux paramètres sans tenir compte de la longueur. Vous pouvez également passer des variables de type STRING.

Comme toutes les variables, les tableaux peuvent être passés par valeur ou par référence. Lorsque vous passez un tableau par valeur, le tableau entier est copié dans la pile. Cela peut vous amener à manquer rapidement de mémoire de pile si vous travaillez avec de grandes tableaux.

Utilisation du débogueur avec des tableaux

Lorsque vous souhaitez afficher un tableau pendant le débogage, vous pouvez spécifier trois types différents d'expressions Watch :

Par exemple, a[4], 5 permet de visualiser le sous-tableau a[4] à a[9]. Vous pouvez également utiliser une variable comme index du premier élément.

Enregistrement

Un enregistrement est un ensemble de variables pouvant avoir différents types. Chaque variable de l'enregistrement a un nom pour la différencier des autres variables de l'enregistrement. Ce nom s'appelle un «champ». Pour accéder à un élément d'un enregistrement, vous indiquez à la fois le nom de l'enregistrement et le champ.

Les enregistrements sont courants dans les applications pratiques. Par exemple, considérez un programme maintenant les réservations d'avion. Pour chaque réservation, il existe plusieurs informations pertinentes : nom du client, numéro de vol, date et heure. Vous pouvez combiner toutes ces informations dans un seul enregistrement.

Bien que vous puissiez suivre les différents éléments de données dans des variables distinctes, les regrouper dans un seul enregistrement facilite l'écriture et la maintenance des programmes. De plus, les enregistrements sont des unités de données pratiques à lire et à écrire sur le disque.

Déclaration des enregistrements

Déclarez un enregistrement avec la syntaxe suivante. L'enregistrement peut faire partie d'une définition de type ou d'une déclaration de variable.

RECORD
   FieldDeclarations
END

Dans l'affichage de la syntaxe ci-dessus, FieldDeclarations est une déclaration de variable. Le nom de la variable détermine le nom du Field (voir exemples). Vous devez séparer chaque champ du suivant par un point-virgule.

Les lignes suivantes montrent quelques définitions simples de type d'enregistrement :

  1. Type
  2.  complex=Record
  3.   x_real,y_imag:Real;
  4.  End;
  5.  mail_rec=Record
  6.   name:String[20];
  7.   street:String[25];
  8.   city:String[5];
  9.   state:String[2];
  10.   zip:LongInt;
  11.  END;

En raison de la nature hautement structurée de Pascal, chaque champ peut avoir n'importe quel type de données. Un champ peut être un tableau ou même un autre enregistrement. Lorsqu'un enregistrement apparaît sous la forme d'un champ dans un autre enregistrement, on dit qu'il est «imbriqué». Par exemple, le type mail_list_rec affiché ci-dessous contient last_deleted_rec, étant un autre enregistrement, comme l'un de ses champs :

  1. mail_list_rec=Record
  2.  num_recs:Word;
  3.  last_update,
  4.  last_mailing:String;
  5.  last_deleted_rec;mail_rec;
  6. End;

Les tableaux d'enregistrements sont des types de données courants. Par exemple, la structure de données suivante crée un tableau des notes des élèves d'un cours de mathématiques :

  1. Type
  2.  table_rows=1..30;
  3.  stu_rec=Record
  4.   name:String[20];
  5.   testl_score,
  6.   test2_score,
  7.   test3_score:Word;
  8.   grade_pt:Real;
  9.  End;
  10.  
  11. Var
  12.  table:Array[table_rows] of stu_rec;

Accéder aux champs d'enregistrement

Pour accéder à un champ individuel d'un enregistrement, vous indiquez à la fois le nom de la variable d'enregistrement et le nom du champ :

RecordName.FieldName

Le résultat est un objet de données du type déclaré pour le champ. Vous pouvez utiliser l'élément résultant dans n'importe quel contexte étant valide pour une variable ordinaire du même type.

Considérez le type d'enregistrement suivant :

  1. Type
  2.  mail_rec=Record
  3.   name:String[20];
  4.   street:String[25];
  5.   city:String[5];
  6.   state:String[2];
  7.   zip:LongInt;
  8.  End;
  9.  
  10.  mail_array=Array[1..max_mailing] of mail_rec;
  11.  
  12. Var
  13.  my_mail:mail_rec;
  14.  mailing:mail_array;

L'exemple suivant affecte une chaîne au champ de nom de la variable d'enregistrement my_mail déclarée ci-dessus :

  1. my_mail.name:='Jean Tremblay';

L'expression my_mail.name est une variable de chaîne de caractères pouvant être affectée à une valeur ou transmise à une fonction, comme n'importe quelle autre variable de chaîne de caractères. Par exemple, l'instruction suivante affiche le nom :

  1. WriteLn('Le nom du destinataire est ', my_mail.name);

La syntaxe devient un peu plus compliquée lorsque vous faites référence à un élément dans le tableau d'enregistrements. Par exemple, l'instruction suivante initialise le champ de nom du troisième élément du tableau :

  1. mailing[3].name:='Victor Hugo';

Considérez comment Pascal analyse cette expression. Vous pouvez comprendre n'importe quelle expression complexe en suivant une logique similaire :

Le chemin de données vers un objet augmente à mesure que vous augmentez les niveaux d'imbrication. Par exemple, considérez la définition du type mail_rec ci-dessus plus les instructions supplémentaires suivantes :

  1. Type
  2.  MailArr=Array[1..100] of mail_rec;
  3.  
  4. Var
  5.  mailing_list:Record
  6.   title:String;
  7.   addresses:MailArr;
  8.  End;

Compte tenu de ces déclarations, vous pouvez accéder à un champ de nom individuel comme ceci :

  1. mailing_list.addresses[5].name

La section suivante montre une technique pour raccourcir la longueur de telles expressions.

Utilisation de l'instruction WITH pour accéder aux champs

Bien que la définition du chemin d'accès complet aux données dans un enregistrement rende votre code plus lisible, cela augmente également la longueur des identifiacateurs. L'instruction WITH de QuickPascal vous permet d'omettre le nom d'une variable d'enregistrement d'un bloc d'instructions. Il a la syntaxe suivante :

WITH RecordName DO Statement

La déclaration suivant DO peut faire référence directement aux champs de RecordName. Par exemple, vous pouvez affecter une chaîne de caractères au champ de nom de la variable d'enregistrement my_mail avec l'instruction suivante :

  1. With my_mail DO name:='Jean Tremblay';

Pour faire suivre le mot clef DO de plusieurs instructions, utilisez un bloc d'instructions BEGIN...END.

Dans le cas d'enregistrements imbriqués, l'instruction WITH peut contenir un nom d'enregistrement modifié par un nom de champ. Spécifiez toujours l'enregistrement le plus externe en premier. Par exemple, supposons que name soit un champ de mail_rec, qui à son tour est un champ de la variable d'enregistrement mail_list_rec. L'instruction suivante affecte une chaîne de caractères au champ de name :

  1. With mail_list_rec.mail_rec do name:='Victor Hugo';

Enregistrements constants

Pour déclarer un enregistrement constant, définissez d'abord le type d'enregistrement, puis déclarez l'enregistrement et la valeur initiale dans une instruction CONST. La valeur initiale d'un enregistrement est constituée de la syntaxe suivante :

(FieldName : Constant; FieldName : Constant...)

La valeur initiale de chaque champ suit les règles de son type. Par exemple, chaque ligne d'un initialiseur de tableau doit être placée entre parenthèses. Dans le cas d'enregistrements imbriqués, des niveaux supplémentaires de parenthèses et de champs sont requis, comme indiqué ci-dessous :

  1. Type
  2.  complex=Record
  3.   x_real,
  4.   y_imag:Real;
  5.  End;
  6.  
  7.  square matrix=Record
  8.   mat_size:Byte;
  9.   imag:complex;
  10.   determinant:Real;
  11.   mat_x:Array[1..3, 1..3] of Real;
  12.  End;
  13.  
  14. Const
  15.  origin:complex=(x_real:0.0; y_imag:0.0);
  16.  def_mat:square_matrix=(
  17.   mat_size:3;
  18.   imag:(x_real:1.0; y_imag:1.0);
  19.   determinant:0.0;
  20.   max_x:(
  21.    (1.0,1.0,1.0),
  22.    (2.0,2.0,2.0),
  23.    (3.0,3.0,3.0)
  24.   )
  25.  );

Affectation d'enregistrements à des variables d'enregistrement

Le Pascal prend en charge l'utilisation de l'opérateur d'affectation (:=) pour affecter la valeur d'une variable d'enregistrement à un autre enregistrement. Vous pouvez également affecter un tableau à un autre si vous déclarez le type de tableau en tant que champ dans un enregistrement.

Par exemple, si rec_a et rec_b sont tous deux des tableaux du même type, vous pouvez utiliser l'instruction suivante pour affecter un enregistrement à un autre :

  1. rec_a:=rec_b;

Comme autre exemple, supposons que matrix1 et matrix2 soient tous deux des enregistrements du même type et que ce type contienne un champ de tableau mat_x. Vous pouvez utiliser l'instruction suivante pour affecter un champ de tableau à un autre :

  1. matrix1.mat_x:=matrix2.mat_x;

Utilisation du débogueur avec des enregistrements

La fenêtre Debug affiche les champs d'un enregistrement sous la forme d'une liste d'éléments de données entre parenthèses. L'ajout de ", R" au nom d'un enregistrement surveillé lorsqu'il est placé dans la fenêtre Debug affiche les noms des champs et leurs valeurs. Un deux-points sépare le nom d'un champ et sa valeur courante avec ce format d'affichage. Vous devrez peut-être faire défiler la fenêtre pour voir tous les champs de l'enregistrement.

Enregistrements de variantes

Un enregistrement de variante vous permet de fournir une variété de formats de données pour la même zone de mémoire. Chaque fois que vous vous référez à l'enregistrement de variante, vous indiquez le format à utiliser. Cette fonctionnalité est utile dans les situations suivantes :

Déclaration d'enregistrements de variantes

La syntaxe d'une déclaration d'enregistrement de variante est :

RECORD
   FieldDeclarations
   CASE [[Tag:]] TagType OF
      CaseDeclarations
END

Les FieldDeclarations constituent les "champs fixes" de l'enregistrement et sont facultatifs. La balise est un champ facultatif que vous pouvez utiliser pour indiquer lequel des cas (formats de données) est actif. Chaque CaseDeclaration a le format suivant :

CaseLabel: (FieldDeclarations)

Séparez chaque CaseDeclaration par un point-virgule. Le Tag et chaque CaseLabel doivent être du TagType, pouvant être n'importe quel type ordinal valide (tel qu'un entier ou un type défini par l'utilisateur).

Chaque cas déclare une série différente de champs. Cependant, chaque cas est superposé dans la même zone de l'enregistrement. Le Pascal alloue suffisamment de mémoire pour le cas qui a la plus grande taille totale. Cette zone est appelée la «partie variante» de l'enregistrement. Un cas peut utiliser cette zone pour entreposer un champ de chaîne de caractères. Un autre pourrait l'utiliser pour entreposer des champs à virgule flottante.

L'exemple suivant montre un enregistrement variant modélisant les registres du processeur 8086 :

  1. Type
  2.  regtype = (reg16, reg08);
  3.  registers86=Record
  4.  Case Integer of
  5.   0:(ax,bx,cx,dx,si,di,bp,sp,flags:Word;);
  6.   1:(al,ah,bl,bh,cl,ch,dl,dh:Byte;);
  7.  End;

Cette définition de type vous permet d'accéder aux mêmes données soit comme un élément 16 bits, comme ax, soit comme deux éléments 8 bits, comme al et ah.

Accès aux champs d'enregistrement de variante

Vous accédez à tous les champs de l'enregistrement de la même manière, qu'il s'agisse de champs fixes ou définis dans la partie variante de l'enregistrement. (Par conséquent, les noms de tous les champs dans les parties fixes et variantes doivent être uniques.) De plus, si un champ de balise est déclaré, vous pouvez le définir pour indiquer quel cas est actif.

Par exemple (en supposant la déclaration registers86 à la fin de la dernière section), les instructions suivantes chargent des données dans al et ah, puis affichent ax. Notez que ax contient les mêmes données que al et ah combinés.

  1. Var
  2.  my_regs:registers86;
  3. BEGIN
  4.  my_regs.ah:=$FF;
  5.  my_regs.al:=$10;
  6.  WriteLn('AX contient maintenant : ', my_regs.ax);

Pour un autre exemple, un schéma d'enregistrement de variante simplifié pour le système du personnel d'une entreprise pourrait ressembler à ceci :

  1. Type
  2.  clearance=(topsecret, secret, medium, low, known_spy);
  3.  drink_type=(martini, wine, champagne, teetotaler);
  4.  games_type=(tennis, squash, golf);
  5.  title=(secretary, engineer, exec);
  6.  emp_rec=Record
  7.   name:String[20];
  8.   Case job : title of
  9.    secretary:(wpm,steno:Word);
  10.    engineer:(security:clearance;IQ:Byte);
  11.    exec:(beverage:drink_type;
  12.          pastime:games_type;
  13.          washroom_code:LongInt);
  14.   End;
  15.  
  16. Var
  17.  new_emp:emp_rec;

Le code suivant initialise la variable d'enregistrement new_emp pour un ingénieur récemment embauché :

  1. new_emp.name:='Jean Tremblay';
  2. new_emp.job:=engineer;
  3. new_emp.security:=secret;
  4. new_emp.IQ:=120;

Supposons maintenant que Jean Tremblay soit promue à la direction. Les anciennes données pertinentes pour les ingénieurs (habilitation de sécurité et IQ) ne sont plus pertinentes pour Jean dans son nouveau poste. Heureusement, le type d'enregistrement variant vous permet de réutiliser cette même zone de mémoire pour y mettre des données pertinentes pour les gestionnaires.

Tout d'abord, le programme officialise la promotion de Jean :

  1. new_emp.job:=exec;

Le programme saisit ensuite les nouvelles données de Jean. Pour s'adapter à l'ascension de Jean dans l'échelle de l'entreprise, le programme enregistre sa boisson préférée, son passe-temps préféré et le code de clef pour les toilettes de la direction. Ces informations sont écrasées sur les données de l'ingénieur, n'étant plus nécessaires :

  1. new_emp.beverage:=martini;
  2. new_emp.pastime:=tennis;
  3. new_emp.washroom_code:=12345007;


Dernière mise à jour : Dimanche, le 28 août 2022