Année 2011-2012 Examen de Langage C Vendredi 2 Décembre 2011 Promotion Guichet 1 ière année É. Salvat Modalités : Durée : 2 heures Seul document autorisé : carte de référence du C, pas de machine à calculer, ni de téléphone. Toute sortie est définitive! Le barème est donné à titre indicatif. Exercice 1 (Le sudoku - 5 points). Dans cet exercice on se propose d écrire deux fonctions qui permettent de tester partiellement une grille de sudoku. Une grille de sudoku sera représentée par un tableau d entiers de 9 par 9. Une case de la grille contient un nombre compris entre 1 et 9 ou bien un 0 pour indiquer que la case est vide. 1. définir la fonction VerifieValeurs qui prend en paramètre une grille de sudoku et qui renvoie 0 si toutes les cases ont des valeurs correctes ou bien 1 si une case contient une mauvaise valeur. Il ne s agit pas ici de savoir si la grille est bien remplie en respectant les règles du sudoku, mais simplement de vérifier qu il n y a pas dans la grille de valeur supérieure à 9 ou inférieure à 0. 2. définir la fonction ControleLigne qui prend en paramètre une grille de sudoku et un numéro de ligne et qui vérifie que la ligne en question est correctement remplie : les chiffres entre 1 et 9 n apparaissent au plus qu une fois chacun sur la ligne. de l exercice 1. 1. Fonction VerifieValeurs int VerifieValeurs(int grille[9][9]) int i,j; for (i=0; i<9; i++) for (j=0; j<9; j++) if ((grille[i][j]<0) (grille[i][j]>9) ) 2. Fonction ControleLigne On suppose que la grille ne contient pas de valeurs hors rang (négatives ou supérieures à 9). Le tableau controle permet de marquer les valeurs lues sur la ligne. int ControleLigne(int grille[9][9], int ligne) int i; int controle[9]; for (i=0; i<9; i++) controle[i]=0; for (i=0; i<9; i++) if ((grille[ligne][i]>0) && (grille[ligne][i]<=9) ) controle[grille[ligne][i]-1]++; if (controle[grille[ligne][i]-1] > 1) 1
On peut aussi contrôler sans mémoriser les valeurs déjà lues, il faut alors parcourir plusieurs fois le tableau : int ControleLigne(int grille[9][9], int ligne) int i,j; for (i=0; i<8; i++) for (i=i+1; i<9; i++) if ((grille[ligne][i]>0) && (grille[ligne][i]<=9) ) if (grille[ligne][i] == grille[ligne][j]) Exercice 2 (Les accolades - 4 points). Une des contraintes syntaxiques d un programme écrit en langage C est de respecter les délimiteurs de blocs : à chaque accolade ouvrante () doit correspondre une accolade fermante (). On ne s intéressera dans cet exercice qu aux seules accolades. 1. Ecrire un programme en C qui prend en paramètre le nom d un fichier source et qui vérifie que les accolades sont correctement positionnées dans ce fichier. Pour ce faire vous devez lire le fichier ligne par ligne, pour chaque ligne vous devrez parcourir la ligne à la recherche des accolades. Il suffit de compter les accolades en incrémentant un compteur chaque fois que l on trouve une accolade ouvrante, et en décrémentant ce même compteur chaque fois que l on trouve une accolade fermante. Ainsi, on peut distinguer trois cas de figures : si le compteur passe en dessous de 0, on a un problème : il y a plus d accolades fermantes que d accolades ouvrantes rencontrées jusqu à présent. On peut donc arrêter l analyse et renvoyer une erreur. si à la fin du fichier le compteur est strictement supérieur à 0 : il y a aussi un problème, on a ouvert plus d accolades que ce que l on en a fermé. Il faut alors renvoyer une erreur. Enfin, à la fin du fichier le compteur est à 0 : les accolades sont correctement positionnées. La fonction renvoie le code de succès. de l exercice 2. Lecture du fichier caractère par caractère : #include <stdio.h> #include <stdlib.h> int main(int argc, char**argv) FILE *fic; char c; int cpt=0; if((fic=fopen(argv[1],"r"))==null) printf("erreur d ouverture\n"); exit(-1); 2
while(c=getc(fic)) if(c== ) cpt++; if(c== ) cpt--; if (cpt<0) printf("accolade fermante surnuméraire\n"); if (cpt >0) printf("accolade ouvrante surnuméraire\n"); printf("nombre d accolades ouvrantes et fermantes égaux\n"); Version lisant dans le fichier par chaîne de caractères (ici par 256 caractères) : #include <stdio.h> #include <stdlib.h> int main(int argc, char**argv) FILE *fic; char ligne[256]; int cpt=0; if((fic=fopen(argv[1],"r"))==null) printf("erreur d ouverture\n"); exit(-1); while(fgets(ligne,256,fic)) for(i=0;ligne[i]!= \n ;i++) if(ligne[i]== ) cpt++; if(ligne[i]== ) cpt--; if (cpt<0) printf("accolade fermante surnuméraire\n"); 3
if (cpt >0) printf("accolade ouvrante surnuméraire\n"); printf("nombre d accolades ouvrantes et fermantes égaux\n"); Exercice 3 (Le compte en banque - 11 points). Le programme informatique d une banque, repose sur la structure suivante pour représenter les comptes de ses clients. typedef struct cpte int num; /* numéro du compte*/ char nom[30]; /* nom du propriétaire du compte */ char adresse[100]; /* adresse du propriétaire */ float solde; /* le solde du compte au début du mois en cours*/ ope* operations; /* les opérations du mois en cours */ compte; Le champ operations de la structure permet d enregistrer les opérations en cours de mois afin de calculer le nouveau solde du compte lorsque l on change de mois. L ensemble des opérations sera représenté par une liste chaînée. 1. Donnez la structure du type ope qui permet d enregistrer une opération et qui est donc un élément de la liste chaînée. Chaque opération contiendra les champs suivants : libelle : une chaîne contenant le libellé de l opération date : la date de l opération. On utilisera le type tdate que l on suppose définit ailleurs. type : un caractère, d si l opération est un débit, et c si il s agit d un crédit. montant : le montant de l opération un nombre à virgule positif qui sera à ajouter au solde si l opération est un crédit et à retrancher si il s agit d un débit. 2. Donnez la définition de la fonction NouveauSolde qui prend en paramètre un compte et qui renvoie le nouveau solde du compte en fonction des opérations qu il contient. 3. Définir la fonction NouvelleOperation qui prend en paramètre toutes les informations d une opération et renvoie un pointeur sur un nouveau ope dont les différents champs ont été correctement affectés. 4. En utilisant la fonction précédente écrire la fonction AjouteOperation qui prend en paramètre un pointeur sur un compte et toutes les informations d une opération et qui ajoute l opération dans la liste des opérations du compte. Les opérations doivent être par ordre chronologique. L ajout doit donc se faire au bon endroit. Pour cela on supposera que l on dispose de la fonction CompareDates(tDate d1, tdate d2) qui compare deux dates, et renvoie 1 si d1 est antérieure à d2, 0 si d1 et d2 sont les même dates, et 1 si d1 est postérieure à d2. 4
de l exercice 3. 1. La structure du type ope : typedef struct opera char libelle[20]; tdate date; char type; float montant; struct opera *suiv; ope; 2. La fonction NouveauSolde : float NouveauSolde(compte cpte) float nouveausolde; ope* ope_cour; nouveausolde = cpte.solde; ope_cour = cpte.operations; while (ope_cour!= NULL) if (ope_cour->type== d ) nouveausolde = nouveausolde - ope_cour->montant; nouveausolde = nouveausolde + ope_cour->montant; ope_cour = ope_cour->suiv; return nouveausolde; 3. La fonction NouvelleOperation : ope* NouvelleOperation(char* lib, tdate d, char t, float m) ope* nouv_ope; nouv_ope = (ope *) malloc(sizeof(ope)); strcpy(nouv_ope->libelle,lib); ope->date = d; ope->type = t; ope->montant = m; ope->suiv=null; return nouv_ope; 5
4. La fonction AjouteOperation : void AjouteOperation(compte* cpte,char* lib, tdate d, char t, float m) ope* nouv_ope; ope* ope_cour, ope_pred, ope_suiv; nouv_ope = NouvelleOperation(lib,d,t,m); ope_pred = NULL; ope_cour = cpte->operations; while (ope_cour!= NULL) if (CompareDates(ope_cour->date,d) <= 0) ope_pred = ope_cour; ope_cour = ope_cour->suiv; if (CompareDates(ope_cour->date,d) == 1) ope_pred->suiv = nouv_ope; nouv_ope->suiv = ope_cour; exit; // On insère en fin de liste if (ope_pred == NULL) // La liste est vide! cpte->operations = nouv_ope; ope_pred->suiv = nouv_ope; 6