Partage
  • Partager sur Facebook
  • Partager sur Twitter

zDate

Exercice Langage C

Anonyme
    31 août 2012 à 14:09:43

    Mois : Septembre
    Sujet : Gestion des dates


    zDate



    Salut à tous !

    Aujourd'hui je vous propose un nouvel exercice !
    On commence sans plus attendre ! :pirate:


    Niveau 1



    Pour ce premier niveau, on va faire simple pour que les débutants puissent se familiariser un peu avec la gestion des dates.
    En entrée vous allez recevoir une chaîne de caractère sous cette forme :

    jour mois


    par exemple :

    13 janvier
    30 septembre
    ...


    Afin de convertir une chaîne de caractère en nombre, il faut utiliser la fonction strtol.
    Voici un tutoriel qui vous présente l'utilisation de cette fonction : lien.



    Ensuite, l'utilisateur saisira un nombre. Ce nombre indiquera de combien de jour il faudra ajouter à la date entrée précédemment. Pour faire simple, ne vous préoccupez pas des cas où l'on doit passer au mois suivant par exemple. Cependant, faîtes attention au mois de février qui ne comporte que 28 jours !

    Par exemple :

    ** zDate (niveau 1) **
    
    date : 
    > 13 septembre
    nombre à ajouter :
    > 3
    
    date finale : 
    > 16 septembre


    Niveau 2



    On va corser un peu le tout.

    Désormais le nombre entré peut dépasser le nombre de jour maximum d'un mois.

    Exemple :

    ** zDate (niveau 2) **
    
    date : 
    > 13 septembre
    nombre à ajouter :
    > 20
    
    date finale : 
    > 3 octobre


    Niveau 3



    Cette fois-ci, on gère les années !

    Exemple :

    ** zDate (niveau 3) **
    
    date : 
    > 21 décembre 2012
    nombre à ajouter :
    > 20
    
    date finale : 
    > 10 janvier 2013


    Bonus n°1 : Essayez de gérer les années bissextiles

    Niveau 4



    Pour finir, codez-moi un petit menu qui permettra à l'utilisateur de choisir si il veut ajouter ou soustraire des jours à une date.

    Exemple :

    ** zDate (niveau 4) **
    
    date : 
    > 13 septembre 2012
    
    Que voulez-vous faire ?
    
    1. Ajouter un nombre
    2. Soustraire un nombre
    
    > 2
    
    nombre à soustraire : 
    > 13
    
    date finale : 
    > 31 août 2012


    Voilà c'est tout pour le moment, n'hésitez pas à laisser un commentaire, à proposer une idée, un bonus, à poser une question ou autres choses.

    Je vous souhaite bonne chances à tous !

    EDIT : un grand merci à paraze pour la mise en forme et les explications :)
    • Partager sur Facebook
    • Partager sur Twitter
      31 août 2012 à 15:19:53

      Dois-t-on gérer les dates avant le 15 octobre 1582 ? :-°
      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        31 août 2012 à 15:43:17

        Citation : sildre

        Dois-t-on gérer les dates avant le 15 octobre 1582 ? :-°



        pourquoi cette date précisément ? :)
        • Partager sur Facebook
        • Partager sur Twitter
          31 août 2012 à 15:56:35

          Citation : tib92

          Citation : sildre

          Dois-t-on gérer les dates avant le 15 octobre 1582 ? :-°


          pourquoi cette date précisément ? :)


          Parce que la veille du vendredi 15 octobre 1582, c'est le jeudi 4 octobre 1582. Ça correspond au passage du calendrier julien au calendrier grégorien (le calendrier tel qu'on le connaît). Le calendrier julien a 365,25 jours par an, alors que le calendrier grégorien en a 365,2425.
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            31 août 2012 à 16:02:56

            je ne savais pas merci :)
            sinon pour répondre à ta question non ne t'embêtes pas avec ça ;)

            PS : j'ai trouvé un bonus grâce à ta question j'édite tout de suite
            • Partager sur Facebook
            • Partager sur Twitter
              31 août 2012 à 17:17:50

              Tu devrais plus préciser la chose, donner des conseils, rajouter des explications etc.

              J'ajoute l'exo, et merci. :)
              • Partager sur Facebook
              • Partager sur Twitter
                31 août 2012 à 17:25:12

                Citation : Énoncé

                Sujet : parser une chainer de caractère


                C'est loin d'être la difficulté principale du sujet, non ? Parce que bon, un scanset et c'est réglé...
                • Partager sur Facebook
                • Partager sur Twitter
                Staff désormais retraité.
                  31 août 2012 à 17:33:20

                  Je me suis dit ça aussi. :p
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Anonyme
                    31 août 2012 à 17:53:00

                    Citation : Lucas-84

                    Citation : Énoncé

                    Sujet : parser une chainer de caractère


                    C'est loin d'être la difficulté principale du sujet, non ? Parce que bon, un scanset et c'est réglé...



                    oui effectivement mais je ne sais pas trop quoi mettre à la place ^^

                    Citation : paraze

                    Tu devrais plus préciser la chose, donner des conseils, rajouter des explications etc.



                    tu trouves un point pas très expliqué ou c'est en général ? :)
                    • Partager sur Facebook
                    • Partager sur Twitter
                      31 août 2012 à 21:37:50

                      J'ai eu beaucoup de mal à comprendre le niveau 1 je pense que tu devrais remanier ça.
                      Sinon ça peux être un bon exo :) Est-ce que utiliser le timestamp est une bonne idée ?
                      • Partager sur Facebook
                      • Partager sur Twitter
                        31 août 2012 à 21:49:45

                        Pour le niveau 1 (si j'ai bien compris) :
                        • Tu demandes une saisie du type jj moisEnTouteLettre.
                        • Tu demandes un nombre n qui doit être inférieur à (nbJourDansCeMois - jj).
                        • Tu affiches la date finale (jj+n) moisEnTouteLettre
                        Mais c'est vrai que l'explication du niveau 1 n'est pas très claire aux premiers abords.
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Anonyme
                          31 août 2012 à 22:26:37

                          d'accord j'essaie d'arranger les explications du niveau 1.
                          sinon pour le timestamp non je ne crois pas car si on demande avant le 1er janvier 1970 ça ne marchera pas ;)

                          EDIT : voilà j'ai un peux arranger le niveau 1 dites-moi ce que vous en pensez ;)
                          • Partager sur Facebook
                          • Partager sur Twitter
                            31 août 2012 à 22:39:39

                            Citation : tib92

                            Ce nombre sera inférieur au nombre de jour maximum que le mois entré peu contenir (si le mois contient 30 jours alors le nombre ne peut pas dépasser 30 par exemple).


                            En clair, je peux rentrer la date du 29 septembre, puis le nombre 30 (selon ta phrase). Mais ça correspond pas à ce que tu attends j'imagine... (c'est déjà le niveau 2).
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Anonyme
                              31 août 2012 à 22:45:20

                              non je ne l'ai pas bien formuler j'édite !

                              EDIT : en fait je m'étais trompé en écrivant l'énoncé merci de me l'avoir fais remarqué ;)
                              • Partager sur Facebook
                              • Partager sur Twitter
                                31 août 2012 à 22:56:45

                                salut :)

                                j'ai fais le niveau 3 avec les annees bissextiles, le plus dur c'etait de mettre le bon modulo au bon endroit lors de l'addition des jours o_O

                                #include <stdio.h>
                                
                                const char *ms[12] = {"janvier","fevrier","mars","avril","mai","juin","juillet","aout", "septembre","octobre","novembre","decembre"};
                                int md[12]={31,28,31,30,31,30, 31,31,30,31,30,31};
                                
                                int anneeBis(int a)
                                {
                                	return (a%4==0&&a%100!=0) || a%400==0;
                                }
                                int nbJM(int m, int a) //nombre de jour par mois
                                {
                                	if(m == 1 && anneeBis(a))
                                		return 29;
                                	else 
                                		return md[m];
                                }
                                
                                int main()
                                {
                                	char s[100];
                                	int jour, an, mois=-1;
                                	int i,j,c; //variables / indices pour les boucles
                                
                                	
                                	scanf("%d%s%d", &jour, s,&an);
                                	for(i=0;i<12;i++)
                                	{
                                		for(j=0; s[j] && s[j] == ms[i][j]; j++) ;
                                			
                                		if(s[j] == ms[i][j])
                                			mois = i;
                                	}
                                	if(mois ==-1 || jour < 0 || jour > nbJM(mois, an))
                                	{
                                		printf("entree invalide\n");
                                		return 0;
                                	}
                                	
                                	
                                	
                                	c=0;
                                	printf("cb de jour dans le futur????\n");
                                	scanf("%d",&c);
                                	
                                	while(c)
                                	{
                                		jour = jour%nbJM(mois,an)+1;
                                		if(jour==1)
                                		{
                                			mois = (mois+1)%12;
                                			if(mois==0)
                                				an++;
                                		}
                                		c--;
                                	}
                                	
                                	printf("%d %s %d\n", jour,ms[mois],an); //affiche resultat
                                	
                                	return 0;
                                }
                                

                                n'hesitez pas a le commenter ou a poser des questions si vous ne le comprenez pas ;) mais j'ai essayer d'etre le plus clair possible, jai mis quelque commentaire pour mieux eclairer :p:magicien:
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  1 septembre 2012 à 12:33:22

                                  Salut :)

                                  <EDIT>Une petite faute dans la phrase ci-dessous :lol: :</EDIT>
                                  Deux petites fautes de français dans l’énoncé :
                                  Pour ce premier niveau, on va faire simple pour que les débutants puissent se familiariser un peu avec la gestion des dates.
                                  En entrée vous allez recevoir une chaîne de caractère sous cette forme :

                                  ----------------------------------------------------------------------
                                  J’ai fait le niveau 3.5 (ouais c’est nouveau, c’est le niveau 4 sans le menu) avec le bonus 1 :
                                  #include <stdio.h>
                                  #include <stdlib.h>
                                  #include <string.h>
                                  #include <limits.h>
                                  #include <stdarg.h>
                                  #include <math.h>
                                  
                                  /* type bool */
                                  typedef char bool;
                                  #define true  1
                                  #define false 0
                                  
                                  /* Une date (contient un jour, un mois, et une année) */
                                  typedef struct Date
                                  {
                                      unsigned day; /* 1 - 28,29,30,31 selon le mois */
                                      unsigned month; /* 0 - 11 */
                                      unsigned year; /* 0 - beaucoup  */
                                  } Date;
                                  
                                  char const * monthsArray[] = {"janvier",
                                                                "fevrier",
                                                                "mars",
                                                                "avril",
                                                                "mai",
                                                                "juin",
                                                                "juillet",
                                                                "aout",
                                                                "septembre",
                                                                "octobre",
                                                                "novembre",
                                                                "decembre"};
                                  
                                  /* Prototypes */
                                  void clearBuffer(void); /* Vide stdin */
                                  
                                  void secureInput(char const* text, char const* format, int count,...);
                                  /* saisie sécurisée */
                                  
                                  unsigned stringToMonth(char const* str); /* Permet d’obtenir le numéro
                                  d’un mois à partir d’une chaîne de caractères */
                                  
                                  bool isLeapYear(unsigned year); /* Renvoi true si l’année est
                                  bissextile, sinon false */
                                  
                                  unsigned nbOfDaysForMonth(unsigned month, unsigned year); /* Renvoi le
                                  nombre de jours du mois « month » de l’année « year » */
                                  
                                  void getDate(char const* text, Date* dt); /* Obtient une date depuis
                                  stdin */
                                  
                                  void dateOffset(Date* dt, int offset); /* Décale une date d’un
                                  « offset » en jour(s) */
                                  
                                  int main(void)
                                  {
                                      Date dt;
                                      int offset;
                                  
                                      printf("Entrez une date.\n");
                                      getDate(">> ", &dt);
                                  
                                      printf("\nEntrez un décalage (en jour(s)).\n");
                                      secureInput(">> ", "%d", 1, &offset);
                                  
                                      dateOffset(&dt, offset);
                                  
                                      printf("\nOn est maintenant le %u %s %u !\n",
                                             dt.day,
                                             monthsArray[dt.month],
                                             dt.year);
                                  
                                      return EXIT_SUCCESS;
                                  }
                                  
                                  void clearBuffer(void)
                                  {
                                      int c;
                                  
                                      do c = getchar();
                                      while (c != '\n' && c != EOF);
                                  }
                                  
                                  void secureInput(char const* text, char const* format, int count, ...)
                                  {
                                      va_list ap;
                                      int ret;
                                  
                                      va_start(ap, count);
                                  
                                      do
                                      {
                                          if(text != NULL)
                                          {
                                              printf("%s", text);
                                              fflush(stdout);
                                          }
                                          ret = vscanf(format, ap);
                                          clearBuffer();
                                  
                                          if(feof(stdin))
                                          {
                                              fprintf(stderr, "\n\n\tEOF\n");
                                              exit(EXIT_FAILURE);
                                          }
                                      }
                                      while(ret != count);
                                  }
                                  
                                  unsigned stringToMonth(char const* str)
                                  {
                                      unsigned month;
                                  
                                      for(month = 0u; month < 12u; ++month)
                                      {
                                          if(strcmp(str, monthsArray[month]) == 0)
                                              return month;
                                      }
                                  
                                      return UINT_MAX;
                                  }
                                  
                                  bool isLeapYear(unsigned year)
                                  {
                                      /* Définition de Wikipédia */
                                      return (year % 4u == 0u && year % 100u != 0u)
                                          || (year % 400u == 0u);
                                  }
                                  
                                  unsigned nbOfDaysForMonth(unsigned month, unsigned year)
                                  {
                                      if(month == 1u) /* 1 = Février */
                                          return isLeapYear(year) ? 29u : 28u;
                                      else if(month <= 6u) /* 6 = Juillet */
                                          return (month+1u) % 2u + 30u;
                                      else
                                          return month % 2u + 30u;
                                  }
                                  
                                  void getDate(char const* text, Date* dt)
                                  {
                                      char buf[20];
                                  
                                      do
                                      {
                                          secureInput(text, "%u %19s %u", 3,
                                                      &dt->day, buf, &dt->year);
                                          dt->month = stringToMonth(buf);
                                      }
                                      while (dt->month == UINT_MAX
                                          || dt->day > nbOfDaysForMonth(dt->month, dt->year));
                                  }
                                  
                                  void dateOffset(Date* dt, int offset)
                                  {
                                      int offsetForNewMonth;
                                  
                                      while(offset != 0)
                                      {
                                          if(offset > 0)
                                              offsetForNewMonth = nbOfDaysForMonth(dt->month, dt->year)
                                                                  - dt->day + 1u;
                                          else
                                              offsetForNewMonth = -dt->day;
                                  
                                          if(abs(offsetForNewMonth) <= abs(offset)) /* change de mois */
                                          {
                                              offset -= offsetForNewMonth;
                                              if(offsetForNewMonth > 0)
                                              {
                                                  ++dt->month;
                                                  if(dt->month >= 12u)
                                                  {
                                                      dt->month = 0u;
                                                      ++dt->year;
                                                  }
                                                  dt->day = 1u;
                                              }
                                              else
                                              {
                                                  --dt->month;
                                                  if(dt->month >= 12u) /* unsigned => -1 = UINT_MAX */
                                                  {
                                                      dt->month = 11u;
                                                      --dt->year;
                                                  }
                                                  dt->day = nbOfDaysForMonth(dt->month, dt->year);
                                              }
                                          }
                                          else
                                          {
                                              dt->day += offset;
                                              offset = 0;
                                          }
                                      }
                                  }
                                  

                                  Pour soustraire un nombre de jour il faut entrer un décalage négatif.

                                  Si vous avez des critiques... J’attends vos critiques.

                                  EDIT: J’ai oublié d’enlever le prototype d’une fonction qui n’existe plus.
                                  EDIT2: Je ne serais pas là cette aprem, je ne verrais vos critiques que ce soir ou demain.
                                  Bonne après-midi et surtout bonne prog' ;)
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Anonyme
                                    1 septembre 2012 à 13:21:59

                                    merci pour vos participations mais là je ne peux pas donner mon avis je le ferais en rentrant :)

                                    EDIT : alors on commence avec KiwiMoar :

                                    déjà int main(void)
                                    ensuite le but étais de lire une chaine puis de parser mais bon c'est pas bien dur de le rajouter
                                    tu pourrais utiliser des unsigned comme fscorpio c'est plus adapté
                                    sinon j'ai eu un peu de mal à comprendre ton code mais ça va :p
                                    (paraze vas-y tu peux lui mettre un coup du compilo paranoïa si tu veux ^^ )

                                    @fscorpio :

                                    merci pour les fautes ;)

                                    je te donnerais mon avis demain car là j'ai plein de truc à faire sinon d'un premier coup d'oeil ça à l'air d'être un bon code ;)
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Anonyme
                                      1 septembre 2012 à 18:21:05

                                      On pourrait rajouter des heures:minutes:secondes.millisecondes ?
                                      Et puis intégrer du coup un nouveau format pour l'ajout de temps, du genre VVVj WWh XXm YY.ZZZs.
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Anonyme
                                        1 septembre 2012 à 18:25:24

                                        oui si tu veux tu peux rajouter des bonus :)
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          1 septembre 2012 à 18:28:08

                                          Citation : Hugooguh

                                          On pourrait rajouter des heures:minutes:secondes.millisecondes ?


                                          Après, pourquoi s'arrêter aux millisecondes... Pourquoi ne pas aller carrément jusqu'aux yoctosecondes ?
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                          Anonyme
                                            1 septembre 2012 à 23:53:21

                                            @fscorpio : C99 a un header stdbool.h
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                            Anonyme
                                              2 septembre 2012 à 14:12:29

                                              je viens de lire ton code fscorpio, et je trouve ton code très bien, très clair, très explicite, conclusion : bravo ! :)
                                              n'hésitez à commentez les codes ou à poster les votres ;)
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                2 septembre 2012 à 14:42:12

                                                Quelques remarques pour @fscorpio donc. :p
                                                • Tes identificateurs manquent un peu de concordance ; je parle surtout de tes identificateurs de fonction. Habituellement, on utilise la forme [verbe+substantif], ou, du moins, on se tient à quelque chose. Là, il y a un mélange.
                                                • Tu déclares ton type booléen comme étant de type char. Déjà, ce que tu veux gagner en place, tu le perdras en conversions excessives et inutiles, contrairement à l'utilisation d'un simple entier. Tu pourrais utiliser une énumération qui serait déjà plus naturelle (mais franchement, ce n'est pas nécessaire de définir une nouvelle abstraction que tu n'utilises pas du tout !).
                                                • C'est une bonne pratique de suffixer tes constantes numériques, mais, habituellement, on préfère éviter les minuscules, notamment pour les suffixes « l » qui se confondent avec des « 1 », ce qui nuit sensiblement à la lisibilité.
                                                • Honnêtement, je ne pense pas que l'utilisation des types non signés est nécessaire ici. Le C, est, par définition, un langage au typage pas toujours prononcé, et tu essayes de le forcer, et, à défaut d'y parvenir, tu vas te retrouver avec pas mal de conversions louches. Pour des programmes aussi simples (ça reste de simples dates !), préfère utiliser un type signé, généralement natif pour le processeur. Réserve les non signés à des cas plus spécifiques, où tu veux mettre en évidence des comportements de dépassement contrôlé ou de bornes limitées, par exemple. En l'état, vouloir mettre des non signés sur tout ce qui bouge ne me semble pas être une bonne idée.
                                                • L'indentation de ta fonction clearBuffer est assez étrange. De plus, la plupart des normes de style conseillent d'utiliser des accolades autour de do ... while (même dans le Kernel !), exception du genre. Au moins, si tu pouvais indenter correctement ton instruction, ça serait déjà mieux.
                                                • C'est quoi ce feof(stdin) ? Tu cherches à faire quoi exactement avec cette instruction ?
                                                • Il est étrange ton argument count, dans la fonction secureInput. Il serait peut-être préférable de faire ça avec un comptage du nombre d'arguments (liste terminée par un pointeur nul) ; elle ne me semble pas être d'une utilisation très naturelle.
                                                • Les constantes en dur, c'est toujours pas très joli, même auréolées d'un joli commentaire (pas très uniforme en passant) qui est censé expliquer l'interface et pas l'implémentation dans des fonctions aussi simples.
                                                • C'est sympathique tes calculs du nombre de jours, mais, honnêtement, une lookup table devrait davantage faire l'affaire. À voir pour le cas des années bissextiles, cependant.
                                                • Quant à ta fonction dateOffset, elle très difficilement lisible je trouve. Franchement, je pense que le cas nécessiterait un découpage en deux fonctions (une d'addition d'offset et une de soustraction). Même si ce que tu essayes de faire est totalement louable, ou voit qu'il y a des redondances de conditions et d'instructions qui sont embêtantes. Ça simplifierait sans nul doute cette fonction, que je trouve personnellement trop chargée.
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Staff désormais retraité.
                                                  2 septembre 2012 à 15:05:16

                                                  Citation : lucas

                                                  Honnêtement, je ne pense pas que l'utilisation des types non signés est nécessaire ici.

                                                  Ca peut etre pratique car il est sur que le nombre nest pas negatif.


                                                  Il pourra faire directement un truc comme :
                                                  if (month >= 12)
                                                    return printf("erreur le mois nest pas bon etc.\n");
                                                  
                                                  Il n'a pas besoin de mettre en plus le month < 0 ||.

                                                  Et moi au contraire les "u" partout jtrouve ca useless.

                                                  Et ça coûte quoi de mettre le main en bas pour un si petit programme?
                                                  Quel est intérêt de se mettre la contrainte de devoir modifier chaque prototype deux fois?
                                                  (jsuis trop feignant surement)
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    2 septembre 2012 à 15:08:25

                                                    Citation

                                                    Quel est intérêt de se mettre la contrainte de devoir modifier chaque prototype deux fois?


                                                    Les warnings, les warnings... :lol:
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      2 septembre 2012 à 15:10:16

                                                      quel warning? y'a pas de warning
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        2 septembre 2012 à 15:22:51

                                                        Citation : Mr21

                                                        Citation : lucas

                                                        Honnêtement, je ne pense pas que l'utilisation des types non signés est nécessaire ici.

                                                        Ca peut etre pratique car il est sur que le nombre nest pas negatif.


                                                        Il pourra faire directement un truc comme :

                                                        if (month >= 12)
                                                          return printf("erreur le mois nest pas bon etc.\n");
                                                        

                                                        Il n'a pas besoin de mettre en plus le month < 0 ||.


                                                        Pour autant, je ne suis pas forcément convaincu, pas forcément dans un tel programme, mais d'une manière générale, je ne suis pas certain que ce soit une habitude à prendre de manière irrémédiable. Ce genre de vérifications de bornes, dans la pratique, ça se fait généralement par des fonctions/macros spécialisées, et c'est juste une chance, qu'ici, la borne inférieure soit à 0 (elle serait à 1, ça reviendrait strictement au même d'utiliser un signé ou un non signé). Et franchement, cet argument ne tient pas vraiment la route, tu ne changes pas de typage juste pour une condition en moins dans un tel programme, qui subit des ralentissements inhérents à des problèmes bien plus graves !

                                                        En fait, jusqu'à quelques semaines, j'étais plutôt de ton point de vue (mettre des non signés sur tout ce qui bouge), mais je change petit à petit d'avis, en lisant des témoignages, notamment. Le problème, surtout, c'est que la plupart des fonctions que tu utilises couramment manipulent des signés, et que, si tu commences à utiliser des non signés dans le dos de ta bibliothèque, le mixage des deux types dans les comparaisons p.ex. ne fera pas bon ménage. En revanche, comme je l'ai dit, quand tu dois mettre en évidence des comportements spécifiques (décalages de bits vers la droite avec de la portabilité absolue, overflows contrôlés p.ex.). Tu trouveras de nombreux papiers sur le sujet qui disent à peu près la même chose (tu en trouveras d'autres qui disent le contraire, mais c'est ça la programmation : un débat perpétuel...).

                                                        Après tout, les langages dits « modernes » comme Java ou C# ne fournissent pas de non signés à proprement dit (il y a des exceptions comme Byte, mais ce sont des cas particuliers), et les programmeurs s'en sortent très bien !

                                                        Citation : Mr21

                                                        Et moi au contraire les "u" partout jtrouve ca useless.


                                                        C'est du typage de constante. Pour le coup, c'est surtout pour la sémantique, mais il y a des cas où c'est nécessaire. Après, il faut peser le pour et le contre. Si ça alourdit vraiment les expressions, ce n'est pas forcément une bonne chose. Mais, de manière générale, quand on « débute », je trouve ça intéressant, puisque cela force l'étude des types en eux-mêmes.

                                                        Citation : Mr21

                                                        quel warning? y'a pas de warning


                                                        Le genre d'avertissements faux positifs que tu actives avec des options de fou, qui force des transtypages là où il y en a pas besoin. Personnellement, je suis plutôt de ton avis sur ce point (des prototypes pour un si petit programme en un seul fichier, mouais).
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter
                                                        Staff désormais retraité.
                                                          2 septembre 2012 à 16:01:20

                                                          Citation : lucas

                                                          Le genre d'avertissements faux positifs que tu actives avec des options de fou

                                                          ouai bah si c'est pas dans -Wall -Wextra -pedantic jcrois que... osef :D
                                                          m'enfin.

                                                          Citation

                                                          (elle serait à 1, ça reviendrait strictement au même d'utiliser un signé ou un non signé)

                                                          clairement, mais il se trouve que beaucoup de cas c'est comme ca, ca commence a 0.
                                                          Mais jvois pas pourquoi ca ferait ralentir quoi que ce soit.
                                                          • Partager sur Facebook
                                                          • Partager sur Twitter
                                                            2 septembre 2012 à 16:32:32

                                                            Citation : Mr21

                                                            Citation

                                                            (elle serait à 1, ça reviendrait strictement au même d'utiliser un signé ou un non signé)

                                                            clairement, mais il se trouve que beaucoup de cas c'est comme ca, ca commence a 0.
                                                            Mais jvois pas pourquoi ca ferait ralentir quoi que ce soit.


                                                            En fait, c'est pas forcément une question de performances, mais, puisque tu soulèves ce point, ça peut faire une liaison avec un autre domaine. En effet, les entiers signés sont sujets à plus de comportements indéterminés, et le compilateur peut en profiter pour éviter des vérifications. Par exemple, si tu veux attraper des problèmes de dépassements d'entier, et que tu fais quelque chose comme :

                                                            int
                                                            f(int a)
                                                            {
                                                                 return a + 1 < a ? OVERFLOW_Y : OVERFLOW_N;
                                                            }
                                                            

                                                            Force est de constater qu'il y a deux possibilités :
                                                            • si (a != INT_MAX), alors (a+1 > a), et donc la fonction retournera OVERFLOW_N ;
                                                            • si (a == INT_MAX), alors (a+1) est un dépassement d'entier signé, ce qui est un comportement indéterminé en C. À partir de là, le code n'est pas censé suivre de logique particulière, le compilateur peut donc faire ce qui l'arrange. En l'occurrence, il peut retourner OVERFLOW_N pour inliner la fonction et enlever une comparaison de l'exécutable.

                                                            Avec des entiers non signés, étant donné le comportement de wrap around de ces derniers lors d'un dépassement de capacité, le compilateur est obligé de vérifier les deux cas. Dans la pratique, tu as des flags de contrôle à la compilation, mais c'est spécifique à certains compilateurs et il ne faut pas en faire une généralité.

                                                            Ainsi, tu as plusieurs situations comme celle-ci où le compilateur peut faire des optimisations agressives en cas de comportement indéterminé. C'est en partie pour ça qu'on préfère souvent utiliser le type int.
                                                            • Partager sur Facebook
                                                            • Partager sur Twitter
                                                            Staff désormais retraité.
                                                              2 septembre 2012 à 16:35:41

                                                              Citation : Lucas-84

                                                              Tu déclares ton type booléen comme étant de type char. Déjà, ce que tu veux gagner en place, tu le perdras en conversions excessives et inutiles, contrairement à l'utilisation d'un simple entier. Tu pourrais utiliser une énumération qui serait déjà plus naturelle (mais franchement, ce n'est pas nécessaire de définir une nouvelle abstraction que tu n'utilises pas du tout !).

                                                              J’utilise mon type bool pour le type de retour de la fonction isLeapYear, pour plus de lisibilité.
                                                              Je l’ai déclaré avec une énumération maintenant.

                                                              Citation : Lucas-84

                                                              - C'est une bonne pratique de suffixer tes constantes numériques, mais, habituellement, on préfère éviter les minuscules, notamment pour les suffixes « l » qui se confondent avec des « 1 », ce qui nuit sensiblement à la lisibilité.
                                                              - Honnêtement, je ne pense pas que l'utilisation des types non signés est nécessaire ici. Le C, est, par définition, un langage au typage pas toujours prononcé, et tu essayes de le forcer, et, à défaut d'y parvenir, tu vas te retrouver avec pas mal de conversions louches. Pour des programmes aussi simples (ça reste de simples dates !), préfère utiliser un type signé, généralement natif pour le processeur. Réserve les non signés à des cas plus spécifiques, où tu veux mettre en évidence des comportements de dépassement contrôlé ou de bornes limitées, par exemple. En l'état, vouloir mettre des non signés sur tout ce qui bouge ne me semble pas être une bonne idée.

                                                              OK, j’ai mis des unsigned car c’est plus logique, un jour ou un mois est un entier naturel (pas relatif).
                                                              J’ai mis des int à la place.

                                                              Citation : Lucas-84

                                                              L'indentation de ta fonction clearBuffer est assez étrange. De plus, la plupart des normes de style conseillent d'utiliser des accolades autour de do ... while (même dans le Kernel !), exception du genre. Au moins, si tu pouvais indenter correctement ton instruction, ça serait déjà mieux.

                                                              Dommage, je trouvais ça très lisible.

                                                              Citation : Lucas-84

                                                              C'est quoi ce feof(stdin) ? Tu cherches à faire quoi exactement avec cette instruction ?

                                                              Je cherchai à sécurisée ma saisie par rapport à EOF.

                                                              Citation : Lucas-84

                                                              Il est étrange ton argument count, dans la fonction secureInput. Il serait peut-être préférable de faire ça avec un comptage du nombre d'arguments (liste terminée par un pointeur nul) ; elle ne me semble pas être d'une utilisation très naturelle.

                                                              Si tu le dit, moi je ne vois pas trop de différence mais je n’ai pas non plus autant d’expérience que toi.

                                                              Citation : Lucas-84

                                                              Les constantes en dur, c'est toujours pas très joli, même auréolées d'un joli commentaire (pas très uniforme en passant) qui est censé expliquer l'interface et pas l'implémentation dans des fonctions aussi simples.

                                                              Je l’avais vu en me relisant un peu avant que tu ne postes (suite au message de tib92). ;)

                                                              Citation : Lucas-84

                                                              C'est sympathique tes calculs du nombre de jours, mais, honnêtement, une lookup table devrait davantage faire l'affaire. À voir pour le cas des années bissextiles, cependant.

                                                              Les mois se suivent de manière logique, je trouve ça bête de ne pas en profiter.

                                                              Citation : Lucas-84

                                                              Quant à ta fonction dateOffset, elle très difficilement lisible je trouve. Franchement, je pense que le cas nécessiterait un découpage en deux fonctions (une d'addition d'offset et une de soustraction). Même si ce que tu essayes de faire est totalement louable, ou voit qu'il y a des redondances de conditions et d'instructions qui sont embêtantes. Ça simplifierait sans nul doute cette fonction, que je trouve personnellement trop chargée.

                                                              Je l’avais fait en deux fonctions au début, mais j’ai fusionné ces fonctions à cause des redondances.

                                                              Citation : Mr21

                                                              Et ça coûte quoi de mettre le main en bas pour un si petit programme?
                                                              Quel est intérêt de se mettre la contrainte de devoir modifier chaque prototype deux fois?
                                                              (jsuis trop feignant surement)

                                                              Je met des prototypes pour ne pas avoir à me soucier de l’ordre des fonctions.
                                                              Et ça me parait plus logique de mettre le main en premier.

                                                              Merci.
                                                              ----------------------------------------------------------------------
                                                              J’ai essayer de modifier mon code en prenant en compte tes critiques.
                                                              #include <stdio.h>
                                                              #include <stdlib.h>
                                                              #include <stdarg.h>
                                                              #include <ctype.h>
                                                              
                                                              /* type bool */
                                                              typedef enum{false, true} bool;
                                                              
                                                              /* X-macro */
                                                              #define X_MONTH \
                                                                          X(JANVIER), \
                                                                          X(FEVRIER), \
                                                                          X(MARS), \
                                                                          X(AVRIL), \
                                                                          X(MAI), \
                                                                          X(JUIN), \
                                                                          X(JUILLET), \
                                                                          X(AOUT), \
                                                                          X(SEPTEMBRE), \
                                                                          X(OCTOBRE), \
                                                                          X(NOVEMBRE), \
                                                                          X(DECEMBRE)
                                                              
                                                              /* Énumération pour les mois */
                                                              #define X(month) month
                                                              typedef enum Month{X_MONTH, NB_MONTH} Month;
                                                              #undef X
                                                              
                                                              /* Une date (contient un jour, un mois, et une année) */
                                                              typedef struct Date
                                                              {
                                                                  int day; /* 1 - 28,29,30,31 selon le mois */
                                                                  int year; /* 0 - beaucoup  */
                                                                  Month month; /* 0 - 11 */
                                                              } Date;
                                                              
                                                              #define X(month) #month
                                                              char const * const monthsArray[] = {X_MONTH};
                                                              #undef X
                                                              
                                                              /* Prototypes */
                                                              void clearBuffer(void); /* Vide stdin */
                                                              
                                                              void secureInput(char const* text, char const* format, ...);
                                                              /* saisie sécurisée, le dernier argument doit être NULL */
                                                              
                                                              Month stringToMonth(char const* str); /* Permet d’obtenir le numéro
                                                              d’un mois à partir d’une chaîne de caractères */
                                                              
                                                              bool isLeapYear(int year); /* Renvoi true si l’année est
                                                              bissextile, sinon false */
                                                              
                                                              int nbOfDaysForMonth(Month month, int year); /* Renvoi le
                                                              nombre de jours du mois « month » de l’année « year » */
                                                              
                                                              void getDate(char const* text, Date* dt); /* Obtient une date depuis
                                                              stdin */
                                                              
                                                              void addDateOffset(Date* dt, int offset); /* Ajoute un décalage à une
                                                              date */
                                                              
                                                              void subtractDateOffset(Date* dt, int offset); /* Retire un décalage à
                                                              une date */
                                                              
                                                              bool equalText(char const* str1, char const* str2); /* Indique si deux
                                                              chaînes de caractères sont egaux, en ignorant la casse */
                                                              
                                                              int main(void)
                                                              {
                                                                  Date dt;
                                                                  int offset;
                                                              
                                                                  printf("Entrez une date.\n");
                                                                  getDate(">> ", &dt);
                                                              
                                                                  printf("\nEntrez un décalage (en jour(s)).\n");
                                                                  secureInput(">> ", "%d", &offset, NULL);
                                                              
                                                                  addDateOffset(&dt, offset);
                                                              
                                                                  printf("\nOn est maintenant le %d %s %d !\n",
                                                                         dt.day,
                                                                         monthsArray[dt.month],
                                                                         dt.year);
                                                              
                                                                  return EXIT_SUCCESS;
                                                              }
                                                              
                                                              void clearBuffer(void)
                                                              {
                                                                  int c;
                                                              
                                                                  do
                                                                  {
                                                                      c = getchar();
                                                                  }
                                                                  while (c != '\n' && c != EOF);
                                                              }
                                                              
                                                              void secureInput(char const* text, char const* format, ...)
                                                              {
                                                                  va_list ap;
                                                                  int ret, count;
                                                              
                                                                  va_start(ap, format);
                                                                  for(count = 0; va_arg(ap, void*) != NULL; ++count);
                                                                  va_end(ap);
                                                              
                                                                  do
                                                                  {
                                                                      if(text != NULL)
                                                                      {
                                                                          printf("%s", text);
                                                                          fflush(stdout);
                                                                      }
                                                                      va_start(ap, format);
                                                                      ret = vscanf(format, ap);
                                                                      va_end(ap);
                                                                      clearBuffer();
                                                              
                                                                      if(feof(stdin))
                                                                      {
                                                                          fprintf(stderr, "\n\n\tEOF\n");
                                                                          exit(EXIT_FAILURE);
                                                                      }
                                                                  }
                                                                  while(ret != count);
                                                              }
                                                              
                                                              Month stringToMonth(char const* str)
                                                              {
                                                                  Month month;
                                                              
                                                                  for(month = JANVIER; month <= DECEMBRE; ++month)
                                                                  {
                                                                      if(equalText(str, monthsArray[month]))
                                                                          return month;
                                                                  }
                                                              
                                                                  return NB_MONTH;
                                                              }
                                                              
                                                              bool isLeapYear(int year)
                                                              {
                                                                  /* Définition de Wikipédia */
                                                                  return (year % 4 == 0 && year % 100 != 0)
                                                                      || (year % 400 == 0);
                                                              }
                                                              
                                                              int nbOfDaysForMonth(Month month, int year)
                                                              {
                                                                  if(month == FEVRIER)
                                                                      return isLeapYear(year) ? 29 : 28;
                                                                  else if(month <= JUILLET)
                                                                      return (month+1) % 2 + 30;
                                                                  else
                                                                      return month % 2 + 30;
                                                              }
                                                              
                                                              void getDate(char const* text, Date* dt)
                                                              {
                                                                  char buf[20];
                                                              
                                                                  do
                                                                  {
                                                                      secureInput(text, "%d %19s %d",
                                                                                  &dt->day, buf, &dt->year, NULL);
                                                                      dt->month = stringToMonth(buf);
                                                                  }
                                                                  while (dt->month == NB_MONTH
                                                                      || dt->year < 0
                                                                      || dt->day < 0
                                                                      || dt->day > nbOfDaysForMonth(dt->month, dt->year));
                                                              }
                                                              
                                                              void addDateOffset(Date* dt, int offset)
                                                              {
                                                                  int offsetForNewMonth;
                                                              
                                                                  if(offset < 0)
                                                                  {
                                                                      subtractDateOffset(dt, -offset);
                                                                      return;
                                                                  }
                                                              
                                                                  while(offset > 0)
                                                                  {
                                                                      offsetForNewMonth = nbOfDaysForMonth(dt->month, dt->year)
                                                                                          - dt->day + 1;
                                                              
                                                                      if(offsetForNewMonth <= offset) /* change de mois */
                                                                      {
                                                                          offset -= offsetForNewMonth;
                                                                          ++dt->month;
                                                                          if(dt->month > DECEMBRE)
                                                                          {
                                                                              dt->month = JANVIER;
                                                                              ++dt->year;
                                                                          }
                                                                          dt->day = 1;
                                                                      }
                                                                      else
                                                                      {
                                                                          dt->day += offset;
                                                                          offset = 0;
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              void subtractDateOffset(Date* dt, int offset)
                                                              {
                                                                  int offsetForNewMonth;
                                                              
                                                                  if(offset < 0)
                                                                  {
                                                                      subtractDateOffset(dt, -offset);
                                                                      return;
                                                                  }
                                                                  else
                                                                      offset = -offset;
                                                              
                                                                  while(offset < 0)
                                                                  {
                                                                      offsetForNewMonth = -dt->day;
                                                              
                                                                      if(offsetForNewMonth >= offset) /* change de mois */
                                                                      {
                                                                          offset -= offsetForNewMonth;
                                                                          --dt->month;
                                                                          /* unsigned, -1 = UINT_MAX */
                                                                          if(dt->month > DECEMBRE)
                                                                          {
                                                                              dt->month = DECEMBRE;
                                                                              --dt->year;
                                                                          }
                                                                          dt->day = nbOfDaysForMonth(dt->month, dt->year);
                                                                      }
                                                                      else
                                                                      {
                                                                          dt->day += offset;
                                                                          offset = 0;
                                                                      }
                                                                  }
                                                              }
                                                              
                                                              bool equalText(char const* str1, char const* str2)
                                                              {
                                                                  for(; *str1 != '\0' && *str2 != '\0'; ++str1, ++str2)
                                                                  {
                                                                      if(toupper(*str1) != toupper(*str2))
                                                                          return false;
                                                                  }
                                                                  return (*str1 == '\0' && *str2 == '\0');
                                                              }
                                                              

                                                              (La X-macro est là surtout pour m’entraîner à les utiliser, et parce que je déteste les répétitions.)

                                                              EDIT: Deux %u qui sont devenu des %d.
                                                              • Partager sur Facebook
                                                              • Partager sur Twitter

                                                              zDate

                                                              × 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.
                                                              • Editeur
                                                              • Markdown