Université Paris-Nord Institut Galilée Année 2008-2009 Licence 1-2ième semestre Travaux dirigés 3 : pointeurs et fonctions L1 L objectif de ce TD est de mettre en évidence le fait que les paramètres formels sont des variables locales aux fonctions. Les variables locales ont une place mémoire allouée au début de l exécution de la fonction et libérée à la fin de l exécution. Si l on souhaite modifier des variables déclarées en dehors de la fonction, il faut définir des paramètres formels pointeurs et les initialiser avec les adresses de ces variables. 1 Initialisation d un tableau passé en paramètre Soit le programme suivant : #include <stdlib.h> /* EXIT_SUCCESS */ #include <stdio.h> /* printf */ void init_tableau(int t[],int taille); int main() /* un tableau et sa taille */ int tab[2]; int taille = 2; int i; /* var boucle */ /* représenter l occupation mémoire */ identificateur adresse valeur tab[0] 1000? tab[1] 1004? taille 1008 2 i 1012? init_tableau(tab,taille); /* représenter l occupation mémoire */ Remarquer que la zone mémoire de init_tableau a été désallouée. identificateur adresse valeur tab[0] 1000 0 tab[1] 1004 1 taille 1008 2 i 1012? 1
for(i = 0;i < taille;i = i + 1) printf("%d ",tab[i]); printf("\n"); return EXIT_SUCCESS; void init_tableau(int t[],int taille) int i; /* représenter l occupation mémoire */ Remarquer que l on donne toute l occupation mémoire du prog. Il faut distinguer taille et i de main et de init_tableau, même si c est pas très clair avec cette présentation. Insister sur le fait que la zone mémoire de init_tableau est désallouée/perdue à la fin de identificateur adresse valeur tab[0] 1000 0 tab[1] 1004 1 l exécution de la fonction (voir plus haut). taille 1008 2 i 1012? t 8000 1000 taille 8004 2 i 8008? for(i = 0;i < taille;i = i + 1) t[i] = i; Représenter l occupation mémoire comme indiqué en commentaires. Qu affiche le programme? Pour déterminer les adresses, on fera les simplifications suivantes 1 : les données sont réservées en mémoire dans l ordre de leur déclaration ; les données allouées dans la fonction main démarre à 1000 ; les données allouées dans la fonction init_tableau démarre à 8000 ; l architecture est 32 bits Proposez une réécriture de la procédure init_tableau qui permet de faire l économie de la variable de boucle (i). var de boucle. taille est une variable locale donc on peut la modifier et l utiliser comme 1 Le choix des adresses est arbitraire, seule importe l observation que les données locales allouées dans une fonction ont un espace mémoire propre. 2
void init_tableau(int t[],int taille) for(taille = taille - 1;taille >= 0;taille = taille - 1) t[taille] = taille; 2 Recopie de tableaux Nous souhaitons écrire une procédure recopie_tableau qui prend en entrée deux tableaux de réels de même taille, original et copie, leur taille taille et qui recopie les valeurs de original dans copie. 1. Donner le prototype de cette fonction. Les deux sont strictement équivalents mais on préfère la b (sucre syntaxique pour le passage de tableaux) : (a) void recopie_tableau(double *original,double *copie,int taille) ; (b) void recopie_tableau(double original[],double copie[],int taille) ; 2. Définir cette fonction. 3. Écrire une programme simple permettant de tester cette fonction. Faire une trace si besoin. On peut faire sans affichage_tableau. #include <stdlib.h> /* EXIT_SUCCESS */ #include <stdio.h> /* printf */ /* déclaration de fonctions utilisateurs */ void affichage_tableau(double t[],int taille); void recopie_tableau(double original[],double copie[],int taille); int main() double original[5] = 1,2,3,4,5; double copie[5] = 5,4,3,2,1; recopie_tableau(original,copie,5); affichage_tableau(copie,5); return EXIT_SUCCESS; void affichage_tableau(double t[],int taille) int i; /* var. boucle */ 3
for(i = 0;i < taille;i = i + 1) printf("%g\n",t[i]); void recopie_tableau(double original[],double copie[],int taille) int i; /* var. boucle */ for(i = 0;i < taille;i = i + 1) copie[i] = original[i]; 3 Les rationnels, suite et fin Cet exercice est à terminer en TP pour tester votre codage. 1. Réécrire les fonctions lit_rat, somme_rat, produit_rat, affiche_rat, difference_rat, quotient_rat sous forme de procédures, c est-à-dire sans valeur de retour. Le résultat du calcul sera communiqué par un paramètre supplémentaire jouant le rôle de paramètre de sortie. Il y a rend_irreductible aussi pour ceux qui l ont fait. /* prototypes */ void lit_rat(struct rat *p_r); void affiche_rat(struct rat r); void somme_rat(struct rat r1, struct rat r2, struct rat *p_res); void produit_rat(struct rat r1, struct rat r2, struct rat *p_res); void rend_irreductible(struct rat *p_r); /*fonctions */ void lit_rat(struct rat *p_r) scanf("%d", &p_r->num); scanf("%d", &p_r->deno); rend_irreductible(p_r); void affiche_rat(struct rat r) printf("(%d/%d)\n", r.num, r.den); void somme_rat(struct rat r1, struct rat r2, struct rat *p_res) 4
p_res->num= r1.num * r2.den + r2.num * r1.den; p_res->den= r1.den * r2.den; rend_irreductible(p_res); void produit_rat(struct rat r1, struct rat r2, struct rat *p_res) p_res->num= r1.num * r2.num; p_res->den= r1.den * r2.den; rend_irreductible(p_res); void rend_irreductible(struct rat *p_r) int diviseur; if (p_r->num < p_r->den) diviseur= p_r->num; else diviseur= p_r->den; while (diviseur > 1) if (p_r->num % diviseur == 0 && p_r->den % diviseur == 0) p_r->num= p_r->num / diviseur; p_r->den= p_r->den / diviseur; diviseur = diviseur - 1; 2. Modifier le programme de la mini-calculatrice pour utiliser ces fonctions. Que le main... int main() struct rat nombre_g; /* membre gauche de l expression */ struct rat nombre_d; /* membre droit de l expression */ char op; /* operateur */ struct rat expr; /* resultat de l expression */ /* saisie expression */ printf("les nombres ici sont rationnels. Pour saisir un nombre saisir le nume printf("entrez une expression de la forme : nombre operateur nombre\n"); lit_rat(&nombre_g); 5
scanf(" %c",&op); lit_rat(&nombre_d); /* calcul valeur expression */ /* cas mutuellement exclusif */ if(op == + ) /* addition */ somme_rat(nombre_g,nombre_d,&expr); if(op == - ) /* soustraction */ difference_rat(nombre_g,nombre_d,&expr); if(op == * ) /* multiplication */ produit_rat(nombre_g,nombre_d,&expr); if(op == / ) /* division */ quotient_rat(nombre_g,nombre_d,&expr); /* affichage resultat */ affiche_rat(expr); return EXIT_SUCCESS; 3. Étendre les fonctionnalités de la mini-calculatrice pour faire des opérations entre rationnels et entiers. Des exemples d expressions valides sont : 2 3 / 2 2 + 3 5 3! + 4 5 Cette question n est pas corrigée et doit être faite que par ceux qui ont tout terminé, le TP ddd compris. Une solution est d écrire une procédure void lire_expression(struct rat *p_nombre_g,struct rat *p_nombre_d) qui normalise les entrées sous la forme de rationnels. N.B. il faut que les expressions puissent être parsées de façon déterministe, d où le. Ils verront la reprise sur erreurs en E/S avancées. 6