Cette semaine, nous ne vous proposons pas un nouveau parser. Cet exercice est très abordable pour tout le monde, quel que soit le niveau : un chronomètre.
Si vous souhaitez plus de renseignements sur les défis, rendez vous sur le topic de recensement des défis, vous y trouverez également les règles principales.
Cet exercice a été écrit par GuilOooo, un grand merci à lui !
Un Chronomètre
Salut !
Le défi de la semaine sera de recréer un chronomètre. Ce défi est plutôt simple et les explications vous permettront de vous aider si vous avez des difficultés. Sachez que ce défi est accessible dès la fin de la partie 2 du tutoriel officiel du site. Passons dès à présent au cahier des charges.
Cahier des charges
Cet exercice serra composé de trois niveaux :
Niveau 1 :
Vous devrez arrivez à reproduire ce programme :
Appuyez sur "Entrée" :
Encore :
Il s'est écoulé 11 secondes.
Vous devez donc simplement calculer les temps écoulé entre les 2 "Enter". Pour cela vous pouvez utiliser les fonctions du header standard time.h. D'ailleurs, il y a un tuto à ce sujet.
Pour attendre l'appui sur la touche Entrée, vous pouvez utiliser la fonction getchar() ou encore simplement un scanf(). Les fonctions que vous devrez utiliser afin de récupérer la date sont time() et difftime().
Niveau 2 :
Vous devrez arrivez à reproduire ceci :
Appuyez sur "Entrée" :
Encore :
Il s'est écoulé 4.255 secondes.
La différence avec le premier ? La précision. Ici nous allons gérer une précision grandement accrue, de l'ordre de la micro seconde.
Pour cela, nous allons utiliser des fonctions différentes pour la gestion du temps, mais pour l'attente de l'appuie sur la touche Entrée, vous pouvez encore utiliser getchar() ou scanf().
Pour le temps, cette fois ci nous allons utiliser la fonction clock() qui se base sur la fréquence du processeur. Pour retrouver un résultat en seconde, vous devrez utiliser la macro CLOCKS_PER_SEC.
Niveau 3 :
Les choses se gâtent.
En effet, vous allez essayer d'afficher le temps écoulé en temps réel. Cette fois-ci, vous êtes libre du résultat, cependant, pour vous montrer un exemple voici ce que pourrait afficher votre programme :
Appuyez sur "Entrée" :
Encore :
Deja 1 seconde
Deja 2 seconde
Deja 3 seconde
Deja 4 seconde
Il s'est écoulé 4.625 secondes.
Vous pouvez arriver à ce résultat par plusieurs moyens. Le plus simple étant d'utiliser des fonctions propre à votre système mais ce n'est pas la seul solution.
Vous pouvez :
Vérifier l'état de la touche Entrée grâce à des fonctions propres à votre système.
Utiliser le multithreading afin de gérer plusieurs threads et donc de gérer l'appui d'une touche grâce à un thread enfant.
Il est clair que la première solution est la plus simple. Je vous laisse chercher les informations pour ce niveau, mais généralement vous trouverez très facilement grâce à votre moteur de recherche préféré. Il serait intéressant de se renseigner sur les différentes manières proposées. Il serait aussi intéressant de voir certaines personnes se pencher sur les 2 dernières méthodes qui ont été proposées ou même de réaliser ce programme par une autre méthode encore.
Vous aurez dans tous les cas certainement besoin d'une fonction permettant d'attendre un certain temps. Pour cela, il n'existe pas de fonction portable vous pouvez :
Sous Windows : inclure windows.h et utiliser la fonction Sleep() (avec une majuscule).
Sous Linux et Mac OS : inclure unistd.h et utiliser la fonction sleep().
@Loadware: Comme dit dans l'énoncé, tu as pris la solution la plus simple (et tu as bien raison).
Après, si tu te sens à l'aise, peut-être devrais-tu essayer la programmation événementielle. Par-contre, ça nécessite un peu de recherche
Citation : kaka551
Citation
Cet exercice a été écrit par GuilOooo, un grand merci à lui !
Le défi n'est pas de @che ?
Oh, c'est une petite erreur, tu as raison, c'est bien moi qui l'ai écrit, mais d'après l'idée de GuilOooo
@Ouss4: C'est un vrai exercice pour débutant, ici, l'exercice est plus axé sur la recherche que sur le résultat. Tu devrais essayer
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles- ♡ Copying is an act of love.
@Ouss4: C'est un vrai exercice pour débutant, ici, l'exercice est plus axé sur la recherche que sur le résultat. Tu devrais essayer
Oui oui je viens de voir le défis, je croyais qu'il était comme les précédents.
Mais bon vais essayer de le faire après mon repas
EDIT : J'ai fait le niveau 3, très similaire à celui de Loadware, je connaissais pas bien les fonctions de "conio.h" donc j'ai un peu chercher, et je dois avouer que je ne l'aurais pas fait avec si loadware n'en avait pas parler, j'aurais très probablement galérer sans "kbhit()"...
/*******************************************************
Nom ......... : main.c
Role ........ : chronomètre
Auteur ...... : lucas-84
Version ..... : 15/10/2011
Licence ..... : aucune
Compilation :
gcc -W -Wall -Wextra -pedantic main.c
Pour exécuter, tapez :
Windows : ./limites.exe
Unix : ./a.out
********************************************************/
/* printf() - perror() */
#include <stdio.h>
/* exit() - EXIT_SUCCESS */
#include <stdlib.h>
/* time_t - time() - difftime() */
#include <time.h>
/* void enter(const char *s);
Entrée : une chaîne de caractère qui sera affichée
Sortie : aucune
Description : la fonction enter() afficher la chaîne de caractère s suivie
d'un espace et attend que l'utilisateur appuie sur "Entrée" */
void enter(const char *s)
{
printf("%s ", s);
getchar();
}
/* time_t take_time(void);
Entrée : aucune
Sortie : nombre de secondes écoulées depuis le 1er Janvier 1970 à 00h 00m 00s
GMT
Description : la fonction time() retourne le nombre de secondes écoulées
depuis le 1er Janvier 1970 à 00h 00m 00s GMT */
time_t take_time(void)
{
time_t t;
if ((t = time(NULL)) == -1) {
perror("time :");
exit(EXIT_FAILURE);
}
return t;
}
/* void print_result(int result);
Entrée : le résultat
Sortie : aucune
Description : la fonction print_result affiche le temps écoulé entre les deux
frappes sur "Entrée" */
void print_result(int result)
{
printf("Time elapsed: %d seconds.\n", result);
}
/* int calc(time_t t1, time_t t2);
Entrée : deux temps
Sortie : la différence entre les deux temps
Description : la fonction calc retourne la différence entre deux temps */
int calc(time_t t1, time_t t2)
{
return (int)difftime(t2, t1);
}
/* void chrono(void);
Entrée : aucune
Sortie : aucune
Description : fonction principale du programme */
void chrono(void)
{
time_t t1, t2;
enter("Press enter:");
t1 = take_time();
enter("Again:");
t2 = take_time();
print_result(calc(t1, t2));
}
int main(void)
{
chrono();
return EXIT_SUCCESS;
}
Il y a un petit problème dans l'exercice qui est proposé. Pour le niveau 1 utilisant time et difftime il n'y a pas de soucis, par contre, pour le niveau 2, l'utilisation de clock est problématique. En effet, cette dernière retourne la meilleure approximation du temps processus utilisé par le programme depuis qu'il a été exécuté:
Citation : Norme C99 7.23.2.1 § 3 p 339
The clock function returns the implementation's best approximation to the processor
time used by the program since the beginning of an implementation-defined era related
only to the program invocation. To determine the time in seconds, the value returned by
the clock function should be divided by the value of the macro CLOCKS_PER_SEC. If
the processor time used is not available or its value cannot be represented, the function
returns the value (clock_t)(-1).
Or, en faisant appel à getchar ou tout autre fonction qui ont pour effet "d'endormir" le processus, ce temps est dans ce cas nul (puisque le processeur n'est pas sollicité).
D'ailleurs, seuls les codes proposés par Tosh et Loadware retourne un temps non nul. En effet, celui de Tosh boucle tant qu'il n'y a rien à lire sur l'entrée standard (la fonction select bloquant au maximum le programme pendant 10 millisecondes). Celui de Loadware fait plus ou moins la même chose (je ne connais pas la fonction _kbhit ) en mettant le programme en pause pendant 20 millisecondes à chaque tour de boucle.
Le but est d'éviter que le programme ne soit bloqué par les lectures sur l'entrée standard en utilisant l'attribut O_NONBLOCK. Pour le reste, le programme boucle et dort 1 microsecondes à chaque tour. Le programme reçoit le signal SIGALRM toutes les secondes afin d'afficher l'état du chronomètre.
J'avais placé l'appel à usleep histoire d'éviter que le programme n'utilise tout le cpu; en pensant que cela n'influencerait pas trop les résultats. Mais visiblement je me suis trompé
@loadware : on peut dire que les threads sont portables, vu que MinGW en fournit une implantation également.
Je n'ai pas eu le temps de finaliser mon code multithread. PS : quelqu'un pourrait-il m'expliquer des manières portables de faire de la programmation événementielle, je l'avoue curieux.
Je n'ai jamais entendu parler de l'implantation des threads dans MinGW... je devrais faire une recherche dessus. Perso quand j'ai besoin de faire du multithreading j'utilise la lib pthreads-win32.
En même temps, les threads seront bientôt standards (C1X)
Sinon, pour la programmation évènementielle, il faudrait que tu utilises des bibliothèques pour avoir un code portables. Ce n'est pas vraiment le but de l'exo, mais si ça te tente vas-y
Moi perso, je ne suis pas allez aussi loin :
Citation : @che
Faire de la programmation évènementielle grâce à des fonctions propres à votre système,
Ouh mais c'est qu'il y a du monde C'est bien.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles- ♡ Copying is an act of love.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("Appuyez sur Entrée !");
getchar();
printf("Appuyez une seconde fois sur Entrée !");
getchar();
printf("Il s'est écoulé 42 secondes !\n");
return EXIT_SUCCESS;
}
Pour le niveau 2 :
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf("Appuyez sur Entrée !");
getchar();
printf("Appuyez une seconde fois sur Entrée !");
getchar();
printf("Il s'est écoulé 42.000 secondes !\n");
return EXIT_SUCCESS;
}
Pour le niveau 3 :
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int i;
printf("Appuyez sur Entrée !");
getchar();
printf("Appuyez une seconde fois sur Entrée !");
getchar();
for (i = 1; i <= 42; i++)
printf("Déjà %d secondes !\n", i);
printf("Il s'est écoulé 42.000 secondes !\n");
return EXIT_SUCCESS;
}
Comme déjà dit plus haut, c'est pas très malin d'utiliser clock pour calculer le temps, sachant que clock utilise les cycles CPU, en utilisant une fonction bloquante (getchar) on arrive à 0 secondes d'exécution. ahah
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.
🍊 - Étudiant - Codeur en C | Zeste de Savoir apprenez avec une communauté | Articles - ♡ Copying is an act of love.