ECP – Option SA Henri Fallon <henri.fallon@centraliens.net> “Rappels” de C, la suite ECP – Option SA Henri Fallon <henri.fallon@centraliens.net>
Macros « Instructions » de remplacement sont interprétées avant le compilateur remplacement « textuel » exemples : #define PI 3.141592 #define CINQ (3+2) #define BIZARRE ,12); printf("Pi vaut %f, Cinq vaut %d, et douze vaut %d\n", PI, CINQ BIZARRE printf("Pi vaut %f, Cinq vaut %d, et douze vaut %d\n", 3.141592, (3+2) ,12);
Macro : danger #define CINQ 3+2 printf("3*5 vaut-il %d ?\n", 3*CINQ); /* Correct */ #define CINQ (3+2) #define FOIS_TROIS(x) (x*3) printf("cinq fois trois vaut-il %d?\n",FOIS_TROIS(3+2)); printf("cinq fois trois vaut-il %d?\n",(3+2*3)); /* Correct */ #define FOIS_TROIS(x) ((x)*3)
Choix multiples Pour éviter les nombreux « if » « else » switch( variable ) { case valeur_1: instructions_1; break; case valeur_2: instructions_juste_pour_2; /* que se passe-t-il si on ne met pas break ? */ case valeur_3: instructions_pour_2_et_3; default : printf("Valeur inconnue"); }
Meilleur contrôle des boucles Sortir d'une boucle : break int i=0; while(1) { printf("trois fois en tout\n"); if( ++i > 3 ) break; } /* Nous venons de réinventer la boucle "for" */ Passer à l'éxécution suivante : continue int i; for( i=-5; i<6; i++ ) { /* Evitons la division par zéro */ if( !i ) continue; printf( "100/%d = %d\n", i, 100/i ); }
Les structures Permettent de clarifier le code en stockant dans une seule variable un ensemble de variables struct rectangle { unsigned int longueur; unsigned int largeur; } r; r.longueur = 12; r.largeur = 42; printf("L'aire de r est %d\n", r.longueur * r.largeur );
Les structures (2) Lourdeur des déclaration : struct rectangle { unsigned int longueur; unsigned int largeur; } r; struct rectangle r2; r.longueur = 12; r.largeur = 42; r2=r; printf("L'aire de r est %d\n", r.longueur * r.largeur );
Definir ses types instruction typedef typedef int mytype_int; typedef struct _rectangle { unsigned int longueur; unsigned int largeur; } rectangle; rectangle r; r.longueur = 12; r.largeur = 42; printf("L'aire de r est %d\n", r.longueur * r.largeur );
La memoire Variable dans les fonctions La fonction malloc dites « automatiques » allouées au début de la fonction automatiquement désallouées à la fin La fonction malloc permet d'allouer un « morceau » de memoire qui persiste même après le retour de la fonction ne la libère pas automatiquement : risque de « fuite memoire »
Variables automatiques : le piège char * chaine( void ) { char c[]= "chaine de retour"; return c; } /* ce programme va planter ! */ int main(void) { char * test; test = chaine(); printf("%s\n", test ); return 0;
malloc : allocation dynamique char * chaine( void ) { char * c; c = (char *)malloc( 5 * sizeof(char) ); return c; } /* ce programme va fonctionner ! */ int main( void ) { char * test; test = chaine(); printf("%s\n", test ); return 0;
libération La memoire allouée reste allouée ! Possibilité de « perdre » le pointeur : memory leak La fonction free /* ce programme va fonctionner ! */ int main( void ) { char * test; test = chaine(); printf("%s\n", test ); free(test); return 0; }
ré-allocation fonction realloc même retour que malloc
Bonnes pratiques tester le retour de malloc toujours libérer la memoire dès que possible lire le manuel des fonctions : allouent-elles la memoire ou doit-on l'allouer avant ? utiliser sizeof if( (p=malloc( taille * sizeof( int ) ) == NULL ) { printf("Erreur d'allocation\n"); return -1; } p[0] = 12; /* .... */
Les cast (transtypage) Conversion explicite d'un type à un autre Attentions aux casts implicites ! unsigned int positif = 10; int negatif = -12; if( positif < negatif ) { printf("ah ben bravo l'implicite"); } if( negatif < (int)positif ) { printf("Il faut tout faire soi-même"); }ᄇ
A la pratique !