C3 Pointeurs et types structurés ¶
"Pointers have been lumped with the goto
statement as a marvelous way to create impossible-to-understand programs. This is certainly true when they are used carelessly, and it is easy to create pointers that point somewhere unexpected. With discipline, however, pointers can also be used to achieve clarity and simplicity"
(in the C programming language 1978)
Cours¶
Attention
Ce diaporama ne vous donne que quelques points de repères lors de vos révisions. Il devrait être complété par la relecture attentive de vos propres notes de cours et par une révision approfondie des exercices.
Travaux dirigés¶
Travaux pratiques¶
Exercice 1 : Visualisation avec Python Tutor¶
Le site Python Tutor, permet de visualiser l'execution de programmes C.
- Aller sur Python Tutor, recopier et visualiser l'exécution du programme suivant :
#include <stdlib.h>
int main() {
int n_local;
int *p_local = &n_local;
int *p_tas = malloc(sizeof(int));
return 0;
}
-
En citant le cours, justifier brièvement que
p_local
pointe sur la pile alors quep_tas
pointe sur le tas. -
Compléter ce programme en définissant une variable globale
n_globale
de typeint
non initialisée. Que remarquez-vous ? -
En utilisant le pointeur
p_local
, donner la valeur 42 àn_local
-
Quelle instruction, pourtant très importante, est manquante dans ce programme ? La rajouter et indiquer quelle option de compilation permettrait de faire apparaître le problème.
Exercice 2 : Pour démarrer en douceur¶
-
Ecrire en C un programme qui définit (dans
main
) une variable localen_local
de typeint
et affiche son adresse mémoire.Aide
- L'opérateur
&
permet de récupérer l'adresse d'une variable - Le spécificateur de format pour les pointeurs dans
printf
est%p
- L'opérateur
-
Ecrire en C un programme qui alloue dans le tas une variable de type
int
et affiche son adresse mémoire. -
Les résultats sont-ils conformes au modèle mémoire du C vu en cours ? Justifier.
Exercice 3 : Manipulation de pointeurs¶
Ecrire un programme effectuant les opérations suivantes :
- Déclarer un entier
n
initialisé à \(42\). - Déclarer un pointeur sur un entier
p
initialisé àNULL
- Faire pointer
p
surn
. - Modifier la valeur de
n
de deux façon différentes : en utilisantn
et en utilisantp
. - Après chacune des modification, afficher la valeur de
n
pour vérifier qu'elle a changé. - Afficher l'adresse de
n
.
Exercice 4 : Warning¶
On souhaite écrire en C, un programme qui affiche l'adresse et le contenu d'une variable locale à une fonction.
-
Recopier, compiler (en ignorant le warning) et exécuter la proposition de solution suivante qui effectue un affichage depuis le
main
: -
Expliquer le résultat obtenu
Aide
Le warning obtenu à la compilation devrait vous mettre sur la voie
-
Est-il possible d'afficher l'adresse d'une variable locale à une fonction depuis le
main
? Et depuis la fonction ? -
Effectuer une allocation sur le tas à la ligne 6 (et changer le nom de la variable en
n_tas
). Expliquer pourquoi le programme fonctionne maintenant sans erreur
Exercice 5 : Renvoyer un tableau¶
Note
On utilise, l'abus de langage "renvoyer un tableau", on gardera cependant à l'esprit qu'en C, on renvoie en fait un pointeur vers une zone mémoire de taille \(n \times t\) où \(n\) est la taille du tableau et \(t\) la taille en mémoire de l'un de ses éléments. L'accès à cette zone mémoire se fait comme pour un tableau (c'est-à-dire avec la notation tab[i]
).
-
Recopier et compléter la fonction
get_tab
suivante qui prend en argument un entiersize
et une valeur entièreval
et renvoie un "tableau" de taillesize
dont toutes les cases sont initialisées àval
: -
Ecrire un programme permettant de tester cette fonction
-
La mémoire allouée dans la fonction, n'a pas été libéré, est-ce une erreur ?
-
En vous inspirant de cette fonction écrire :
-
une fonction renvoyant un tableau contenant les entiers de 1 à
size
-
une fonction renvoyant un tableau contenant
size
entiers aléatoires tous compris entre deux valeursvmin
etvmax
Aide
- Pour générer un entier aléatoire entre
vmin
etvmax
on utilisera la fonctionrand()
qui renvoie un entier entre 0 et une constanteRAND_MAX
puis on utilisera un modulo. - Pour initialiser le générateur de nombre aléatoires on utilise usuellement la fonction
srand
en lui donnant en argument une durée en seconde obtenue à l'aide detime(NULL)
(importertime.h
).
- Pour générer un entier aléatoire entre
-
Exercice 6 : Suite de Fibonnaci¶
La suite de Fibonnaci est définie par :
\(\left\{ \begin{array}{lll}
f_0 & = & 0, \\
f_1 & = & 1, \\
f_{n} & = & f_{n-1}+f_{n-2} \mathrm{\ \ pour\ tout\ \ } n\geq2.\end{array} \right.\)
-
Ecrire une fonction
termes_fibo(n)
qui renvoie un tableau contenant les termes de la suite de Fibonnaci jusqu'au rangn
(exclus). Par exemplefibo(5)
doit renvoyer le tableau{0,1,1,2,3}
. -
Ecrire une fonction
somme_pair
qui prend en argument un tableau (et donc sa taille) et renvoie la somme des termes pairs de ce tableau. Par exemple sitab = {0,1,1,2,3}
alorssomme_pair(tab,5)
doit renvoyer2
. -
A l'aide des deux fonctions précédentes, calculer la somme des termes pairs de la suite de Fibonnaci pour \(n<42\). Vous pouvez tester le résultat de votre programme dans le formulaire ci-dessous :
Exercice 7 : Minimum et maximum¶
On souhaite écrire une fonction min_max
qui prend en argument un tableau contenant au moins un entier et permet d'obtenir le minimum et le maximum de ce tableau.
-
Une première solution consiste à passer en paramètre deux pointeurs et à les faire pointer vers le minimum et le maximum du tableau. Dans ce cas la signature de la fonction sera donc :
Ecrire et tester cette fonction. -
Une seconde solution consiste à définir un type structuré
Ecrire et tester cette fonctioncouple
contenant deux champs de typeint
et de d'écrire une fonction renvoyant uncouple
dont le premier champ sera le minimum et le second le maximum. Dans ce cas, la signature de la fonction sera donc :
Exercice 8 : Sur les caractères¶
On souhaite écrire une fonction inverse_casse
en C qui ne renvoie rien et change la casse de la lettre passée en argument (si c'est une majuscule alors elle devient minuscule et inversement). Si l'argument n'est pas une lettre, la fonction ne fait rien.
Aide
- Les caractères ascii des majuscules vont de 65 (pour le
A
) à 90 (pour leZ
) - Les caractères ascii des minuscules vont de 92 (pour le
a
) à 122 (pour lez
)
-
La proposition de solution ci-dessous ne compile pas, corriger les erreurs qui s'y trouvent puis exécuter le programme (les lignes problématiques sont surlignées).
-
Expliquer pourquoi le programme affiche
c
(et que donc la fonction est inopérante) -
Quelle devrait être la signature de cette fonction ?
-
Corriger la proposition ci-dessus
-
Compléter le programme en ajoutant une fonction
inverse_casse_chaine
qui ne renvoie rien et inverse la casse de toutes les lettres présentes dans la chaine donnée en paramètre .
Exercice 9 : Tri par sélection¶
Algorithme
Pour trier les éléments d'un tableau par ordre croissant, l'algorithme du tri par sélection consiste à :
- rechercher le plus petit élement du tableau à partir de l'indice 0
- échanger cet élément avec celui situé à l'indice 0
- rechercher le plus petit élement du tableau à partir de l'indice 1
- échanger cet élément avec celui situé à l'indice 1
- et ainsi de suite jusqu'à atteindre la fin du tableau
- Ecrire une fonction
echange
qui prend en argument un tableau et deux indices \(i\) et \(j\) et échange les éléments d'indice \(i\) et \(j\) de ce tableau. - Ecrire une fonction
indice_min_depuis
qui prend en argument une liste et un indice \(i\) et renvoie l'indice du minimum des éléments de ce tableau depuis l'indice \(i\). - Programmer et tester l'algorithme du tri par sélection.
Exercice 10 : Somme des entiers dans un fichier¶
Le fichier entiers.txt
téléchargeable ci-dessous contient sur chaque ligne un entier. Ecrire un programme qui lit ce fichier et calcule la somme de ces entiers.
entiers.txt
Vous pouvez vérifier le résultat de votre programme dans le formulaire ci-dessous
Exercice 11 : Type structuré point¶
On donne le code suivant permettant de définir le type structuré Point
:
- Créer les points \(A(3;-2)\) et \(B(-1;6)\).
- Ecrire une fonction
affiche
qui prend en argument un objetPoint
et l'écrit dans le terminal. -
Ecrire une fonction
milieu
qui prend en argument deux objets de typePoint
et un caractère et renvoie un objet de typePoint
ayant pour nom ce caractère et pour coordonnées celles du milieu du segment formé par les deux points.Aide
On rappelle que pour deux points \(A(x_A,y_A)\) et \(B(x_B,y_B)\) les coordonnes \(x_I\) et \(y_I\) du milieu \(I\) du segment \([AB]\) sont :
\(x_I = \dfrac{x_A+x_B}{2}\) et \(y_I = \dfrac{y_A+y_B}{2}\) -
Créer le point \(I\), milieu de \(A\) et de \(B\) et l'afficher.
- Créer la fonction
renomme
qui prend en argument un objet de typePoint
et un caractèreC
et change le nom du point enC
.
Exercice 12 : Modélisation d'un compte en banque¶
En C, On modélise un compte bancaire par un objet de type struct
possédant les champs suivants :
- un numéro de compte de type
uint32_t
- un nom de titulaire de type
char[50]
- un solde de type
float
On répondra aux questions suivantes en écrivant au fur et à mesure le programme correspondant
- Créer le type
CompteBancaire
- Dans le
main
, créer la variableuntel
représentant le compte de M. Untel de numéro 421 ayant un solde de \(-318,53\) € - Ecrire et tester la fonction
affiche
qui ne renvoie rien, prend en argument un objet de typeCompteBancaire
et affiche les informations de ce compte. Par exemple sur la variableuntel
, la fonctionaffiche
doit écrire dans le terminale :N°421 - M. Untel : -318,53 euros
- Ecrire et tester les méthodes
depot
etretrait
permettant respectivement d'ajouter ou de retirer une somme d'argent d'une variable de type CompteBancaire en modifiant le champsolde
.
Exercice 13 : Date¶
- Créer un type structuré permettant de représenter une date au format
JJ/MM/AAAA
- Ecrire une fonction prenant en argument une date et permettant de l'afficher au format
JJ/MM/AAAA
- Ecrire une fonction
lendemain
qui prend en argument une date et renvoie un objet de typedate
correspondant au lendemain de cette date.
Exercice 14 : Boîte de plus grand volume¶
Le fichier boites.txt
téléchargeable ci-dessous fait 1000 lignes, chaque ligne contient la référence d'un modèle de boîte sous la forme d'un code à 4 lettres suivi de trois entiers représentant les dimensions de la boîte. A titre d'exemple, les trois premières lignes du fichier sont :
NWLR
a comme dimension 283x75x46
.
boites.txt
Le but de l'exercice est d'écrire un programme en C permettant de trouver la référence de la boîte de plus grand volume.
-
Définir le type structuré
boite
ayant un champreference
de type chaine de caractères de longueur 4, et 3 champs entierslongueur
,largeur
,hauteur
. -
Ecrire une fonction
volume
qui prend en argument un objet de typeboite
et renvoie le volume de cette boîte. -
Dans votre programme principal, déclarer un tableau de 1000 élements de type
boite
, lire le fichierboites.txt
en stockant chaque ligne lue dans le tableauboite
. -
Trouver la référence de la boite de plus grand volume, et vérifier votre résultat dans le formulaire suivant :
Exercice 15 : Fractions¶
- Créer un type structuré permettant de représenter une fraction, ce type aura deux champs de type
int
, qu'on appeleranumerateur
etdenominateur
- Ecrire une fonction permettant d'afficher "proprement" une fraction dans le terminal (on pourra par exemple envisager les cas où le dénominateur vaut 1 ou celui ou le numérateur vaut 0).
-
Créer une fonction
simplifie
qui modifie la fraction passée en paramètre pour la rendre irreductible.Aide
On rappelle que le pgcd de deux entiers peut se calculer avec l'algorithme d'Euclide :
- Si \(b=0\) alors l'algorithme se termine et le pgcd est \(a\)
- Sinon faire la division euclidienne de \(a\) par \(b\), et en notant \(r\) le reste, revenir à l'étape précédente en remplaçant \(a\) par \(b\) et \(b\) par \(a\).
-
Ecrire la fonction
addition
qui prend en argument deux fractions et renvoie leur somme. - Faire de même pour les autres opérations de base.
Exercice 16 : Compilation séparée¶
On trouvera sur cette page, les fichiers turtle.c
et turtle.h
qui définissent une implémentation simple du dessin à l'aide d'une tortue graphique comme dans le langage logo. c'est-à-dire qu'on peut dessiner en bougeant à l'aide d'une "tortue" qui se déplace, avance, tourne, ...
Attention
Le module turtle
utilise le module <math.h>
, avec gcc il faudra donc utiliser l'option -lm
pour lier le module math lors de la compilation finale.
-
En utilisant la méthode de compilation séparée vue en cours, compiler le programme suivant qui utilise la librairie
turtle.h
. Puis visualiser l'image produite (carre.bmp
) pour vérifier que tout s'est bien passé.Dessin avec turtle
#include "turtle.h" int main() { /* crée une image de taille 300x300 le centre de l'image est le point (0,0) la tortue y est positionnée */ turtle_init(300, 300); /* dessin d'un carré de coté 100 on avance de 100 et on tourne de 90° à 4 reprises */ for (int i=0;i<4;i++) { turtle_forward(100); turtle_turn_left(90); } // Sauve l'image pour la visualiser turtle_save_bmp("carre.bmp"); return 0; }
-
En vous inspirant de l'exemple précédent, réaliser le dessin ci-dessous, sachant que l'image est de dimension 500x500 et que les carrés sont tous de côté 150 et qu'il sont tracés depuis l'origine en inclinant de multiples de 10° par rapport à l'horizontale.
Exercice 17 : Module complexe¶
-
Ecrire le fichier d'entête d'un module
complexe
dans lequel on définit ;- le type
struct complexe
qui représente un complexe sous forme algébrique composé de deux champs de type double (reel
etimaginaire
) - les opérations usuelles addition, soustraction, multiplication et division sur ce type
- la fonction
module
qui renvoie le module d'un complexe sous la forme d'undouble
- le type
-
Ecrire l'implémentation de ces fonctions dans le module
complexe.c
et compiler sous la forme d'un fichier objet. -
Dans un fichier
test_complexe.c
, inclure le fichier d'en-tête et tester votre module.
Humour d'informaticien¶
"1972 - Dennis Ritchie invents a powerful gun that shoots both forward and backward simultaneously. Not satisfied with the number of deaths and permanent maimings from that invention he invents C and Unix."
(blog)