• Aucun résultat trouvé

Exercice 3 : Tri de 3 valeurs

N/A
N/A
Protected

Academic year: 2022

Partager "Exercice 3 : Tri de 3 valeurs"

Copied!
13
0
0

Texte intégral

(1)

Isup 1 - Programmation TD no4 Matthieu Journault 19 juin 2020

Exercice 1 : Rappel

Q. 1Ecrire une fonction r´´ ecursive qui calcule la mise `a la puissance n d’un entier m.

Solution /* Mise `a la puissance n de l'entier m */

int pow(int m, int n) { if (n == 0) {return 1;}

else {return (m * pow(m, n-1));}

}

Q. 2Ecrire une fonction r´´ ecursive calculant le binomial

n

m

Solution /* Calcul du coefficient binomial m parmis n */

int binomial(int m, int n) {

if (m == 0 || m == n) {return 1;}

else {return (binomial(m-1, n-1) + binomial(m, n-1));}

}

Q. 3Repr´esenter l’´etat de la m´emoire `a chacun des points de programme suivant (1, 2, . . .) void swap(int a, int b) { /* 4 */

int c = b ; /* 5 */

b = a ; /* 6 */

a = c ; /* 7 */

}

void incr(int u) { /* 9 */

u = u + 1; /* 10 */

}

int main() { /* 1 */

int u = 0 ; /* 2 */

int v = 3 ; /* 3 */

swap(u, v); /* 8 */

incr(v); /* 11 */

incr(v); /* 12 */

}

(2)

Solution 1. main

2. main u : 0

3.

u : 0 v : 3 main

4.

a : 0 b : 3 swap

u : 0 v : 3 main

5.

a : 0 b : 3 c : 3 swap

u : 0 v : 3 main

6.

a : 0 b : 0 c : 3 swap

u : 0 v : 3 main

7.

a : 3 b : 0 c : 3 swap

u : 0 v : 3 main

8.

u : 0 v : 3 main

9.

u : 3 incr

u : 0 v : 3 main

10.

u : 4 incr

u : 0 v : 3 main

u : 0 v : 3 main

(3)

9(2)

u : 3 incr

u : 0 v : 3 main

10(2)

u : 4 incr

u : 0 v : 3 main

12

u : 0 v : 3 main

Exercice 2 : Pointeurs

Q. 4Que remarquez vous concernant les modifications m´emoires dans la question 3 ? Comment expliquez vous ce ph´enom`ene ? Voyez vous un moyen permettant `a une fonction f appel´ee par une fonction g de modifier les variables locales deg.

Solution

Nous pouvons remarquer que les variables locales `a la fonction main ne sont pas modifi´es par les appels aux fonctions swap et incr. L’explication est simple : lors d’un appel de fonction en C, ce sont des valeurs qui sont propager vers la fonction appel´ee et non pas la variable. Ainsi dans l’exemple de la question 3, lorsque la fonctionswapmodifie le contenu deaetbles valeurs stock´ees dans les variables u et v ne sont pas modifi´es puisqu’une copie de ces valeurs a ´et´e donn´e `a la fonction swap. `A ce point d’avancement dans le cours il n’est donc pas possible de modifier les variables locales de la fonction appelante dans la fonction appel´ee.

Nous avons vu jusqu’`a maintenant plusieurs types de valeurs en C : les entiers, les flottants, les caract`eres. Il existe de nombreux autres types de valeurs en C, celui qui nous int´eresse particuli`erement aujourd’hui est le type depointeur.

La m´emoire est un grand bloc de “cases” telle que chaque case contient une valeur. Ces cases ont un emplacement dans la m´emoire, cet emplacement s’appellel’adresse de la case. L’adresse n’est en fait rien d’autre qu’un entier et la m´emoire peut ˆetre vu comme un tr`es grand tableau.

6 0

2 1

1 2

. . . 3 1498

2 1499

1 1500

7 1501

6 1502

valeur

adresse . . .

En C il est possible de modifier le contenu de n’importe quelle case m´emoire, `a condition bien sˆur, d’en connaˆıtre l’adresse. Il sera donc souvent n´ecessaire en C de manipuler des adresses des cases de la

(4)

m´emoire. Toutefois afin de ne pas introduire de confusions pour le programmeur, le langage C s´epare les entiers repr´esentant des entiers, des entiers repr´esentant des adresses. Ce dernier type de valeur est appelle un pointeur. Ainsi une valeur de type pointeur n’est rien d’autre que l’adresse d’une case m´emoire. Les pointeurs peuvent “pointer” vers diff´erents types de valeurs (le type de la valeur contenue dans la case point´ee par le pointeur), ainsi diff´erents types de pointeur existent et le type d’un pointeur pointant vers une valeur de type t est t *. Par exemple un pointeur vers une case m´emoire contenant un entier a le type int *, un pointeur vers une case m´emoire contenant un caract`ere a le type char

*. De la mˆeme mani`ere qu’il est possible de stocker un entier dans une case m´emoire il est possible de stocker un pointeur dans une case m´emoire (rappel : ce pointeur n’est en fait rien d’autre qu’un entier).

Q. 5 Quel est alors le type d’un pointeur pointant vers une case m´emoire contenant un pointeur vers un entier.

Solution int **

Voyons maintenant comment manipuler un pointeur. Si e est une expression de type pointeur (par exemple une variable contenant un pointeur), alors l’expression * e permet de lire (ou de modifier si `a gauche d’une affectation) le contenu de la case point´ee pare. Six est un ´el´ement ayant une adresse dans la m´emoire (par exemple une variable) alors &x est un pointeur vers cette adresse dans la m´emoire.

Q. 6Supposons que la m´emoire soit dans l’´etat suivant : p : @x

y : 4 f

x : 1

main (La fl`eche de p vers x repr´esente le fait que la valeur stock´ee dans la variable p est un pointeur vers la variable x). Repr´esenter la m´emoire apr`es l’ex´ecution de chacune des 3 instructions suivantes `a partir de cette ´etat.

1. *p = 3;

2. y = *p + 5;

3. *p = *p + 1;

4. p = &y; *p = 3;

5. *p = *(&y);

Solution

1.

p : @x y : 4 f

x : 3 main

2.

p : @x y : 6 f

x : 1 main

(5)

3.

p : @x y : 6 f

x : 1 main

4.

p : @x y : 4 f

x : 2 main

5.

p : @y y : 3 f

x : 1 main

6.

p : @x y : 4 f

x : 4 main

Q. 7Pour chacun des programme suivant donner les diff´erents ´etats de la m´emoire :

1. int x = 1; /* 1 */

int* y = &x; /* 2 */

int z = *y; /* 3 */

2. int* x; /* 1 */

x = &x; /* 2 */

int y = *x; /* 3 */

3. int x = 1; /* 1 */

int* y = &x; /* 2 */

int** z = &y; /* 3 */

int w = **z; /* 4 */

4. int* x; /* 1 */

x = &x; /* 2 */

int y = **** ((int****) x); /* 3 */

Solution 1. 1. main x : 1

2.

x : 1 y : @x main

(6)

3.

x : 1 y : @x z : 1 main

2. 1. main x : ? 2. main x : @x

3.

x : @x y : ? main

3. 1. main x : 1

2.

x : 1 y : @x main

3.

x : 1 y : @x z : @y main

4.

w : 1 x : 1 y : @x z : @y main

4. 1. main x : ? 2. main x : @x

3.

x : @x y : ? main

Le fait qu’une fonction modifie l’´etat de la m´emoire autre que ses propres variables locales est appel´ee uneffet de bord.

Q. 8 Ecrire une fonction´ incr dont vous pr´eciserez la signature et qui a pour effet d’incr´ementer la valeur stock´ee dans une variable. Donner un exemple d’utilisation d’une telle fonction, et repr´esenter les diff´erents ´etats de la m´emoire au long de l’ex´ecution de votre programme.

(7)

Solution /* Fonction d'incr´ementation */

void incr(int* p) { /* 3 */

*p = *p + 1; /* 4 */

}

/* Utilisation dans main */

int main() { /* 1 */

int x = 0; /* 2 */

incr(&x); /* 5 */

}

1. main

2. main x : 0

3.

p : @x incr

x : 0 main

4.

p : @x incr

x : 1 main

5. main x : 1

Q. 9D´efinir une fonctionswappermettant l’inversion du contenu de deux variables. Donner un exemple d’utilisation d’une telle fonction, et repr´esenter les diff´erents ´etats de la m´emoire au long de l’ex´ecution de votre programme.

Solution /* Fonction d'inversion */

void swap(int* p, int* q) { /* 4 */

int c = *p; /* 5 */

*p = *q; /* 6 */

*q = c; /* 7 */

}

/* Utilisation dans main */

int main() { /* 1 */

int x = 0; /* 2 */

int y = 3; /* 3 */

swap(&x, &y); /* 8 */

}

1. main

2. main x : 0

(8)

3.

x : 0 y : 3 main

4.

p : @x q : @y swap

x : 0 y : 3 main

5.

c : 0 p : @x q : @y swap

x : 0 y : 3 main

6.

c : 0 p : @x q : @y swap

x : 3 y : 3 main

7.

c : 0 p : @x q : @y swap

x : 3 y : 0 main

8.

x : 3 y : 0 main

Q. 10 On consid`ere la transformation lin´eaire f :

x

y

7→

x+y

x−y

. D´efinir une fonction f, dont vous pr´eciserez la signature, et appliquant cette transformation par effet de bord `a ses deux arguments. De mˆeme pour la fonction inverse de f.

Solution void f(float* x, float* y) {

float resx = *x + *y;

float resy = *x - *y;

*x = resx;

*y = resy;

}

(9)

void inverse_f(float* x, float* y) { float resx = (*x + *y) / 2 ;

float resy = (*x - *y) / 2 ;

*x = resx;

*y = resy;

}

Exercice 3 : Tri de 3 valeurs

Q. 11 D´efinir une fonction void tri2(int* x, int* y), qui place le minimum des valeurs point´ees par int* x et int* y dans la case m´emoire point´ee par int* x et le maximum dans la case m´emoire point´ee parint* y. Utiliser la fonction swap d´efinie pr´ec´edemment.

Solution void swap(int* p, int* q) { /* 4 */

int c = *p;

*p = *q;

*q = c; /* 5 */

}

void tri2(int* x, int* y) { /* 3 */

if (*x > *y) { swap(x, y);

} /* 6 */

}

Q. 12D´efinir une fonctionvoid tri3(int* x, int* y, int* z), qui place la plus petite valeur parmis les trois valeurs point´ees par int* x, int* y et int* z dans la case m´emoire point´ee par int* x, la deuxi`eme dans la case m´emoire point´ee par int* y et la plus grande dans celle point´ee par int* z.

Utiliser la fonction tri2.

Solution void tri3(int* x, int* y, int* z) { /* 2 */

tri2(x, y);

tri2(y, z);

tri2(x, y); /* 7 */

}

Q. 13 Tester votre programme en appelant tri3 sur des pointeurs pointant sur des cases m´emoires contenant 3, 2 et1 (dans cet ordre). Repr´esenter la m´emoire en entr´ee et en sortie de chaque fonction.

(10)

Solution void main() {

int x = 3;

int y = 2;

int z = 1; /* 1 */

tri3(&x, &y, &z); /* 8 */

}

(11)

1 :

x : 3 y : 2 z : 1 main

2 :

x : @x y : @y z : @z tri3

x : 3 y : 2 z : 1 main

3 :

x : @x y : @y tri2

x : @x y : @y z : @z tri3

x : 3 y : 2 z : 1 main

4 :

p : @x q : @y swap

x : @x y : @y tri2

x : @x y : @y z : @z tri3

x : 3 y : 2 z : 1 main

5 :

c : 3 p : @x q : @y swap

x : @x y : @y tri2

x : @x y : @y z : @z tri3

x : 2 y : 3 z : 1 main

6 :

x : @x y : @y tri2

x : @x y : @y z : @z tri3

x : 2 y : 3 z : 1 main

3(2) :

x : @y y : @z tri2

x : @x y : @y z : @z tri3

x : 2 y : 3 z : 1 main

4(2) :

p : @y q : @z swap

x : @y y : @z tri2

x : @x y : @y z : @z tri3

x : 2 y : 3 z : 1 main

5(2) :

c : 3 p : @y q : @z swap

x : @y y : @z tri2

x : @x y : @y z : @z tri3

x : 2 y : 1 z : 3 main

(12)

6(2) :

x : @y y : @z tri2

x : @x y : @y z : @z tri3

x : 2 y : 1 z : 3 main

3(3) :

x : @x y : @y tri2

x : @x y : @y z : @z tri3

x : 2 y : 1 z : 3 main

4(3) :

p : @x q : @y swap

x : @x y : @y tri2

x : @x y : @y z : @z tri3

x : 2 y : 1 z : 3 main

5(3) :

c : 2 p : @x q : @y swap

x : @x y : @y tri2

x : @x y : @y z : @z tri3

x : 1 y : 2 z : 3 main

6(3) :

x : @x y : @y tri2

x : @x y : @y z : @z tri3

x : 1 y : 2 z : 3 main

7 :

x : @x y : @y z : @z tri3

x : 1 y : 2 z : 3 main

8 :

x : 1 y : 2 z : 3 main

Exercice 4 : Pointeurs et pile d’appel

Q. 14Expliquer ce qui se passe lors de l’ex´ecution du programme suivant : int* f1(int* x, int* y) {

if (*x < *y) {return x;}

else {return y;}

}

int* f2(int* x, int* y) { int c;

(13)

else {c = *y;}

return (&c);

}

int main() { int x = 1;

int y = 2;

int* p = f1(&x, &y);

int* q = f2(&x, &y);

}

Solution

La premi`ere fonction f1 retourne un pointeur vers la case m´emoire x de la fonction main car celle-ci contient la valeur minimale parmi les cases m´emoires x et y. L’ex´ecution de la seconde fonction f2 produit une erreur car celle-ci retourne un pointeur vers une de ses variables locales, qui est d´esallou´ee `a la sortie de la fonction et donc le pointeur retourn´e n’est pas un pointeur valide.

Références

Documents relatifs

LYCÉE ERNEST BICHAT 1ES 20092010 Devoir surveillé n ◦ 9

[r]

Il faudrait pousser plus avant pour comprendre ` a quelles transformations correspond le fait d’avoir comme on l’a vu “un seul point sur l’´ equateur”, dans la mesure o` u

La qualit´ e du g´ en´ erateur est ´ evalu´ ee au moyen du crit` ere qui stipule que le g´ en´ erateur est un bon g´ en´ erateur de nombres pseudo-al´ eatoires si on ne parvient

Le principe de calcul est tr` es simple et assez naturel : on fait la diff´ erence entre la somme des carr´ es relative aux erreurs dans le mod` ele additif (sans interactions)

On peut donc consid´erer indiff´eremment une mesure de Radon comme une forme lin´eaire continue T sur un espace de fonctions continues et comme une mesure ensembliste sign´ee µ,

e coursename : afficher le nom d’un professeur le plus ancien souhaitant enseigner le cours coursename f filename : recopie la liste chaînée qui en résulte dans le

Sur le cˆ ot´ e AB du grand triangle, la r` egle relative aux noms des points ne permet que des points A et B, une arˆ ete bicolore faisant passer de A ` a B ou inversement ;