Programmation Impérative en Langage C Examen (durée 2 heures) CORRECTION de la Première Session du 11 Janvier 2012 Remarque : Ce document ne présente que des éléments de correction. Les variantes possibles sont nombreuses. Exercice 1 : Questions de cours 1) À quoi sert un compilateur? À traduire un langage de programmation (par exemple C) en langage machine (fichier binaire décrivant une suite d instructions compréhensibles par le processeur) 2) Comment est-il possible de récupérer les arguments de la ligne de commande? En spécifiant et en utilisant les paramètres argc et argv de la fonction principale : int main (int argc, char *argv[]) 3) Dans l usage de la fonction printf(), que signifient les formatages %s et %c? Il signifient qu une chaîne de caractères et un caractère doivent être respectivement affichés en remplacement du %s et du %c. 4) Combien de fonctions main() faut-il dans un programme? Pourquoi? Il faut une et une seule fonction main() dans un programme. En effet, c est le point de départ de l exécution du programme, et il ne peut y en avoir qu un seul, pas plus! Mais il en faut impérativement un. 5) Pour accéder à une case d un tableau, quel opérateur utilise-t-on? On utilise deux crochets [] 6) Dîtes ce que fait l instruction suivante i += 3 ; Elle ajoute 3 à la variable i 7) À quoi sert la fonction fprintf()? À écrire dans un fichier 8) À quoi sert la fonction feof()? À tester si la fin de fichier à été atteinte 9) Lorsqu on a utilisé la fonction malloc() quelque part, que faut-il faire avant la fin du programme? La fonction malloc() permet de réservez dynamiquement de la mémoire. Il faut donc libérer cette mémoire lorsqu elle n est plus utile. Pour ce faire, il faut appeler la fonction free() avant la fin du programme. 10) Qu est-il possible d observer lors de l exécution d un programme avec un debugger? Il est possible d observer l évolution du contenu des variables (à chaque instruction en mode pas à pas, où seulement à certains moments en posant des points d arrêt) 11) On utilise le logiciel Glade et la bibliothèque GTK pour construire quoi? Pour construire des interfaces graphiques (GUI) 12) À quoi servent les logiciels Visual Studio et Eclipse? Ce sont des environnement de développement. Il intègrent plusieurs outils en un seul logiciel : éditeur de texte, compilateur, debugger, etc. Il servent donc à écrire, compiler et exécuter des programmes. (Comme avec une console, notepad++ et GCC) E Les connaissances générales du domaine sont validées Guillaume Rivière 1
Exercice 2 : Compteur d occurrences (au clavier) Écrire un programme dans lequel l utilisateur entre 20 nombres entiers au clavier, et qui affiche ensuite le nombre total de nombres strictement positifs lus, strictement négatifs et nuls. 1 # include <stdio.h> 2 3 int main () { 4 int i, n, pos =0, neg =0, nul =0 ; 5 6 for (i=0 ; i <20 ; i ++) { 7 printf (" Donnez un nombre : ") ; 8 scanf ("%d", &n) ; 9 if (n > 0) 10 pos ++ ; 11 else if ( n < 0) 12 neg ++ ; 13 else 14 nul ++ ; 15 } 16 17 printf (" Positifs : %d\n", pos ) ; 18 printf (" Negatigs : %d\n", neg ) ; 19 printf (" Nuls : %d\n", nul ) ; 20 21 return 0 ; 22 } Exercice 3 : Moyenne d un tableau Écrire une fonction qui calcule la moyenne des valeurs du tableau d entiers, de taille N, donné en paramètre. La fonction retournera le résultat du calcul. Le prototype de la fonction sera le suivant : double moyenne (int *a, int N) ; 3 double moyenne ( int *a, int N) { 4 int i, sum =0 ; 5 for ( i=0 ; i<n ; i ++) 6 sum += a[ i] ; 7 return sum / ( double ) N ; 8 } D Les exercices donnés à l avance sont résolus Exercice 4 : Le point le plus proche Plaçons nous par exemple dans le contexte du développement d une couche logicielle pour un écran tactile multipoint (smartphone, table interactive, touchsmart,...). Pour implémenter le double clic, nous avons besoin de déterminer le point le plus proche par rapport à un ensemble de points (i.e. l ensemble des points détectés dans la frame précédente). Remarquons que ce type de calcul pourrait aussi bien aider à déterminer la direction à prendre pour un robot devant passer par ensemble de cibles, ou encore pour un livreur de colis. Écrire une fonction qui détermine quel point est le plus proche d un point P parmi un ensemble de N points. Le point P sera représenté par ses coordonnées entières xp et yp. L ensemble de points sera représenté par deux tableaux d entiers x et y, chacun de taille N, stockant respectivement les abscisses et les ordonnées des points. La fonction retournera l indice du point le plus proche. Le prototype de la fonction sera le suivant : int le plus proche (int xp, int yp, int *x, int *y, int N) ; Par exemple, soient les deux tableaux tab x et tab y de taille 5 représentant les coordonnées d un ensemble de points. Soit le point P de coordonnées (2, 1). Guillaume Rivière 2
L appel de la fonction le plus proche(1,2,tab x,tab y,5) devra alors retourner 3, c.à.d. l indice du point de coordonnées (1,3). Pour réaliser cet exercice, vous utiliserez et écrirez aussi une fonction qui calcule la distance euclidienne entre deux points. Son prototype sera le suivant : double distance (int xa, int ya, int xb, int yb) ; 8 int le_plus_proche ( int xp, int yp, int *x, int *y, int N) { 9 int i, pos = -1 ; 10 double d, dmin ; 11 12 if (N > 0) { 13 /* Premier point */ 14 dmin = distance ( xp, yp, x[0], y [0]) ; 15 pos = 0 ; 16 17 /* Les autres points */ 18 for (i=1 ; i<n ; i ++) { 19 d = distance (xp, yp, x[i], y[i]) ; 20 if (d <= dmin ) { 21 d = dmin ; 22 pos = i ; 23 } 24 } 25 } 26 27 return pos ; 28 } 4 double distance ( int xa, int ya, int xb, int yb) { 5 return sqrt (( xb - xa) * (xb - xa) + (yb - ya) * (yb - ya)) ; 6 } C Les briques de base sont maîtrisées dans un exercice nouveau Exercice 5 : Matrices 1) Écrire une fonction qui vérifie si la matrice carré d entiers, de taille N, passée en paramètre, est symétrique. Une matrice carré est symétrique lorsqu elle est égale à sa propre transposée. Une façon simple pour déterminer si une matrice A est symétrique est de vérifier que i, j tq i < j on a : A i,j = A j,i. Ainsi, on ne se préoccupe pas des valeurs de la diagonale. Par exemple, ces quatre matrices sont des matrices symétriques : 1 4 6 8 0 1 2 3 1 0 0 0 4 1 9 7 1 0 6 4 0 2 0 0 6 9 1 5 2 6 0 5 0 0 3 0 8 7 5 1 3 4 5 0 0 0 0 4 La fonction retournera 1 si la matrice est symétrique, et 0 sinon. Le prototype de la fonction sera le suivant : char est symetrique (int **A, int N) ; Guillaume Rivière 3
VERSION NAÏVE : 4 char est_symetrique ( int ** A, int N) { 5 int i, j ; 6 char res = 1 ; /* VRAI */ 7 8 for (i=0 ; i<n ; i ++) { 9 for (j=0 ; j<n ; j ++) { 10 if (i < j && A[i][j]!= A[j][i]) 11 res = 0 ; /* FAUX */ 12 } 13 } 14 15 return res ; 16 } VERSION OPTIMISÉE : 32 char est_symetrique_v3 ( int ** A, int N) { 33 int i, j ; 34 char res = 1 ; /* VRAI */ 35 36 for (i=0 ; res && i<n ; i ++) { 37 for ( j=i+1 ; res && j<n ; j ++) { 38 if (A[i][j]!= A[j][i]) 39 res = 0 ; /* FAUX */ 40 } 41 } 42 43 return res ; 44 } VERSION EFFICACE : 18 char est_symetrique_v2 ( int ** A, int N) { 19 int i, j ; 20 char res = 1 ; /* VRAI */ 21 22 for (i=0 ; i<n ; i ++) { 23 for ( j=i+1 ; j<n ; j ++) { 24 if (A[i][j]!= A[j][i]) 25 res = 0 ; /* FAUX */ 26 } 27 } 28 29 return res ; 30 } 2) Écrire une fonction qui réalise l addition de deux matrices A et B dans une troisième C, et toutes trois de dimension N M. On veut donc une fonction qui réalise l opération i, j : C i,j = A i,j + B i,j. Le prototype de la fonction sera le suivant : void addition (int **C, int **A, int **B, int N, int M) ; 46 void addition ( int ** C, int ** A, int ** B, int N, int M) { 47 int i, j ; 48 49 for ( i=0 ; i<n ; i ++) 50 for ( j=0 ; j<m ; j ++) 51 C[i][j] = A[i][j] + B[i][j] ; 52 } B Manipulation de structures de données complexes Exercice 6 : Chiffres, lettres et caractères de ponctuation 1) Écrire une fonction qui compte le nombre de chiffres, de lettres et de caractères de ponctuation, dans la chaîne de caractères qui lui est passée en paramètre. Après appel de la fonction, les 3 valeurs comptées seront récupérables dans les variables entières dont l adresse aura été donnée en argument de la fonction. Le prototype de la fonction sera donc le suivant : void compter (const char *s, int *cpt chiffre, int *cpt lettre, int *cpt ponctuation) ; Aide : voici quelques fonctions de ctype.h et string.h La fonction int isalpha(char c) retourne vrai si c est un caractère alphabétique, faux sinon. La fonction int isdigit(char c) retourne vrai si c est un chiffre, faux sinon. La fonction int ispunct(char c) retourne vrai si c est un caractère de ponctuation, faux sinon. La fonction int strlen(const char *s) retourne la longueur de la chaîne passée en paramètre. Guillaume Rivière 4
5 void compter ( const char *s, int * cpt_chiffre, int * cpt_lettre, int * cpt_ponctuation ) { 6 int i ; 7 * cpt_chiffre = * cpt_lettre = * cpt_ponctuation = 0 ; 8 for (i=0 ; i< strlen (s) ; i ++) 9 if ( isdigit (s[i])) 10 (* cpt_chiffre ) ++; 11 else if ( isalpha (s[i])) 12 (* cpt_lettre ) ++ ; 13 else if ( ispunct (s[i])) 14 (* cpt_ponctuation ) ++ ; 15 } VARIANTE : 17 void compter_v2 ( const char *s, int * cpt_chiffre, int * cpt_lettre, int * cpt_ponctuation ) { 18 const char * c = s ; 19 * cpt_chiffre = * cpt_lettre = * cpt_ponctuation = 0 ; 20 while (*c!= \0 ) { 21 if ( isdigit (*c)) 22 (* cpt_chiffre ) ++; 23 else if ( isalpha (* c)) 24 (* cpt_lettre ) ++ ; 25 else if ( ispunct (* c)) 26 (* cpt_ponctuation ) ++ ; 27 c++ ; 28 } 29 } 2) Écrire une fonction main() qui appelle la fonction compter() de la question précédente sur la chaîne de caractère suivante : Vive la programmation!!! Et 1, et 2, et 3... zero!. Ensuite le programme affichera le nombre de chiffres, de lettres et de caractères de ponctuation de la chaîne. 32 int main () { 33 int c, l, p ; 34 35 compter (" Vive la programmation!!! Et 1, et 2, et 3... zero!", &c, &l, &p) ; 36 37 printf (" Chiffres = % d\ n", c) ; 38 printf (" Lettres = % d\ n", l) ; 39 printf (" Ponctuation = % d\ n", p) ; 40 41 return 0 ; 42 } A La notion de fonction est réellement acquise et l utilisation des pointeurs est maîtrisée Guillaume Rivière 5