Serie 6 Corrigé Exercice 1 (niveau 1):Tailles des variables des types de base avec sizeof() Voici le résultat de l'exécution du programme (depuis la VM 2015-16): Taille Taille Taille Taille Taille Taille Taille Taille Taille d'un d'un d'un d'un d'un d'un d'un d'un d'un char : 1 short int : 2 int : 4 long int : 8 long long int : 8 int8_t : 1 float : 4 double : 8 long double : 16 1.1 : Puisqu'une variable de type float occupe 4 bytes, on peut stocker 1024 / 4 = 256 variables de type float dans 1024 bytes. Pour les double, on peut y stocker seulement 128 variables 1.2 : La taille du type int en bits est de 4 bytes * 8 = 32 bits, car il y a 8 bits par byte. 1.3 : Oui, depuis la VM 2015-16 le type int est codé sur 4 octets tandis que long int est codé sur 8 octets. Par contre il n’y a pas de différence entre long int et long long int car les deux types sont sur 8 octets. Exercice 2 (niveau 1): Conséquences d'un overflow avec des nombres entiers Les résultats, qu'il fourmit, sont : 500 + 2500 = 3000 1000000000 + 1000000000 = 2000000000 1500000000 + 1500000000 = -1294967296 (overflow) Comme un type int est codé sur 32 bits (avec signe), l'intervalle des valeurs admises est [-231...231-1] = [-2147483648...2147483647]. C'est beaucoup, mais pas suffisant pour faire le calcul demandé. Exercice 3 (niveau 1): Le compteur entier détraqué Le programme incrémente bien la variable, jusqu'à ce que celle-ci atteigne la valeur entière positive maximum 2147483647, qui est équivalente à 231 -1. Si on ajoute une unité, la retenue modifie le bit de signe qui passe alors à 1. Cela est interprété comme un nombre négatif. Il s’agit du plus petit nombre négatif représentable dans la représentation choisie. C’est un cas d’overflow. Ensuite à chaque ajout de une unité on revient vers vers les nombres positifs. Donc la boucle va recommencer à faire un overflow plus tard. Exercice 4 (niveau 1): opérateur de division avec des nombres entiers L'erreur est faite quand on affecte à la variable f le résultat d'une division entière (a et b étant de type int) car la division de 2 entiers donne un quotient entier sans partie fractionnaire. Par exemple : 5 / 9 = 0. Il faut donc demander explicitement une conversion en type float de l'une des deux variables (au moins). // faire include de stdio.h et stdlib.h #include <stdio.h> #include <stdlib.h> int main (void) { int a, b; float f; printf ("Entrez deux nombres entiers: "); scanf ("%d %d", &a, &b); f = (float) a / b; printf ("La fraction %d / %d est egale a %f\n", a, b, f); } return EXIT_SUCCESS; Exercice 5 (niveau 1): Conversion de degrés Fahrenheit (°F) en degrés Celsius (°C) L'erreur classique est de recopier la formule mathématique sans faire attention aux types des constantes. En particulier, si on recopie la fraction 5/9 celle-ci est interprétée par le compilateur comme une division de deux entiers, c'est à dire une division entière qui donne comme résultat zéro... Or ce qu'on veut est bien sûr le quotient avec une partie fractionnaire ; pour cela il faut indiquer qu'on travaille avec des constante de type double (ou float) comme ceci: 5.0/9. // faire include de stdio.h et stdlib.h #include < stdio.h> #include < stdlib.h> int main (void) { float f, /* Temperature en degres Fahrenheit */ c; /* Temperature en degres Celsius */ printf("Entrez la temperature en degres Fahrenheit :"); scanf ("%f", &f); c = (f - 32.) * (5./9.); if (c > -273.15) printf ("La temperature en degres Celsius vaut %f\n", c); else printf("Votre valeur doit etre superieure au zero absolu\n"); } return EXIT_SUCCESS; Exercice 6 (niveau 1): Conversion en heures minutes-secondes d'un nombre de secondes et l'opérateur modulo % C'est une application typique de l'opérateur de division entière et du modulo de nombres entiers. // faire include de stdio.h et stdlib.h #include <stdio.h> #include <stdlib.h> int main (void) { int s; printf ("entrez le nombre de secondes: "); scanf ("%d", &s); printf ("cela correspond a : %u h %u min %u secondes", s / 3600, (s % 3600) / 60, s % 60); return EXIT_SUCCESS; } Exercice 7 (niveau 1): Conversion d'un float en int le plus proche La conversion automatique d'un float ou d'un double en int est faite en supprimant la partie fractionnaire: on obtient la partie entière. Ce n'est pas un arrondi à l'entier le plus proche. Sachant cela, pour obtenir l'arrondi à l'entier le plus proche il suffit de prendre la partie entière du nombre augmenté de 0.5 . // faire include de stdio.h et stdlib.h #include <stdio.h> #include <stdlib.h> int main (void) { } float f; printf ("Donnez un nombre reel: "); scanf ("%f", &f); printf ("Nombre entier le plus proche: %d\n", (int) (f + 0.5)); return EXIT_SUCCESS; Exercice 8 (niveau 1): Opérateurs bit à bit Voici le program, qui affiche un message indiquant si le bit p du nombre n est à 1 ou pas : #include < stdio.h> #include < stdlib.h> int main (void) { unsigned n ; int p; printf ("nombre unsigned: "); scanf("%u",&n); printf ("indice du bit [0, 31]:"); scanf("%d",&p); printf ("Le bit %d est à %d\n", p,((1<<p)&n)?1:0); } return EXIT_SUCCESS; NOTE : l’opérateur conditionnel (?:) évalue une expression retournant une valeur si cette expression est vraie et une autre si l'expression est faux, donc l’expression : printf ("Le bit %d est à %d\n", p,((1<<p)&n)?1:0); est équivalent à: int isEqual; if ((1<<p)&n) isEqual = 1; else isEqual = 0; printf ("Le bit %d est à %d\n", p, isEqual); Pour qu'il affiche le nombre total de bits à 1 et à 0 du nombre n, il faut le modifier comme ci-dessous : #include <stdio.h> #include <stdlib.h> int main (void) { unsigned n, mask; int count_1 =0; printf ("nombre unsigned: "); scanf("%u",&n); mask = 1; do { count_1 += ((mask&n)?1:0); mask = mask << 1 ; }while(mask); } printf ("Le nombre de bits à 1 est à %d\n", count_1); printf ("Le nombre de bits à 0 est à %d\n", 32-count_1); return EXIT_SUCCESS;