1. Calcul de statistiques
Cette section illustre la gestion de la mémoire dynamique en langage C par la mise en place d'un programme de calcul statistique. Le travail vise à réaliser des calculs de statistique simples (moyenne, variance, médiane) à partir de séries de valeurs de taille dynamique. Les pointeurs et l’allocation dynamique sont une bonne solution pour implanter ce genre de traitement.
Ecrire un programme tp5-stat.c contenant une fonction int* creation_serie(unsigned int n) qui crée dynamiquement un espace en mémoire permettant de stocker une série de valeurs de taille n et retourne un pointeur vers celui-ci. Le programme doit contenir également une fonction main qui permet de faire saisir à l’utilisateur une série de 5 valeurs.
Exemple d’exécution
Valeur 1/5: 2
Valeur 2/5: 3
Valeur 3/5: 4
Valeur 4/5: 5
Valeur 5/5: 6
#include <stdio.h>
#include <stdlib.h> // Pour malloc(), free()
int* creation_serie(unsigned int n) {
if (n > 0){
return (int*)malloc(n*sizeof(int));
}
return NULL;
}
int main() {
unsigned int nb_valeurs = 5;
int* serie = creation_serie(nb_valeurs);
if (serie == NULL) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < nb_valeurs; i++){
printf("Valeur %d/%d: ", i+1, nb_valeurs);
scanf("%d", serie+i);
}
free(serie);
}
Dans le programme tp5-stat.c, ajouter une fonction void affiche_serie(int* s, unsigned int n) qui affiche la série de valeurs pointée par la variable s sous la forme : ( s[0], …, s[i], …, s[n-1] ). Modifier la fonction main du programme pour afficher la série des 5 valeurs saisies.
Exemple d’exécution
Valeur 1/5: 2
Valeur 2/5: 3
Valeur 3/5: 4
Valeur 4/5: 5
Valeur 5/5: 6
Serie: ( 2, 3, 4, 5, 6 )
#include <stdio.h>
#include <stdlib.h> // Pour malloc(), free()
int* creation_serie(unsigned int n) {
if (n > 0){
return (int*)malloc(n*sizeof(int));
}
return NULL;
}
void affiche_serie(int* s, unsigned int n) {
printf("( ");
if ((s != NULL) && (n > 0)){
printf("%d", s[0]);
for(int i = 1; i < n; i++){
printf(", %d", s[i]);
}
}
printf(" )");
}
int main() {
unsigned int nb_valeurs = 5;
int* serie = creation_serie(nb_valeurs);
if (serie == NULL) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < nb_valeurs; i++){
printf("Valeur %d/%d: ", i+1, nb_valeurs);
scanf("%d", serie+i);
}
printf("Serie: ");
affiche_serie(serie, nb_valeurs);
free(serie);
}
Dans le programme tp5-stat.c, ajouter une fonction void destruction_serie(int** ps) qui désalloue l’espace mémoire contenant la série pointée par la variable ps et affecte la valeur NULL à la série pointée. Modifier la fonction main du programme pour détruire la série utilisée avant la fin de l’exécution.
Exemple d’exécution
Valeur 1/5: 2
Valeur 2/5: 3
Valeur 3/5: 4
Valeur 4/5: 5
Valeur 5/5: 6
Serie: ( 2, 3, 4, 5, 6 )
#include <stdio.h>
#include <stdlib.h> // Pour malloc(), free()
int* creation_serie(unsigned int n) {
if (n > 0){
return (int*)malloc(n*sizeof(int));
}
return NULL;
}
void affiche_serie(int* s, unsigned int n) {
printf("( ");
if ((s != NULL) && (n > 0)){
printf("%d", s[0]);
for(int i = 1; i < n; i++){
printf(", %d", s[i]);
}
}
printf(" )");
}
void destruction_serie(int** ps) {
if ((ps != NULL) && (*ps != NULL)){
free(*ps);
*ps = NULL;
}
}
int main() {
unsigned int nb_valeurs = 5;
int* serie = creation_serie(nb_valeurs);
if (serie == NULL) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < nb_valeurs; i++){
printf("Valeur %d/%d: ", i+1, nb_valeurs);
scanf("%d", serie+i);
}
printf("Serie: ");
affiche_serie(serie, nb_valeurs);
destruction_serie(&serie);
}
Moyenne empirique
Soit $X=(x_{1},\ldots ,x_{i},\ldots ,x_{n})$ une série de $n$ valeurs. La moyenne empirique de $X$, notée $\overline{x}$, est définie par la somme des valeurs de $X$ divisée par le nombre $n$ de valeur. Plus formellement:
$$\overline{x}\ =\ \frac{1}{n}\sum_{i=1}^{n}x_{i}$$
Dans le programme tp5-stat.c, ajouter une fonction float moyenne(int* s, unsigned int n) qui calcule et retourne la moyenne de la série de $n$ valeurs pointée par s. Si la série est vide, la fonction doit retourner la valeur spéciale NAN (Not a Number) de l’en-tête math.h. Modifier la fonction main du programme pour afficher la série des 5 valeurs saisies et sa moyenne.
Exemple d’exécution
Valeur 1/5: 6
Valeur 2/5: 7
Valeur 3/5: 2
Valeur 4/5: 4
Valeur 5/5: 9
La moyenne de ( 6, 7, 2, 4, 9 ) est 5.600000
#include <stdio.h>
#include <stdlib.h> // Pour malloc(), free()
#include <math.h> // Pour NAN
int* creation_serie(unsigned int n) {
if (n > 0){
return (int*)malloc(n*sizeof(int));
}
return NULL;
}
void affiche_serie(int* s, unsigned int n) {
printf("( ");
if ((s != NULL) && (n > 0)){
printf("%d", s[0]);
for(int i = 1; i < n; i++){
printf(", %d", s[i]);
}
}
printf(" )");
}
void destruction_serie(int** ps) {
if ((ps != NULL) && (*ps != NULL)){
free(*ps);
*ps = NULL;
}
}
float moyenne(int* s, unsigned int n){
if ((s != NULL) && (n > 0)){
float m = 0;
for(int i = 0; i < n; i++){
m += s[i];
}
return m / n;
}
return NAN;
}
int main() {
unsigned int nb_valeurs = 5;
int* serie = creation_serie(nb_valeurs);
if (serie == NULL) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < nb_valeurs; i++){
printf("Valeur %d/%d: ", i+1, nb_valeurs);
scanf("%d", serie+i);
}
printf("La moyenne de la serie ");
affiche_serie(serie, nb_valeurs);
printf(" est %f", moyenne(serie, nb_valeurs));
destruction_serie(&serie);
}
Variance
Soit $X=(x_{1},\ldots ,x_{i},\ldots ,x_{n})$ une série de $n$ valeurs et soit $\overline{x}$ la moyenne empirique de $X$. La variance, notée $V$, de la série $X$ est définie par la moyenne des carrés des écarts entre les valeurs de $X$ et la moyenne empirique $\overline{x}$. Plus formellement :
$$V=\frac{1}{n}\sum_{i=1}^{n}(x_{i}-\overline{x})^{2}$$
Dans le programme tp5-stat.c, ajouter une fonction float variance(int* s, unsigned int n) qui calcule et retourne la variance de la série de $n$ valeurs pointée par s. Si la série est vide, la fonction doit retourner la valeur spéciale NAN (Not a Number) de l’en-tête math.h. Modifier la fonction main d'afficher la variance de la série saisie.
Exemple d’exécution
Valeur 1/5: 9
Valeur 2/5: 8
Valeur 3/5: 4
Valeur 4/5: 1
Valeur 5/5: 2
La moyenne de ( 9, 8, 4, 1, 2 ) est 4.800000
Sa variance est de 10.1600000
#include <stdio.h>
#include <stdlib.h> // Pour malloc(), free()
#include <math.h> // Pour NAN
int* creation_serie(unsigned int n) {
if (n > 0){
return (int*)malloc(n*sizeof(int));
}
return NULL;
}
void affiche_serie(int* s, unsigned int n) {
printf("( ");
if ((s != NULL) && (n > 0)){
printf("%d", s[0]);
for(int i = 1; i < n; i++){
printf(", %d", s[i]);
}
}
printf(" )");
}
void destruction_serie(int** ps) {
if ((ps != NULL) && (*ps != NULL)){
free(*ps);
*ps = NULL;
}
}
float moyenne(int* s, unsigned int n){
if ((s != NULL) && (n > 0)){
float m = 0;
for(int i = 0; i < n; i++){
m += s[i];
}
return m / n;
}
return NAN;
}
float variance(int* s, unsigned int n){
float m = moyenne(s, n);
if (m != NAN){
float v = 0;
for(int i = 0; i < n; i++){
v += (s[i] - m)*(s[i] - m);
}
return v / n;
}
return NAN;
}
int main() {
unsigned int nb_valeurs = 5;
int* serie = creation_serie(nb_valeurs);
if (serie == NULL) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < nb_valeurs; i++){
printf("Valeur %d/%d: ", i+1, nb_valeurs);
scanf("%d", serie+i);
}
printf("La moyenne de la serie ");
affiche_serie(serie, nb_valeurs);
printf(" est %f", moyenne(serie, nb_valeurs));
printf("\nSa variance est de %f", variance(serie, nb_valeurs));
destruction_serie(&serie);
}
Dans le programme tp5-stat.c ajouter une fonction int* tri_croissant(int* s, unsigned int n) qui retourne un pointeur vers une série contenant les n valeurs pointée par s triées dans l’ordre croissant. Si la série s est vide, la fonction doit retourner NULL. La série s ne doit pas être modifiée par la fonction et le choix de l’algorithme de tri est libre. Modifier la fonction main afin d’y ajouter l’affichage de la série triée (penser à bien désallouer tous les pointeurs avant la fin de l’exécution).
Aide: Pour trier une série Il est possible d'adapter l'un des algorithmes développés dans le TP sur les tableaux.
Exemple d’exécution
Valeur 1/5: 5
Valeur 2/5: 1
Valeur 3/5: 2
Valeur 4/5: 4
Valeur 5/5: 6
Serie originale: ( 5, 1, 2, 4, 3 )
Serie triee: ( 1, 2, 3, 4, 5 )
#include <stdio.h>
#include <stdlib.h> // Pour malloc(), free()
#include <math.h> // Pour NAN
int* creation_serie(unsigned int n) {
if (n > 0){
return (int*)malloc(n*sizeof(int));
}
return NULL;
}
void affiche_serie(int* s, unsigned int n) {
printf("( ");
if ((s != NULL) && (n > 0)){
printf("%d", s[0]);
for(int i = 1; i < n; i++){
printf(", %d", s[i]);
}
}
printf(" )");
}
void destruction_serie(int** ps) {
if ((ps != NULL) && (*ps != NULL)){
free(*ps);
*ps = NULL;
}
}
float moyenne(int* s, unsigned int n){
if ((s != NULL) && (n > 0)){
float m = 0;
for(int i = 0; i < n; i++){
m += s[i];
}
return m / n;
}
return NAN;
}
float variance(int* s, unsigned int n){
float m = moyenne(s, n);
if (m != NAN){
float v = 0;
for(int i = 0; i < n; i++){
v += (s[i] - m)*(s[i] - m);
}
return v / n;
}
return NAN;
}
int* tri_croissant(int* s, unsigned int n){
if ((s == NULL) || (n < 1))
return NULL;
int* r = malloc(n*sizeof(int));
for(int i=0;i<n;i++){
r[i] = s[i];
}
// Tri selection
int c;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
if ( r[i] > r[j] ) {
c = r[i];
r[i] = r[j];
r[j] = c;
}
}
}
return r;
}
int main() {
unsigned int nb_valeurs = 5;
int* serie = creation_serie(nb_valeurs);
int* serie_triee = NULL;
if (serie == NULL) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < nb_valeurs; i++){
printf("Valeur %d/%d: ", i+1, nb_valeurs);
scanf("%d", serie+i);
}
printf("Serie originale: ");
affiche_serie(serie, nb_valeurs);
serie_triee = tri_croissant(serie, nb_valeurs);
printf("\nSerie triee: ");
affiche_serie(serie_triee, nb_valeurs);
destruction_serie(&serie);
}
Médiane
Soit $X=(x_{1},\ldots ,x_{i},\ldots ,x_{n})$ une série de $n$ valeurs triées par ordre croissant. La médiane, notée $Me$, de la série $X$ est définie par la valeur située au milieu de la séquence. Plus formellement :
$$
Me\ =\ \left\{
\begin{array}{l}
x_{\frac{n}{2}},\ \textrm{si n est pair }\\
x_{\frac{n+1}{2}},\ \textrm{si n est impair }
\end{array}
\right.
$$
Dans le programme tp5-stat.c ajouter une fonction float mediane(int* s, unsigned int n) qui calcule et retourne la médiane de la série de n valeurs pointée par s. Si la série est vide, la fonction doit retourner la valeur spéciale NAN (Not a Number) de l’en-tête math.h. Modifier la fonction main afin d’y ajouter l’affichage de la médiane de la série saisie.
Exemple d’exécution
Valeur 1/5: 5
Valeur 2/5: 1
Valeur 3/5: 2
Valeur 4/5: 4
Valeur 5/5: 6
La valeur mediane de ( 5, 1, 2, 4, 6 ) est 2.000000
#include <stdio.h>
#include <stdlib.h> // Pour malloc(), free()
#include <math.h> // Pour NAN
int* creation_serie(unsigned int n) {
if (n > 0){
return (int*)malloc(n*sizeof(int));
}
return NULL;
}
void affiche_serie(int* s, unsigned int n) {
printf("( ");
if ((s != NULL) && (n > 0)){
printf("%d", s[0]);
for(int i = 1; i < n; i++){
printf(", %d", s[i]);
}
}
printf(" )");
}
void destruction_serie(int** ps) {
if ((ps != NULL) && (*ps != NULL)){
free(*ps);
*ps = NULL;
}
}
float moyenne(int* s, unsigned int n){
if ((s != NULL) && (n > 0)){
float m = 0;
for(int i = 0; i < n; i++){
m += s[i];
}
return m / n;
}
return NAN;
}
float variance(int* s, unsigned int n){
float m = moyenne(s, n);
if (m != NAN){
float v = 0;
for(int i = 0; i < n; i++){
v += (s[i] - m)*(s[i] - m);
}
return v / n;
}
return NAN;
}
int* tri_croissant(int* s, unsigned int n){
if ((s == NULL) || (n < 1))
return NULL;
int* r = malloc(n*sizeof(int));
for(int i=0;i<n;i++){
r[i] = s[i];
}
// Tri selection
int c;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
if ( r[i] > r[j] ) {
c = r[i];
r[i] = r[j];
r[j] = c;
}
}
}
return r;
}
float mediane(int* s, unsigned int n){
if ((s != NULL) && (n > 0)){
if (n % 2 == 0)
return s[(n-1)/2];
else
return s[n/2];
}
return NAN;
}
int main() {
unsigned int nb_valeurs = 5;
int* serie = creation_serie(nb_valeurs);
int* serie_triee = NULL;
if (serie == NULL) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < nb_valeurs; i++){
printf("Valeur %d/%d: ", i+1, nb_valeurs);
scanf("%d", serie+i);
}
serie_triee = tri_croissant(serie, nb_valeurs);
printf("La mediane de ");
affiche_serie(serie, nb_valeurs);
printf(" est %f", mediane(serie_triee, nb_valeurs));
destruction_serie(&serie);
}
2. Structures
Il est apparu dans la partie 1 de ce travail qu’afin de gérer une série de valeur il est indispensable de connaitre :
- Le pointeur vers la série
- Le nombre de valeurs contenues dans la série
Une telle configuration alourdi les prototypes de fonctions utilisant des séries et peut entrainer des erreurs si l’une des deux informations vient à être modifiée.
Afin de résoudre ce problème, une solution est de grouper les deux informations au sein d’une même structure.
Ecrire un programme tp5-serie.c contenant la déclaration d’un type permettant de représenter une série de valeurs. Ce type sera nommé serie et sera définit par une structure contenant les champs suivants :
- Une variable nommé valeurs de type int*.
- Une variable taille de type unsigned int représentant le nombre de valeurs de la série.
Le programme doit contenir également une fonction main qui déclare une variable s de type serie.
#include <stdio.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
void main(void){
serie s;
}
En s'inspirant de l’exercice 1.1. de la partie 1, dans le programme tp5-serie.c, ajouter une fonction serie creation_serie(unsigned int n) qui crée dynamiquement une série pouvant contenir n valeurs. Modifier la fonction main afin de faire saisir à l’utilisateur la taille de la série qu'il souhaite créer puis les valeurs de celle-ci .
Exemple d’exécution
Nombre de valeurs: 5
Valeur 1/5: 1
Valeur 2/5: 2
Valeur 3/5: 3
Valeur 4/5: 4
Valeur 5/5: 5
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
int main(void){
serie s;
unsigned int nb_valeurs;
printf("Nombre de valeurs: ");
scanf("%u", &nb_valeurs);
s = creation_serie(nb_valeurs);
if (s.taille == 0) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < s.taille; i++){
printf("Valeur %d/%d: ", i+1, s.taille);
scanf("%d", &(s.valeurs[i])); // equivalent a scanf("%d", s.valeurs+i))
}
return 0;
}
En s'inspirant de l’exercice 1.2. de la partie 1, dans le programme tp5-serie.c, ajouter une fonction void affiche_serie(serie s) qui affiche la série s sous la forme :
( s[0], …, s[i], …, s[n-1] ). Modifier la fonction main du programme pour afficher la série de valeurs saisie.
Exemple d’exécution
Nombre de valeurs: 6
Valeur 1/6: 1
Valeur 2/6: 4
Valeur 3/6: 3
Valeur 4/6: 2
Valeur 5/6: 5
Valeur 6/6: 6
Serie: ( 1, 4, 3, 2, 5, 6 )
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
int main(void){
serie s;
unsigned int nb_valeurs;
printf("Nombre de valeurs: ");
scanf("%u", &nb_valeurs);
s = creation_serie(nb_valeurs);
if (s.taille == 0) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < s.taille; i++){
printf("Valeur %d/%d: ", i+1, s.taille);
scanf("%d", &(s.valeurs[i])); // equivalent a scanf("%d", s.valeurs+i))
}
printf("Serie: ");
affiche_serie(s);
return 0;
}
Pointeurs vers des structures
Soit une structure ma_structure contenant un champ c (par exemple de type int). Pour une variable v dont le type est ma_structure, l'accès à la valeur du champ c de v se fait en utilisant le point:
typedef struct {
int c;
} ma_structure;
int main(){
ma_structure v;
v.c = 1;
}
Soit la variable pv déclarée comme un pointeur vers une variable de type ma_structure:
typedef struct {
int c;
} ma_structure;
int main(){
ma_structure v;
ma_structure* pv = &v;
}
L'accès à la valeur du champ c de v peut se faire de 2 façons équivalentes:
- (*pv).c (ecriture classique du déréférencemet)
- pv->c (écriture concise via l'opérateur ->)
ces deux écritures produisent le même comportement:
typedef struct {
int c;
} ma_structure;
int main(){
ma_structure v;
ma_structure* pv = &v;
(*pv).c = 1;
pv->c = 1;
}
En s'inspirant de l’exercice 1.3. de la partie 1, dans le programme tp5-serie.c, ajouter une fonction void destruction_serie(serie* ps) qui désalloue l’espace mémoire contenant la série pointée par la variable ps et affecte la valeur NULL à la variable valeurs de la série et 0 à sa taille. Modifier la fonction main du programme pour détruire la série utilisée avant la fin de l’exécution et afficher l'adresse de ses valeurs et la valeur de sa taille.
Exemple d’exécution
Nombre de valeurs: 6
Valeur 1/6: 1
Valeur 2/6: 4
Valeur 3/6: 6
Valeur 4/6: 3
Valeur 5/6: 2
Valeur 6/6: 5
Serie: ( 1, 4, 6, 3, 2, 5 )
Serie desallouee: valeurs = (nil), taille = 0
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
void destruction_serie(serie* ps) {
if ((ps != NULL) && (ps->valeurs != NULL)){
free(ps->valeurs);
ps->valeurs = NULL;
ps->taille = 0;
}
}
int main(void){
serie s;
unsigned int nb_valeurs;
printf("Nombre de valeurs: ");
scanf("%u", &nb_valeurs);
s = creation_serie(nb_valeurs);
if (s.taille == 0) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < s.taille; i++){
printf("Valeur %d/%d: ", i+1, s.taille);
scanf("%d", &(s.valeurs[i])); // equivalent a scanf("%d", s.valeurs+i))
}
printf("Serie: ");
affiche_serie(s);
destruction_serie(&s);
printf("\nSerie desallouee\n");
printf(" Valeurs: %p", s.valeurs);
printf(" taille: %u", s.taille);
return 0;
}
En s'inspirant de l’exercice 1.4. de la partie 1, dans le programme tp5-serie.c, ajouter une fonction float moyenne(serie s) qui calcule et retourne la moyenne de la série s. Si la série est vide, la fonction doit retourner la valeur spéciale NAN (Not a Number) de l’en-tête math.h. Modifier la fonction main afin d'afficher la moyenne de la série saisie.
Exemple d’exécution
Nombre de valeurs: 6
Valeur 1/6: 1
Valeur 2/6: 3
Valeur 3/6: 2
Valeur 4/6: 5
Valeur 5/6: 4
Valeur 6/6: 6
Serie: ( 1, 3, 2, 5, 4, 6 )
Moyenne de la serie: 3.500000
Serie desallouee
Valeurs: (nil) taille: 0
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
void destruction_serie(serie* ps) {
if ((ps != NULL) && (ps->valeurs != NULL)){
free(ps->valeurs);
ps->valeurs = NULL;
ps->taille = 0;
}
}
float moyenne(serie s){
if ((s.valeurs != NULL) && (s.taille > 0)){
float m = 0;
for(int i = 0; i < s.taille; i++){
m += s.valeurs[i];
}
return m / s.taille;
}
return NAN;
}
int main(void){
serie s;
unsigned int nb_valeurs;
printf("Nombre de valeurs: ");
scanf("%u", &nb_valeurs);
s = creation_serie(nb_valeurs);
if (s.taille == 0) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < s.taille; i++){
printf("Valeur %d/%d: ", i+1, s.taille);
scanf("%d", &(s.valeurs[i])); // equivalent a scanf("%d", s.valeurs+i))
}
printf("Serie: ");
affiche_serie(s);
printf("\n\nMoyenne de la serie: %f", moyenne(s));
destruction_serie(&s);
printf("\n\nSerie desallouee\n");
printf(" Valeurs: %p", s.valeurs);
printf(" taille: %u", s.taille);
return 0;
}
En s'inspirant de l’exercice 1.5. de la partie 1, dans le programme tp5-serie.c, ajouter une fonction float variance(serie s) qui calcule et retourne la variance de la série s. Si la série est vide, la fonction doit retourner la valeur spéciale NAN (Not a Number) de l’en-tête math.h. Modifier la fonction main afin d’y ajouter l’affichage de la variance de la série saisie.
Exemple d’exécution
Nombre de valeurs: 7
Valeur 1/7: 1
Valeur 2/7: 1
Valeur 3/7: 3
Valeur 4/7: 9
Valeur 5/7: 4
Valeur 6/7: 8
Valeur 7/7: 1
Serie: ( 1, 1, 3, 9, 4, 8, 1 )
Moyenne de la serie: 3.857143
Variance de la serie: 9.836734
Serie desallouee
Valeurs: (nil) taille: 0
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
void destruction_serie(serie* ps) {
if ((ps != NULL) && (ps->valeurs != NULL)){
free(ps->valeurs);
ps->valeurs = NULL;
ps->taille = 0;
}
}
float moyenne(serie s){
if ((s.valeurs != NULL) && (s.taille > 0)){
float m = 0;
for(int i = 0; i < s.taille; i++){
m += s.valeurs[i];
}
return m / s.taille;
}
return NAN;
}
float variance(serie s) {
float m = moyenne(s);
if (m != NAN){
float v = 0;
for(int i = 0; i < s.taille; i++){
v += (s.valeurs[i] - m)*(s.valeurs[i] - m);
}
return v / s.taille;
}
return NAN;
}
int main(void){
serie s;
unsigned int nb_valeurs;
printf("Nombre de valeurs: ");
scanf("%u", &nb_valeurs);
s = creation_serie(nb_valeurs);
if (s.taille == 0) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < s.taille; i++){
printf("Valeur %d/%d: ", i+1, s.taille);
scanf("%d", &(s.valeurs[i])); // equivalent a scanf("%d", s.valeurs+i))
}
printf("Serie: ");
affiche_serie(s);
printf("\n\nMoyenne de la serie: %f", moyenne(s));
printf("\n\nVariance de la serie: %f", variance(s));
destruction_serie(&s);
printf("\n\nSerie desallouee\n");
printf(" Valeurs: %p", s.valeurs);
printf(" taille: %u", s.taille);
return 0;
}
En s'inspirant de l’exercice 1.6. de la partie 1, dans le programme tp5-serie.c, ajouter une fonction serie tri_croissant(serie s) qui retourne une série contenant mêmes valeurs que celles contenues dans la série s mais triées dans l’ordre croissant. La série s ne doit pas être modifiée. Si la série s est vide, la fonction doit retourner une série vide (valeurs à NULL et taille à 0). Modifier la fonction main afin d’y ajouter l’affichage de la série triée (penser à bien désallouer tous les pointeurs avant la fin de l’exécution).
Exemple d’exécution
Nombre de valeurs: 6
Valeur 1/6: 1
Valeur 2/6: 3
Valeur 3/6: 6
Valeur 4/6: 4
Valeur 5/6: 2
Valeur 6/6: 5
Serie: ( 1, 3, 6, 4, 2, 5 )
Moyenne de la serie: 3.500000
Variance de la serie: 2.916667
Serie triee: ( 1, 2, 3, 4, 5, 6 )
Serie desallouee
Valeurs: (nil) taille: 0
Serie triee desallouee
Valeurs: (nil) taille: 0
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
void destruction_serie(serie* ps) {
if ((ps != NULL) && (ps->valeurs != NULL)){
free(ps->valeurs);
ps->valeurs = NULL;
ps->taille = 0;
}
}
float moyenne(serie s){
if ((s.valeurs != NULL) && (s.taille > 0)){
float m = 0;
for(int i = 0; i < s.taille; i++){
m += s.valeurs[i];
}
return m / s.taille;
}
return NAN;
}
float variance(serie s) {
float m = moyenne(s);
if (m != NAN){
float v = 0;
for(int i = 0; i < s.taille; i++){
v += (s.valeurs[i] - m)*(s.valeurs[i] - m);
}
return v / s.taille;
}
return NAN;
}
serie tri_croissant(serie s) {
serie r = creation_serie(s.taille);
for(int i=0;i<s.taille;i++){
r.valeurs[i] = s.valeurs[i];
}
// Tri selection
int c;
for(int i=0;i<s.taille-1;i++){
for(int j=i+1;j<s.taille;j++){
if ( r.valeurs[i] > r.valeurs[j] ) {
c = r.valeurs[i];
r.valeurs[i] = r.valeurs[j];
r.valeurs[j] = c;
}
}
}
return r;
}
int main(void){
serie s;
serie s_triee;
unsigned int nb_valeurs;
printf("Nombre de valeurs: ");
scanf("%u", &nb_valeurs);
s = creation_serie(nb_valeurs);
if (s.taille == 0) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < s.taille; i++){
printf("Valeur %d/%d: ", i+1, s.taille);
scanf("%d", &(s.valeurs[i])); // equivalent a scanf("%d", s.valeurs+i))
}
printf("Serie: ");
affiche_serie(s);
printf("\n\nMoyenne de la serie: %f", moyenne(s));
printf("\n\nVariance de la serie: %f", variance(s));
s_triee = tri_croissant(s);
printf("\n\nSerie triee: ");
affiche_serie(s_triee);
destruction_serie(&s);
printf("\n\nSerie desallouee\n");
printf(" Valeurs: %p", s.valeurs);
printf(" taille: %u", s.taille);
destruction_serie(&s_triee);
printf("\n\nSerie triee desallouee\n");
printf(" Valeurs: %p", s_triee.valeurs);
printf(" taille: %u", s_triee.taille);
return 0;
}
En vous inspirant de l’exercice 1.7. de la partie 1, dans le programme tp5-serie.c, ajouter une fonction float mediane(serie s) qui calcule et retourne la médiane de la série s. Si la série est vide, la fonction doit retourner la valeur spéciale NAN (Not a Number) de l’en-tête math.h. Modifier la fonction main afin d’y ajouter l’affichage de la médiane de la série saisie.
Exemple d’exécution
Nombre de valeurs: 6
Valeur 1/7: 11
Valeur 2/7: 2
Valeur 3/7: 1
Valeur 4/7: 6
Valeur 5/7: 4
Valeur 6/7: 1
Valeur 7/7: 3
Serie: ( 1, 2, 1, 6, 4, 1, 3 )
Serie triee: ( 1, 1, 1, 2, 3, 4, 6 )
Moyenne de la serie: 2.571429
Variance de la serie: 3.102041
Mediane de la serie: 2.000000
Serie desallouee
Valeurs: (nil) taille: 0
Serie triee desallouee
Valeurs: (nil) taille: 0
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
void destruction_serie(serie* ps) {
if ((ps != NULL) && (ps->valeurs != NULL)){
free(ps->valeurs);
ps->valeurs = NULL;
ps->taille = 0;
}
}
float moyenne(serie s){
if ((s.valeurs != NULL) && (s.taille > 0)){
float m = 0;
for(int i = 0; i < s.taille; i++){
m += s.valeurs[i];
}
return m / s.taille;
}
return NAN;
}
float variance(serie s) {
float m = moyenne(s);
if (m != NAN){
float v = 0;
for(int i = 0; i < s.taille; i++){
v += (s.valeurs[i] - m)*(s.valeurs[i] - m);
}
return v / s.taille;
}
return NAN;
}
serie tri_croissant(serie s) {
serie r = creation_serie(s.taille);
for(int i=0;i<s.taille;i++){
r.valeurs[i] = s.valeurs[i];
}
// Tri selection
int c;
for(int i=0;i<s.taille-1;i++){
for(int j=i+1;j<s.taille;j++){
if ( r.valeurs[i] > r.valeurs[j] ) {
c = r.valeurs[i];
r.valeurs[i] = r.valeurs[j];
r.valeurs[j] = c;
}
}
}
return r;
}
float mediane(serie s) {
if ((s.valeurs != NULL) && (s.taille > 0)){
if (s.taille % 2 == 0)
return s.valeurs[(s.taille-1)/2];
else
return s.valeurs[s.taille/2];
}
return NAN;
}
int main(void){
serie s;
serie s_triee;
unsigned int nb_valeurs;
printf("Nombre de valeurs: ");
scanf("%u", &nb_valeurs);
s = creation_serie(nb_valeurs);
if (s.taille == 0) return 1; // Impossible d'allouer la memoire
for(int i = 0; i < s.taille; i++){
printf("Valeur %d/%d: ", i+1, s.taille);
scanf("%d", &(s.valeurs[i])); // equivalent a scanf("%d", s.valeurs+i))
}
printf("Serie: ");
affiche_serie(s);
s_triee = tri_croissant(s);
printf("\n\nSerie triee: ");
affiche_serie(s_triee);
printf("\n\nMoyenne de la serie: %f", moyenne(s));
printf("\n\nVariance de la serie: %f", variance(s));
printf("\n\nMediane de la serie: %f", mediane(s_triee));
destruction_serie(&s);
printf("\n\nSerie desallouee\n");
printf(" Valeurs: %p", s.valeurs);
printf(" taille: %u", s.taille);
destruction_serie(&s_triee);
printf("\n\nSerie triee desallouee\n");
printf(" Valeurs: %p", s_triee.valeurs);
printf(" taille: %u", s_triee.taille);
return 0;
}
3. Gestion de classes
Cette section vise à illustrer les capacités de calcul statistique implantées précédemment en simulant la gestion des notes d’un ensemble de classes dans une école. D’un point de vue statistique, une classe est représentée par une série de valeurs correspondant chacune à la moyenne individuelle d’un élève de la classe (les moyennes seront représentées par des nombres entiers entre $0$ et $20$).
Une école est un ensemble de classes chacune identifiée par un nombre entier allant de $1$ (première classe) à $n$ (dernière classe). Chaque classe peut être composée d’un nombre différent d’élèves et chaque école ayant un nombre variable de classes. Par exemple, une école comportant 3 classes, la première composée de 8 élèves, la seconde de 6 élèves et la troisième de 7 élèves peut se représenter comme suit:
Dans la figure précédente, le premier élève de la classe 1 à une moyenne de 15, le premier élève de la classe 2 à une moyenne de 13, le troisième élève de la classe 3 à une moyenne de 11.
Ecrire un programme tp5-ecole.c contenant la définition d’un type ecole reposant sur une structure dont les champs sont :
- Un pointeur nommé classes vers un ensemble de serie (réutiliser le type définit pour l’exercice 2.1 de la partie 2)
- Une variable nommée nb_classes de type unsigned int qui représente le nombre de classes présentes dans l’école.
Le programme doit contenir également une fonction main qui déclare une variable e de type ecole.
#include <stdio.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
typedef struct {
serie* classes;
unsigned int nb_classes;
} ecole;
void main(void){
ecole e;
}
Dans le programme tp5-ecole.c, ajouter une fonction ecole creation_ecole(unsigned int m) qui crée une ecole de m classes. Si la valeur de m est strictement inférieure à 1, la fonction renvoie une variable de type ecole dont le champ classes est à NULL et le champ nb_classes à 0. Modifier la fonction main afin de permettre à l’utilisateur de saisir un nombre de classes et de créer une variable e de type ecole avec le nombre de classes adéquat. Le programme affichera le nombre de classes crées et l'adresse pointée par la variable e.classes.
Exemple d’exécution
Nombre de classes dans l'ecole: 3
Classes dans l'ecole: 3
Addresse de e.classes: 0x5b2d29bd0ac0
#include <stdio.h>
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
typedef struct {
serie* classes;
unsigned int nb_classes;
} ecole;
void main(void){
ecole e;
}
Dans le programme tp5-ecole.c, ajouter une fonction void saisie_ecole(ecole e) qui demande à l’utilisateur de saisir l’ensemble des notes d’une école. L’école utilisée doit avoir été créée avant d’être saisie. La fonction a pour algorithme :
pour chaque classe c de e
demander le nombre d’eleves
créer une serie à partir du nombre d’élèves
pour chaque eleve e
demander sa moyenne individuelle
affecter la moyenne a la valeur e de la serie
finpour
affecter la serie saisie à la classe c
finpour
Aide: Il est recommandé de réutiliser toutes les fonctions relatives aux séries implantées lors de la partie 2 de ce travail.
Exemple d’exécution
Nombre de classes dans l'ecole: 3
Nombre d'eleves de la classe 1: 5
Note de l'eleve 1/5: 12
Note de l'eleve 2/5: 13
Note de l'eleve 3/5: 15
Note de l'eleve 4/5: 14
Note de l'eleve 5/5: 14
Nombre d'eleves de la classe 2: 4
Note de l'eleve 1/4: 4
Note de l'eleve 2/4: 15
Note de l'eleve 3/4: 16
Note de l'eleve 4/4: 9
Nombre d'eleves de la classe 3: 6
Note de l'eleve 1/6: 11
Note de l'eleve 2/6: 12
Note de l'eleve 3/6: 11
Note de l'eleve 4/6: 16
Note de l'eleve 5/6: 14
Note de l'eleve 6/6: 9
Classes dans l'ecole: 3
Addresse de e.classes: 0x5d047a6f5ac0
#include <stdio.h>
#include <stdlib.h> // malloc, free
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
typedef struct {
serie* classes;
unsigned int nb_classes;
} ecole;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
ecole creation_ecole(unsigned int m){
ecole e;
if (m > 0){
e.classes = (serie*) malloc(m*sizeof(serie));
e.nb_classes = m;
} else {
e.classes = NULL;
e.nb_classes = 0;
}
return e;
}
void saisie_ecole(ecole e) {
int tmp;
for(int i = 0; i < e.nb_classes; i++){
printf("Nombre d'eleves de la classe %d: ", i+1);
scanf("%d", &tmp);
e.classes[i] = creation_serie(tmp);
for(int j = 0; j < e.classes[i].taille; j++){
printf(" Note de l'eleve %d/%d: ", j+1, e.classes[i].taille);
scanf("%d", &(e.classes[i].valeurs[j]));
}
}
}
void main(void){
ecole e;
unsigned int n;
printf("Nombre de classes dans l'ecole: ");
scanf("%d", &n);
e = creation_ecole(n);
printf("\n");
saisie_ecole(e);
printf("\nClasses dans l'ecole: %u", e.nb_classes);
printf("\nAddresse de e.classes: %p", e.classes);
free(e.classes);
}
Dans le programme tp5-ecole.c, ajouter une fonction void affiche_ecole(ecole e) qui affiche l’école e sous la forme :
Classe 1 : ( s[0], …, s[i], …, s[n-1] )
…
Classe m : ( s[0], …, s[j], …, s[k-1] )
Modifier la fonction main du programme pour y ajouter l’affichage de l’école saisie.
Aide: Il est recommandé de réutiliser toutes les fonctions relatives aux séries implantées lors de la partie 2 de ce travail.
Exemple d’exécution
Nombre de classes dans l'ecole: 3
Nombre d'eleves de la classe 1: 5
Note de l'eleve 1/5: 12
Note de l'eleve 2/5: 13
Note de l'eleve 3/5: 16
Note de l'eleve 4/5: 14
Note de l'eleve 5/5: 11
Nombre d'eleves de la classe 2: 4
Note de l'eleve 1/4: 16
Note de l'eleve 2/4: 13
Note de l'eleve 3/4: 12
Note de l'eleve 4/4: 15
Nombre d'eleves de la classe 3: 6
Note de l'eleve 1/6: 18
Note de l'eleve 2/6: 11
Note de l'eleve 3/6: 12
Note de l'eleve 4/6: 11
Note de l'eleve 5/6: 16
Note de l'eleve 6/6: 15
Classe 1: ( 12, 13, 16, 14, 11 )
Classe 2: ( 16, 13, 12, 15 )
Classe 3: ( 18, 11, 12, 11, 16, 15 )
Classes dans l'ecole: 3
Addresse de e.classes: 0x560fb152dac0
#include <stdio.h>
#include <stdlib.h> // malloc, free
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
typedef struct {
serie* classes;
unsigned int nb_classes;
} ecole;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
ecole creation_ecole(unsigned int m){
ecole e;
if (m > 0){
e.classes = (serie*) malloc(m*sizeof(serie));
e.nb_classes = m;
} else {
e.classes = NULL;
e.nb_classes = 0;
}
return e;
}
void saisie_ecole(ecole e) {
int tmp;
for(int i = 0; i < e.nb_classes; i++){
printf("Nombre d'eleves de la classe %d: ", i+1);
scanf("%d", &tmp);
e.classes[i] = creation_serie(tmp);
for(int j = 0; j < e.classes[i].taille; j++){
printf(" Note de l'eleve %d/%d: ", j+1, e.classes[i].taille);
scanf("%d", &(e.classes[i].valeurs[j]));
}
}
}
void affiche_ecole(ecole e) {
for(int i = 0; i < e.nb_classes; i++){
printf("Classe %d: ", i+1);
affiche_serie(e.classes[i]);
printf("\n");
}
}
void main(void){
ecole e;
unsigned int n;
printf("Nombre de classes dans l'ecole: ");
scanf("%d", &n);
e = creation_ecole(n);
printf("\n");
saisie_ecole(e);
printf("\n");
affiche_ecole(e);
printf("\nClasses dans l'ecole: %u", e.nb_classes);
printf("\nAddresse de e.classes: %p", e.classes);
free(e.classes);
}
Dans le programme tp5-ecole.c, ajouter une fonction void destruction_ecole(ecole* pe) qui désalloue toute la mémoire utilisée par l’ecole pointée par pe. Modifier la fonction main du programme pour détruire l’école utilisée avant la fin de l’exécution.
Aide: Il est recommandé de réutiliser toutes les fonctions relatives aux séries implantées lors de la partie 2 de ce travail.
Exemple d’exécution
Nombre de classes dans l'ecole: 3
Nombre d'eleves de la classe 1: 4
Note de l'eleve 1/4: 15
Note de l'eleve 2/4: 16
Note de l'eleve 3/4: 12
Note de l'eleve 4/4: 11
Nombre d'eleves de la classe 2: 3
Note de l'eleve 1/3: 14
Note de l'eleve 2/3: 16
Note de l'eleve 3/3: 12
Nombre d'eleves de la classe 3: 4
Note de l'eleve 1/4: 16
Note de l'eleve 2/4: 15
Note de l'eleve 3/4: 12
Note de l'eleve 4/4: 9
Classe 1: ( 15, 16, 12, 11 )
Classe 2: ( 14, 16, 12 )
Classe 3: ( 16, 15, 12, 9 )
Destruction de e
Classes dans l'ecole: 0
Addresse de e.classes: (nil)
#include <stdio.h>
#include <stdlib.h> // malloc, free
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
typedef struct {
serie* classes;
unsigned int nb_classes;
} ecole;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void destruction_serie(serie* ps) {
if ((ps != NULL) && (ps->valeurs != NULL)){
free(ps->valeurs);
ps->valeurs = NULL;
ps->taille = 0;
}
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
ecole creation_ecole(unsigned int m){
ecole e;
if (m > 0){
e.classes = (serie*) malloc(m*sizeof(serie));
e.nb_classes = m;
} else {
e.classes = NULL;
e.nb_classes = 0;
}
return e;
}
void saisie_ecole(ecole e) {
int tmp;
for(int i = 0; i < e.nb_classes; i++){
printf("Nombre d'eleves de la classe %d: ", i+1);
scanf("%d", &tmp);
e.classes[i] = creation_serie(tmp);
for(int j = 0; j < e.classes[i].taille; j++){
printf(" Note de l'eleve %d/%d: ", j+1, e.classes[i].taille);
scanf("%d", &(e.classes[i].valeurs[j]));
}
}
}
void affiche_ecole(ecole e) {
for(int i = 0; i < e.nb_classes; i++){
printf("Classe %d: ", i+1);
affiche_serie(e.classes[i]);
printf("\n");
}
}
void destruction_ecole(ecole* pe){
if (pe != NULL){
for(int i = 0; i < pe->nb_classes; i++){
destruction_serie(&(pe->classes[i]));
}
free(pe->classes);
pe->classes = NULL;
pe->nb_classes = 0;
}
}
void main(void){
ecole e;
unsigned int n;
printf("Nombre de classes dans l'ecole: ");
scanf("%d", &n);
e = creation_ecole(n);
printf("\n");
saisie_ecole(e);
printf("\n");
affiche_ecole(e);
printf("\nDestruction de e");
destruction_ecole(&e);
printf("\n\nClasses dans l'ecole: %u", e.nb_classes);
printf("\nAddresse de e.classes: %p", e.classes);
}
Exercice 3.6.
Dans le programme tp5-ecole.c, Modifier la fonction main du programme pour permettre à l’utilisateur :
- De saisir une école complète
- D’afficher la moyenne d’une classe
- D’afficher la variance d’une classe
- D’afficher la médiane d’une classe
- De quitter le programme
Aide: Il est recommandé de réutiliser toutes les fonctions relatives aux séries implantées lors de la partie 2 de ce travail.
Un exemple de fonction main à compléter pour gérer le menu:
void main(void){
ecole e;
unsigned int n;
char choix = ' ';
while(choix != 'q'){
printf("\nGestion d'ecole\n");
printf("1: Saisir une ecole\n");
printf("2: Moyenne d'une classe\n");
printf("3: Variance d'une classe\n");
printf("4: Mediane d'une classe\n");
printf("q: Quitter\n\n");
printf("Choix: ");
scanf("%c", &choix);
getchar();
switch(choix){
case '1': // a completer
break;
case '2': // a completer
break;
case '3': // a completer
break;
case '4': // a completer
break;
case 'q': break;
default: printf("Choisir 1, 2, 3, 4 ou q.");
}
}
destruction_ecole(&e);
printf("\n\nClasses dans l'ecole: %u", e.nb_classes);
printf("\nAddresse de e.classes: %p", e.classes);
}
Exemple d’exécution
Nombre de classes dans l'ecole: 3
Nombre d'eleves de la classe 1: 4
Note de l'eleve 1/4: 15
Note de l'eleve 2/4: 16
Note de l'eleve 3/4: 12
Note de l'eleve 4/4: 11
Nombre d'eleves de la classe 2: 3
Note de l'eleve 1/3: 14
Note de l'eleve 2/3: 16
Note de l'eleve 3/3: 12
Nombre d'eleves de la classe 3: 4
Note de l'eleve 1/4: 16
Note de l'eleve 2/4: 15
Note de l'eleve 3/4: 12
Note de l'eleve 4/4: 9
Classe 1: ( 15, 16, 12, 11 )
Classe 2: ( 14, 16, 12 )
Classe 3: ( 16, 15, 12, 9 )
Destruction de e
Classes dans l'ecole: 0
Addresse de e.classes: (nil)
#include <stdio.h>
#include <stdlib.h> // malloc, free
typedef struct {
int* valeurs;
unsigned int taille;
} serie;
typedef struct {
serie* classes;
unsigned int nb_classes;
} ecole;
serie creation_serie(unsigned int n) {
serie s;
if (n > 0){
s.valeurs = (int*) malloc(n*sizeof(int));
s.taille = n;
} else {
s.valeurs = NULL;
s.taille = 0;
}
return s;
}
void destruction_serie(serie* ps) {
if ((ps != NULL) && (ps->valeurs != NULL)){
free(ps->valeurs);
ps->valeurs = NULL;
ps->taille = 0;
}
}
void affiche_serie(serie s){
printf("( ");
if ((s.valeurs != NULL) && (s.taille > 0)){
printf("%d", s.valeurs[0]);
for(int i = 1; i < s.taille; i++){
printf(", %d", s.valeurs[i]);
}
}
printf(" )");
}
ecole creation_ecole(unsigned int m){
ecole e;
if (m > 0){
e.classes = (serie*) malloc(m*sizeof(serie));
e.nb_classes = m;
} else {
e.classes = NULL;
e.nb_classes = 0;
}
return e;
}
void saisie_ecole(ecole e) {
int tmp;
for(int i = 0; i < e.nb_classes; i++){
printf("Nombre d'eleves de la classe %d: ", i+1);
scanf("%d", &tmp);
e.classes[i] = creation_serie(tmp);
for(int j = 0; j < e.classes[i].taille; j++){
printf(" Note de l'eleve %d/%d: ", j+1, e.classes[i].taille);
scanf("%d", &(e.classes[i].valeurs[j]));
}
}
}
void affiche_ecole(ecole e) {
for(int i = 0; i < e.nb_classes; i++){
printf("Classe %d: ", i+1);
affiche_serie(e.classes[i]);
printf("\n");
}
}
void destruction_ecole(ecole* pe){
if (pe != NULL){
for(int i = 0; i < pe->nb_classes; i++){
destruction_serie(&(pe->classes[i]));
}
free(pe->classes);
pe->classes = NULL;
pe->nb_classes = 0;
}
}
void main(void){
ecole e;
unsigned int n;
printf("Nombre de classes dans l'ecole: ");
scanf("%d", &n);
e = creation_ecole(n);
printf("\n");
saisie_ecole(e);
printf("\n");
affiche_ecole(e);
printf("\nDestruction de e");
destruction_ecole(&e);
printf("\n\nClasses dans l'ecole: %u", e.nb_classes);
printf("\nAddresse de e.classes: %p", e.classes);
}