Vous êtes sur la page 1sur 4

Rattrapages en langage C, correction

Oprations fondamentales sur les tableaux I. Dans le main, crer un tableau dentiers de taille 30, remplissez le avec des nombres alatoires et trouvez-en le maximum de trois faons diffrentes. Si on doit tout faire dans le main, trois faons diffrentes signifie trois critures diffrentes pour les boucles. On a for, while et do while. Attention : il serait incorrect de dire que la fonction main prend un tableau, le rempli avec des valeurs alatoires, etc. etc. . La fonction main prend toujours un nombre darguments (argument count) et la valeur de ses arguments (argument values). Aprs, elle fait diffrentes choses int main(int argc, char **argv){ int tab[30], i, vMax; /* On fait du C : on dclare toutes les variables, puis on les utilise */ srand(time(NULL)); /* Il faut initialiser lalatoire. Penser faire #include <time.h> */ vMax = tab[0]; /* On initialise le maximum la premire valeur du tableau */ for(i=0; i < 30; i+ +){ /* On peut tout faire en une passe ! */ tab[i]=rand(); /* Nombre alatoire. Penser faire #include <stdlib.h> */ if(vMax < tab[i]) vMax = tab[i] ; /* On a trouv un nouveau maximum, on remplace. */ } return vMax; } Les deux autres critures de la boucle, avec while et do while : i = 0; while(i < 30){ tab[i] = rand() ; if(vMax < tab[i]) vMax = tab[i] ; i++; } i = 0; do{ tab[i] = rand() ; if(vMax < tab[i]) vMax = tab[i]; i++; }while(i < 30);

Crez une fonction vector_Random qui, tant donn un tableau, le remplisse de nombres alatoires. Etant donn un tableau ne signifie pas que le seul paramtre fourni la fonction sera le tableau ! En effet, la taille du tableau est galement un paramtre. Donc on a dj vector_Random(int tab[], int n). Un tableau est en ralit une adresse mmoire et une certaine zone (sa taille). Quand on passe le tableau la fonction, ce quon passe est donc un pointeur sur une adresse mmoire : la fonction va modifier en mmoire le tableau. Donc, en sortie de la fonction, les modifications seront toujours l. Il ny a donc pas besoin de renvoyer le tableau ou quoi que ce soit : on est all le modifier. Ceci nest valable que si lobjet sur lequel on travaille est pass par un pointeur ! Par exemple la mthode void add(int a){ a = a + 10 ;} va modifier localement la variable a, et aprs tout sera oubli. En revanche, void add(int *a){ *a = *a + 10 ;} va modifier la variable a en mmoire ! La solution intermdiaire est int add(int a){ return a + 10 ;}, i.e. cration de variables locales et retour. void vector_Random(int tab[],int n){ int i, vMax; /* Nos variables locales */ srand(time(NULL)); /* Toujours penser initialiser lalatoire */ for(i=0; i < n; i++) /* Remplie le tableau avec des nombres alatoires (pas de faon alatoire !) */ tab[i]=rand(); /* Pas besoin daccolades si on a une seule instruction */ } Philippe Giabbanelli 1 Mai 2006

Crer une fonction vector_Max qui, tant donn un tableau, en dtermine le maximum. Rien de nouveau ici. int vector_Max(int tab[],int n){ int i, vMax; vMax = tab[0]; for(i=0; i < n; i++) if(vMax<tab[i]) vMax = tab[i]; return vMax; } Au dmarrage du programme, il doit maintenant proposer dessayer ces fonctions (oui / non). Avant, on a eu besoin de faire #include <time.h> car on utilisait la fonction time et #include <stdlib.h> car on utilisait la fonction rand. Il ne devait y avoir aucun autre #include : on ne demande que ce qui est ncessaire ! On veut maintenant dautres fonctions : scanf, puts, printf. Il ny a que deux fichiers dont il faut se rappeler : - stdio, pour Input/Ouput (entres-sorties). Dfini entre autre scanf, puts, printf et le type FILE. - stdlib, des utilitaires. Dfini entre autre lalatoire (rand) et la gestion mmoire (malloc, free). #include <stdio.h> #include <stdlib.h> #include <time.h> 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. /* Si on ne lutilise pas en complet, on dit pourquoi on linclut */ /* Par exemple : je met stdlib car jutilise rand. */ /* pour utiliser time (initialisation de lalatoire) */

int main(int argc, char **argv){ char reponse ; puts(Voulez-vous tester vos fonctions ? (o/n) ) ; scanf(%c,&reponse) ; if(reponse == o || reponse == O){ puts(Quelle taille voulez-vous ?); int n , *tab; scanf(%d,&n) ; tab = (int *)malloc(n*sizeof(int)); vector_Random(tab, n) ; printf(Le maximum du tableau de %d cases est %d \n , n, vector_Max(tab, n)) ; free(tab) ; /* Librer la mmoire quon a allou nous mme. Ne pas oublier ! */ }else if(reponse == n || reponse == N) puts(Au revoir) ; else puts(Ne pas toujours ecrire nimporte quoi) ; return EXIT_SUCCESS ; }

Rappelons le fonctionnement de scanf. On prend un certain type de donnes (c : character, d : digit,) et on le met ladresse demande. En pratique, on veut stocker la rponse dans une variable : il faut donc utiliser ladresse mmoire de cette variable, que lon demande en la prcdant de &. Il y a deux fonctions importantes daffichage : printf est la plus complte, on peut y mettre des types comme pour scanf, mais on ne doit pas oublier de passer la ligne : \n. puts est une fonction qui affiche une chane de caractres (put string) et fait automatiquement le retour la ligne ; elle est plus rapide. On demande la taille du tableau et lutilisateur, et on va donc le crer dynamiquement, i.e. en demandant nous mme de rserver de la mmoire. On utilise malloc, en lui fournissant la quantit de mmoire rserver. On manipule des entiers (int), et on en manipule n : malloc(n*sizeof(int)). Comme malloc renvoie un pointeur gnrique (void *), on spcifie ce quon a : un pointeur dentiers, (int *)malloc(n*sizeof(int));. Philippe Giabbanelli 2 Mai 2006

vector_Random2 ne devra pas utiliser le symbole [ ]. On a dit quun tableau est en ralit une adresse mmoire. La notation [ ] est quivalent celle avec *. tab[] est ladresse du premier lment du tableau ; on peut le noter *tab, cest un pointeur sur la 1re case ! tab[i] signifie quon avance de i cases par rapport ladresse de tab ; cela quivaut donc *(tab+i). Notons que ce + est de larithmtique des pointeurs, ce nest pas une simple opration. Le + avance de i cases : il najoute pas la valeur i ladresse. Autrement dit, si on a tableau t1 de petits entiers (short) et un tableau t2 de rels (double), alors *(t1 + 10) et *(t2 + 10) ne se dplacent pas dautant doctets (car la case lunit na pas la mme taille), mais ils se dplacent dautant de cases. void vector_Random2(int *tab, int n){ int i; i=0; srand(time(NULL)); while(i < n){ *(tab+i)= rand(); i++; } } vector_maxAbs donne le maximum en valeur absolue, laide dune macro pour la valeur absolue. Une macro est une substitution textuelle : #define NOM equivalent On ne fait pas ceci pour de la performance, cest un simple exercice acadmique. Il est assez dconseill dcrire ses fonctions sous formes de macro car les choses peuvent tre values plusieurs fois On utilise plutt les macros pour dfinir des choses qui ont du sens. Par exemple, si on fait un jeu de rle : #define NORD 0 #define SUD 1 #define OUEST 2 #define EST 3 On facilite ainsi la lecture du code : il est plus parlant de voir NORD que 0 Ce quon veut ici est lgrement plus compliqu : on veut une fonction. Faisons un exemple : #define CARRE(x) x*x #define ADD(x,y) x+y On ne met pas de ; la fin de la ligne, il ny en a pas besoin car cest une substitution textuelle. Par exemple, si on avait b = CARRE(a); dans le code, alors on remplace avec b = a*a; La valeur absolue de x est x sil est positif, et x sil est ngatif. Cest loccasion dutiliser loprateur ? : #define ABS(x) (x>0) ? x : -x /* syntaxe <expression> ? <si vrai> : <si faux> */ /* ndlr : toutes les directives au prprocesseur (commencent par #...) doivent tre au dbut du fichier ! */ int vector_maxAbs(int tab[], int n){ int i, vMax; vMax = ABS(tab[0]); // si le max est une valeur absolue au dpart, plus besoin de le vrifier i=0; while(i < n){ vMax = (vMax>ABS(tab[i])) ? vMax : ABS(tab[i]); i++; } return vMax; } Philippe Giabbanelli 3 Mai 2006

La fonction vector_Sum doit calculer la somme du tableau ; implmentations itratives et rcursives. Rcursif signifie que la fonction doit se rappeler elle-mme. Dites-vous de faon simple que cest itratif lorsque la fonction ne se rappelle pas elle-mme (en ralit, cest un tout petit peu plus subtil). Pour faire la somme de faon itrative, cest simple : on prend une boucle, une variable de rsultat, on somme tout ceci, puis on renvoie le rsultat. Litratif, cest comme on a toujours fait . int vector_Sum(int *tab,int n){ int somme, i; somme =0; for(i=0; i < n; i++) somme = somme + tab[i]; return somme; } Quand on fait du rcursif, cest loccasion de poser proprement ses quations de rcurrence. Si on est capable dcrire la chose de faon mathmatiquement saine, alors coder ce sera juste une petite traduction. Notre fonction somme est une fonction deux variables : un tableau T et un entier n. n > 0 Somme(T, n) = T[n-1] + Somme(T, n-1) n = 0 Somme(T, 0) = 0 La somme dun tableau cest son dernier lment, plus la somme du reste. Si on est arriv au bout, alors on renvoie le neutre pour laddition : cest 0. On pourra comparer avec la dfinition de la factorielle int vector_Sum_Rec(int *tab, int n){ if(n>0) return tab[n-1] + vector_Sum_Rec(tab,n-1); return 0; } La fonction vector_Cut supprime toutes les occurrences de llment pass en paramtre. On commence ici aborder un peu dalgorithmique. Il faut donc toujours commencer par faire soimme un exemple. Aprs on abstrait, et en dernier on code On ne commence jamais par coder ! Soit le tableau 3 2 1 4 5 6 7 4 1 2 3 2 4 2 3 et je veux supprimer toutes les occurrences de 3. Je me donne un pointeur i sur le dbut du tableau et un pointeur j sur la fin du tableau. 3 2 1 4 5 6 7 4 1 2 3 2 4 2 3, i = 0, j = 14. Je vois un 3 : il faut que je le supprime. Je le permute avec la fin, et je dcrmente la fin. Autrement dit : jai un lment supprimer, je le met en bout de tableau, et je raccourci le tableau. 3 2 1 4 5 6 7 4 1 2 3 2 4 2 3, i = 1, j = 13. Je vois encore un 3. Je supprime nouveau en permutant. 2 2 1 4 5 6 7 4 1 2 3 2 4 3 3, i = 10, j = 12. Javance jusqu trouver quelque chose supprimer 2 2 1 4 5 6 7 4 1 2 3 2 4 3 3, i = 12, j = 12. Les pointeurs se rencontrent, tout a t trait. Sachant que je commence compter partir de 0, cela signifie que ma taille est maintenant j + 1 (ou i+1). int vector_Cut(int *tab, int k, int n){ int i,j; i = 0; j = n-1; do{ if(tab[i]==k){ int tmp; tmp = i; i = j; j = tmp; j--; } else i++; }while(i!=j); return j+1; } Philippe Giabbanelli Exemple dutilisation : int n, *tab ; n = 100 ; *tab = (int *)malloc(n*sizeof(int)) ; vector_random(tab, n); /* tableau de 100 entiers remplis alatoirement */ n = vector_Cut(tab, 32000, n); free(tab); 4 Mai 2006

Vous aimerez peut-être aussi