Année universitaire 2002-2003 |
Licence d'informatique
|
Les comparateurs (>, <, >=, <=, ==, !=) et les opérateurs logiques "binaires" (&&, ||) renvoient 0 si le résultat est FAUX et 1 s'il est VRAI. L'opérateur logique "unaire" de négation (!) renvoie 0 pour toute valeur non nulle et 1 pour la valeur 0 :
!0 == 1 !8 == 0
Les opérateurs logiques binaires && et || doivent être utilisés selon la syntaxe suivante :
où expr1 et expr2 doivent être des expressions de valeurs entières ou flottantes.
Pour l'opérateur &&, si expr1 est nulle (c'est-à-dire évaluée à FAUX), alors expr2 n'est pas évaluée, et le résultat de l'opération vaut 0
Pour l'opérateur ||, si expr1 est non nulle (c'est-à-dire évaluée à VRAI), alors expr2 n'est pas évaluée, et le résultat de l'opération vaut 1
Les opérateurs && et || ne sont donc pas commutatifs. Par conséquent, si on change l'ordre des expressions expr1 et expr2 d'une opération logique binaire, cela peut modifier le comportement d'un programme, en particulier si ce programme comporte des pré-incrémentations ou des post-incrémentations.
Écrire une fonction qui détermine si une année
est bissextile.
Rappel :
Une année est bissextile si son expression numérale est divisible par 4 mais pas par 100, ou si elle est divisible par 400.
Exemples :
1996 est bissextile (multiple de 4, mais pas de
100).
2000 est bissextile (multiple de 4, de 100,
mais aussi de 400).
2100 n'est pas bissextile (multiple de 4,
de 100, mais pas de 400).
Écrire un programme qui, à partir d'une date exprimée sous la forme jour
mois année, calcule le nombre de jours écoulés
depuis le début de l'année jusqu'à la date précisée.
Exemple :
Le programme appelé avec la date 01 03 1996
produira l'affichage suivant :
Nombre de jours écoulés entre le début de 1996 et cette date : 61
(résultat de : 31+29+1).
La déclaration suivante :
int tab[3];
est celle d'un tableau unidimensionnel de 3 entiers, ayant pour adresse tab ou encore &tab[0]
Les 3 cases associées à ce tableau sont situées en mémoire de manière contiguë, et sont 3 variables de type int de noms tab[0], tab[1] et tab[2].
Afin de donner une représentation de la manière dont la mémoire centrale d'un ordinateur est gérée lors de l'exécution d'un programme, on conseille de toujours dessiner un graphique respectant les conventions suivantes :
L'exemple de programme suivant donne une solution pour récupérer l'adresse du tableau précédent dans une fonction :
Langage C |
Équivalent Ada |
Équivalent Pascal |
#include <stdio.h> void lecture_tab_C(int tab2[], int nbcar) { int i; for (i=0;i<nbcar;i++) scanf("%d",&tab2[i]); } int main(void) { int i,tab[3]; lecture_tab_C(tab,3); for (i=0;i<3;i++) printf("%d ",tab[i]); printf("\n"); return(0); } |
with Ada.Text_Io,Ada.Integer_Text_Io; use Ada.Text_Io,Ada.Integer_Text_Io; procedure init_tab_Ada is type tableau is array (0..2) of integer; procedure lecture_tab_Ada (tab2:out tableau;nbcar:in integer) is begin for i in 0..nbcar-1 loop get(tab2(i)); skip_line; end loop; end lecture_tab_Ada; tab:tableau; begin lecture_tab_Ada(tab,3); for i in tab'range loop put(tab(i),0); put(' '); end loop; new_line; end init_tab_Ada; |
PROGRAM init_tab_Pascal; USES crt; TYPE tableau=ARRAY [0..2] OF INTEGER; PROCEDURE lecture_tab_Pascal (VAR tab2:tableau;nbcar:INTEGER); VAR i:INTEGER; BEGIN FOR i:=0 TO nbcar-1 DO readln(tab2[i]) END; VAR i:INTEGER; tab:tableau; BEGIN lecture_tab_Pascal(tab,3); FOR i:=0 TO 2 DO write(tab[i],' '); writeln END. |
Les valeurs des trois cases de tab sont modifiées, lors de l'appel des fonctions lecture_tab_C, lecture_tab_Ada ou lecture_tab_Pascal, par la lecture de nombres tapés au clavier.
Dans la déclaration de la fonction lecture_tab_C, le paramètre formel tab2 est suivi de crochets vides []. On aurait pu également écrire explicitement la dimension souhaitée, c'est-à-dire :
int lecture_tab_C(int tab2[3],int nbcar)
En revanche, dans le programme suivant, dans lequel le paramètre de la fonction n'est plus un tableau, mais un entier, seules les versions Ada et Pascal sont correctes :
Langage C |
Équivalent Ada |
Équivalent Pascal |
#include <stdio.h> void lecture_int_C_incorrecte(int a2) { scanf("%d",&a2); a2++; } int main(void) { int a=0; lecture_int_C(a); printf("%d\n",a); return(0); } |
with Ada.Text_Io,Ada.Integer_Text_Io; use Ada.Text_Io,Ada.Integer_Text_Io; procedure init_int_Ada is procedure lecture_int_Ada (a2:out integer) is begin get(a2); skip_line; a2:=a2+1; end lecture_int_Ada; a:integer:=0; begin lecture_int_Ada(a); put(a,0); new_line; end init_int_Ada; |
PROGRAM init_int_Pascal; USES crt; PROCEDURE lecture_int_Pascal (VAR a2:INTEGER); BEGIN readln(a2); a2:=a2+1 END; VAR a:INTEGER; BEGIN a:=0; lecture_int_Pascal(a); writeln(a1) END. |
Dans la version C, le programme principal produira l'affichage de la valeur 0 initialement affectée à a. La raison en est la suivante : à l'intérieur de la fonction lecture_tab_C de l'exemple précédent, on a accès à l'adresse du tableau tab (passage "par adresse"), alors qu'à l'intérieur de la fonction lecture_int_C, on n'a pas accès à l'adresse de l'entier a (passage "par valeur"). On verra dans la séance 4 de travaux dirigés comment rendre correcte la fonction lecture_int_C.
Soit tab un tableau à deux dimensions (un tel tableau est également appelé une "matrice"), déclaré de la manière suivante :
char tab[2][3];
Les six cases de ce tableau sont situées en mémoire de manière contiguë. Il semble a priori qu'il y ait une ambiguïté concernant l'ordre dans lequel ces six cases apparaissent en mémoire. Il est important de savoir que c'est le dernier indice qui varie en premier. Voici donc la configuration en mémoire des cases du tableau tab :
Si on suppose que le premier indice du tableau tab désigne le numéro de ligne, et le second le numéro de colonne, on peut également retenir que cette configuration correspond à la manière dont on lit un texte, c'est-à-dire ligne par ligne.
Soit une fonction fonct, retournant par exemple un entier, à laquelle on souhaite passer l'adresse du tableau tab en paramètre. L'appel de la fonction fonct se fera en passant l'adresse du tableau tab, sous la forme suivante :
fonct(tab);
Quant à l'en-tête de la déclaration de fonct, il peut être écrit de l'une des deux manières suivantes :
int fonct(char T[2][3])ouint fonct(char T[][3])
En revanche, les deux écritures suivantes sont à proscrire pour l'en-tête de fonct :
int fonct_fausse(char T[2][])ouint fonct_fausse(char T[][])
En effet, dans ces deux derniers cas, on ne pourrait pas connaître les adresses des cases tab[1][0], tab[1][1] et tab[1][2] à l'intérieur de la fonction puisque, d'après le dessin ci-dessus, ces trois adresses valent :
et que le décalage de 3 octets ne serait pas connu à l'intérieur de la fonction.
Il est possible de définir un type en C, à l'aide du mot-clé typedef
Si plusieurs variables ou paramètres doivent être déclarés avec le type "matrice 12 x 12 de caractères", il est conseillé de définir le type matrice, en utilisant la syntaxe suivante :
typedef char matrice[12][12];
Cette définition rendra équivalentes les deux syntaxes suivantes, pour la déclaration de la variable m :
matrice m;ouchar m[12][12];
Écrire un programme C permettant de saisir les notes (entières) obtenues par quatre élèves à trois examens successifs. Les notes sont tapées dans l'ordre suivant :
[note de l'élève 1 à l'examen 1]
[note de l'élève 2 à l'examen 1]
[note de l'élève 3 à l'examen 1]
[note de l'élève 4 à l'examen 1]
[note de l'élève 1 à l'examen 2]
[note de l'élève 2 à l'examen 2]
[note de l'élève 3 à l'examen 2]
[note de l'élève 4 à l'examen 2]
[note de l'élève 1 à l'examen 3]
[note de l'élève 2 à l'examen 3]
[note de l'élève 3 à l'examen 3]
[note de l'élève 4 à l'examen 3]
À l'issue de la saisie des notes, le programme devra afficher la moyenne obtenue par chaque élève à l'ensemble des examens.
Remarques :