|
|
|
|
Bonjour et merci d'avance pour votre aide précieuse.
Ne vous inquietez pas si c'est si long c'est juste quelques points qui me pose probleme dans ces exos.
Dans le premir exo je ne sais pas du tout comment faire pour definir les intervalles faire afficher les etoiles, et retourner le tableau.
Dans le second exo, je sais comment faire pour determiner le plus petit et le plus grand salaire.
Il est evident que si une ame charitable se devoue pour me faire les deux exos je ne peux que plussoyer.
L’objectif de cet exercice est de vous faire manipuler un tableau de réel. Pour analyser une série
de mesures réelles strictement positives (saisies par l’utilisateur, marqueur de fin –1 par
exemple), dont on sait qu'elles sont comprises entre 0,0 et 10,0 ; on propose de les visualiser
par un histogramme. L'histogramme représente les comptages des mesures réparties dans des
intervalles, par exemple : ]0; 2], ]2; 4]…]8; 10].
Ainsi, pour la série de mesures suivantes :
8.3 ; 6.5 ; 7.2 ; 6.5 ; 3.4 ; 2.5 ; 3.5 ; 4.9 ; 7.3 ; 6.2 ; 1.5 ; 0.3 ; 5.8 ; 7.6 ; 3.9 ; 8.2
On désire afficher l'histogramme :
]0,2] : **
]2,4] : ****
]4,6] : **
]6,8] : ******
]8,10] : **
Le programme que vous devez réaliser en langage C devra, après saisie des mesures, afficher
l’histogramme tel qu’il apparaît ci-dessus, ainsi que les bornes des intervalles contenant le moins
et le plus de valeur.
On vous demande d’adopter une approche modulaire. En effet, vous devez décomposer le
problème en sous problèmes qui seront modélisés sous forme de sous-programmes : procédure ou
fonction. Par exemple, on écrira :
- une procédure qui permettra de saisir, de valider (comprises entre 0 et 10) et de
construire l’histogramme.
- une procédure qui permettra d’afficher l’histogramme correspondant aux valeurs
stockées dans le tableau.
- une fonction qui retourne l’intervalle qui contient le plus de valeur
- une fonction qui retourne l’intervalle qui contient le moins de valeur
Vous pouvez bien sûr définir d’autres procédures ou fonctions si vous en ressentez le besoin. On
pourra se poser les questions suivantes : le code est t-il plus lisible ? Ne peux t-on pas réutiliser du
code déjà écrit ? Vous testerez et rendrez accessibles l’ensemble de ces fonctions/procédures par
le biais d’un menu accessible via une structure de type cas ou (switch)
Dans un deuxième temps on vous demande de proposer une version de ce programme ou le
nombre d’intervalles et les bornes de ceux-ci sont demandés à l’utilisateur.
L’objectif de cet exercice est de vous faire manipuler un tableau de structure. Pour cela on
utilisera un tableau personnel de 30 personnes, pour décrire le personnel d’une entreprise.
Constante N = 30
Type salarie = Structure
nom : Chaîne
salaire : Réel
FinStructure
variable personnel : Tableau[1..N] de salarie
Le programme que vous devez réaliser en langage C devra, à partir du tableau personnel,
afficher :
a) les noms de tous les salariés qui ont un salaire strictement supérieur au SMIC (qui est de
12541,31 €)
b) le salaire moyen
c) le nom du salariés ou des salariés ayant le salaire minimal et les noms de celui ou ceux
ayant le salaire maximal.
Réaliser un programme qui réponde à ce cahier des charges en adoptant une approche modulaire :
décomposer le problème en sous problèmes (procédure ou fonction), test unitaire, test
d’intégration, séparation en plusieurs fichiers, etc.
Comment définir les intervalles?
double tab[] = {8.3, 6.5, 7.2, 6.5, 3.4, 2.5, 3.5, 4.9, 7.3, 6.2, 1.5, 0.3, 5.8, 7.6, 3.9, 8.2 };
Puis on crée une fonction qui retourne le nombre d'élements compris dans ]0,2]: int nb_intervalle02(double *tableau, int longueur)
{
//On part de zero nombre dans cet intervalle
int nb_inter=0;
int i;
//On parcoure chaque champs
for (i=0; i< longueur; i++)
{
//Le champs examiné est t'il dans le bon interval?
if (tableau[i] >0 && tableau[i] <= 2){
//Si c'est vrai, on incrémente notre compteur de nombre dans l'interval
nb_inter++;
}
}
return nb_inter;
}
//On teste la fonction:
int main()
{
printf("%d\n", nb_intervalle02(tab, sizeof(tab)));
return 0;
}
Dans cette fonction, l'idéal est de vérifier chaque cas: le nombre est t'il dans l'interval ]0, 2] alors on incrémente le compteur approprié, sinon est t'il dans l'interval ]2 , 4] alors on incrémente un autre compteur associé à cet intervalle etc.... Ca ne résout pas tous tes problèmes mais voilà déjà quelques indications. ..et le...le...enfin, non parce c'est...ya...quand...bah tu sais là le... |
Pour le premier exo, il faut ranger dans une structure décrivant les valeurs de ton histogramme. Si j'ai bien compris les valeurs sont toutes comprises entre 0 et 10 et tu as un ensembles d'intervalles.
#include <cassert>
class intervalle_t{
protected:
double min; // la borne min
double max; // la borne max
bool min_exclu; // la borne min est elle exclue ?
bool max_exclu; // la borne max est elle exclue ?
public:
// Le constructeur
intervalle_t(const double & min0=0,const double & max0=0,bool min_exclu0=false,bool max_exclu0=false):
min(min0),max(max0),
min_exclu(min_exclu0),max_exclu(max_exclu0)
{
assert(min<=max);
}
// Obtenir la borne inférieure
inline const double & get_min() const{
return min;
}
// Obtenir la borne supérieure
inline const double & get_max() const{
return max;
}
// Est ce que x est dans l'intervalle
inline bool contient(const double & x) const{
return (x > min || x >= min && !min_exclu) &&
(x < max || x <= max && !max_exclu);
}
};
Ok alors maintenant l'histogramme c'est juste un ensemble d'intervalle. Il faudra juste que tu contrôles que les intervalles forme une plage continue de valeurs, et qu'ils ne se recouvrent pas. Afin d'ordonner les intervalles (en priorité sur la borne min, ensuite sur la borne max), ce qui facilitera ce contrôle, je vais définir une relation d'ordre : inline bool operator<(const intervalle_t & i,const intervalle_t & j){
return (i.get_min() < j.get_min()) ||
(i.get_min() == j.get_min() && i.get_max() < j.get_max());
}
Il nous faut aussi un opérateur pour écrire un intervalle (<<). Tant qu'à faire je vais définir du même coup l'ecriture sur un std::ostream et un std::ofstream (en gros pour un fichier ou une sortie standard), et ceux à l'aide d'un template. Un template est en fait un type qui est remplacé à la compilation en fonction des besoins du programme. Une fonction template est toujours écrite intégralement dans le .hpp. template <typename Tstream>
Tstream & operator << (Tstream &,const intervalle_t i){
if (min_exclu) out << ']';
else out << '[';
out << min << ',' << max;
if (max_exclu) out << '[';
else out << ']';
return out;
}
A partir de maintenant on peut utiliser les std::set car l'operateur < a été défini. Là on a écrit le fichier intervalle.hpp, et on va passer maintenant à histogramme.hpp (un fichier par classe) #include "intervalle.hpp"
#include <set>
#include <map>
class histogramme_t{
protected:
std::map<intervalle_t,unsigned int> datas;
public:
// Le constructeur par défaut
histogramme_t(){}
//Un autre constructeur. A partir d'un ensemble d'intervalle je
// construit une map qui associe pour chaque intervalle le nb de pt
histogramme_t(const std::set<intervalle_t> & intervalles0){
const std::set<intervalle_t>::const_iterator
intervalle_it (intervalles0.begin()),
intervalle_end(intervalles0.end());
for(;intervalle_it!=intervalle_end;++intervalle_it){
const intervalle_t & intervalle = *intervalle_it;
datas[intervalle] = 0;
}
}
// Encore un constructeur (ici j'ai déjà ma map de point d'initialisée)
histogramme_t(const std::map<intervalle_t,unsigned int> & datas0):
datas(datas0)
{}
// Ajouter un point
void ajouter_point(const double & x){
std::map<intervalle_t,unsigned int>::iterator
data_it (datas.begin()),
data_end(datas.end());
for(;data_it!=data_end;++data_it){
const intervalle_t & intervalle = data_it->first;
if(intervalle.contient(x)) ++(data_it->second);
}
}
// Ecrire l'histogramme
template <typename Tstream>
Tstream & operator << (Tstream & out) const{
std::map<intervalle_t,unsigned int>::iterator
data_it (datas.begin()),
data_end(datas.end());
for(;data_it!=data_end;++data_it){
const intervalle_t & intervalle = data_it->first;
out << intervalle << " : ";
const unsigned int nb_etoile = data_it->second;
for(unsigned int i=0;i<nb_etoile;++i) out << '*';
out << std::endl;
}
return out;
}
};
Bon ben maintenant on à tout ce qu'il nous faut pour écrire main.cpp #include "intervalle.hpp"
#include "histogramme.hpp"
#include <iostream>
int main(){
// Construction des intervalles
std::set<intervalle_t> intervalles;
{
intervalles.insert(intervalle_t(0,2,false,true));
intervalles.insert(intervalle_t(2,4,false,true));
intervalles.insert(intervalle_t(4,6,false,true));
intervalles.insert(intervalle_t(6,8,false,true));
intervalles.insert(intervalle_t(8,10,false,true));
}
histogramme_t h(intervalles); // 2e constructeur
// Ajout des points
{
h.ajouter_point(1.1);
h.ajouter_point(6.9);
h.ajouter_point(2.8);
}
// Ecriture de l'histogramme
std::cout << h << std::endl;
return 0;
}
Bien spur comme il est tard je n'ai pas le temps de tester si tout ce que j'ai écrit marche mais c'est juste pour te donner une idée. Si tu as compris dans cet exemple à quoi servaient les iterator tu vas tout suite voir comment trouver l'intervalle qui a le plus ou le moins de valeur. Au besoin n'hésite pas à poser des questions si certains points dans le code te semblent peu clairs ou si tu ne vois pas comment faire Bonne chance |
Le probleme c'est que je debute à peine le semestre 2 de L1 çà fait que tout ce que vous dites là je l'ai pas fait ...
|
Oui alors effectivement si tu débutes ça ne va pas te convenir car apparemment tu n'as vu ni les classes, ni les référénces, ni les templates, ni les operator, ni la STL. Ca ne m'étonne pas que tu sois perdue !! En fait tu aurais dû mettre C dans le titre car tu n'as pas encore commencé à voir le C++.
|
Répondre à mamiemando
|
Desole si j'ai fait uniquement du C et pas pas du C++ mais sur ma feuille de TP y a les deux donc bon o_O
|
Oui les structures vont aider.
struct intervalle{
double inf, sup; // les bornes
int val; // la valeur
};
intervalle intervalles[5];
Une procédure pour initialiser les intervalles : void initialiser()
{
int i;
for(i = 0; i < 5; i++)
{
intervalles[i].inf = i * 2;
intervalles[i].sup = i * 2 + 1;
intervalles[i].val = 0;
}
}
Et une procédure pour y ajouter des réels : void saisir(double val)
{
int i;
for(i = 0; i < 5; i++)
{
if(val > intervalles[i].inf && val <= intervalles[i].sup)
{
intervalles[i].val++;
return;
}
}
// si on arrive ici, la valeur ne se range dans aucun intervalle
printf("Veuillez entrer un réel dans ]0.0;10.0]\n");
}
Une procédure pour afficher : void afficher()
{
int i, j;
for(i = 0; i < 5; i++)
{
printf("]%f,%f] : ", intervalles[i].inf, intervalles[i].sup);
for(j = 0; j < intervalles[i].val; j++)
printf("*");
printf("\n");
}
}
Une fonction pour le minimum : int minimum()
{
int i, imin, min = -1;
for(i = 0; i < 5; i++)
{
if(-1 == min || intervalles[i].val < min)
{
imin = i;
min = intervalles[i].val;
}
}
return imin;
}
Je te laisse faire celle du maximum :) |
J'ai compilé avec Dev c++ 4.9.9.2 et je n'ai aucune erreur à la compilation. (Enfin, j'avoue, j'ai trop trempé dans le C++ pour avoir oublié le "struct" devant les structures...)
/**
* @file plop.c
* @author plop!
* @date 03/02/07 05:30
* @brief Truc de N00b
*/
#include <stdio.h>
#include <windows.h>
struct intervalle{
double inf, sup; // les bornes
int val; // la valeur
};
struct intervalle intervalles[5];
void initialiser()
{
int i;
for(i = 0; i < 5; i++)
{
intervalles[i].inf = i * 2;
intervalles[i].sup = ( i + 1 )* 2;
intervalles[i].val = 0;
}
}
void saisir(double val)
{
int i;
for(i = 0; i < 5; i++)
{
if(val > intervalles[i].inf && val <= intervalles[i].sup)
{
intervalles[i].val++;
return;
}
}
// si on arrive ici, la valeur ne se range dans aucun intervalle
printf("Veuillez entrer un réel dans ]0.0;10.0]\n");
}
void afficher()
{
int i, j;
for(i = 0; i < 5; i++)
{
printf("]%f,%f] : ", intervalles[i].inf, intervalles[i].sup);
for(j = 0; j < intervalles[i].val; j++)
printf("*");
printf("\n");
}
}
int minimum()
{
int i, imin, min = -1;
for(i = 0; i < 5; i++)
{
if(-1 == min || intervalles[i].val < min)
{
imin = i;
min = intervalles[i].val;
}
}
return imin;
}
int main()
{
float in;
initialiser();
printf("Entrez des réels dans ]0;10] en terminant par 0\n");
while(1)
{
scanf("%f", &in);
if(in == 0) break;
saisir(in);
}
afficher();
//afficher ici les intervalles minimums et maximums
system("pause>nul");
return 0;
}
|
Répondre à nuleninfo
|
Ce que tu écris ne veux rien dire, je pense que là il faut relire ton cours de C, car ça ne sert à rien de te donner la solution direct si on veut que tu apprennes quelque chose. Par exemple :
typedef struct{
double salaires[TAILLE];
char noms[TAILLE][30]; // les noms sont de longueurs < 30
} salaries_t;
- Un exemple : la fonction moyenne devrait en toute rigueur se contenter de renvoyer un double (la moyenne) et l'affichage se fait depuis le main
#define TAILLE 30
...
double moyenne(double *tab,unsigned int taille){
unsigned int i;
double moyenne=0;
for(i=0;i<taille;++i) moyenne += tab[i];
moyenne /= taille;
return moyenne;
}
int main(){
salaries_t salaries;
... // remplissage de la structure
printf("Moyenne : %d\n",moyenne((double *) (salaries.salaires),TAILLE));
return 0;
}
Bonne chance |
Mon dieu tu veux la tuer
moyenne /= taille;est équivlent à moyenne = moyenne / taille;--------------------- printf("Moyenne : %d\n",moyenne((double *) (salaries.salaires),TAILLE));
est équivlent à double moy = moyenne((double *) (salaries.salaires), TAILLE);
printf("Moyenne : %d\n", moy);
Le (double *) sert à convertir le type de la variable salaries.salaires, car c'est un tableau de TAILLE cases, alors que la fonction prend en paramètre un tableau de n'importe quelle taille. (il faut savoir qu'un tableau est un pointeur vers le premier élément de ce tableau. Mais allons donc expliquer ce qu'est un pointeur à nuleninfo...) Pourquoi les filles sont nulles en info ?? Heureusement que mamiemando est là ! |