Forum Programmation.c saisie de chaine et correction d'erreur autonome

Posté par  .
Étiquettes : aucune
0
4
jan.
2007
Bonjour,

Je travaille sur un "bout" de code pour faire une saisie long int et gérer l'erreur de frappe (comme une lettre ou deux ou trois dans la saisie).

pour ça j'ai écrit un petit bout de code TESTEUR (compilable)


1ère idée Envoyer l'utilisateur se faire voir (un peu barbare) ;)

2ème idée un peut plus interessante vérifier que tous les caractères de la chaine sont des chiffres

Ca marche mais il est impossible de traiter l'erreur.

3éme idée et c'est là que je vais avoir besoin de vos conseils/idées

utiliser pour convertir long int = chaine:

P.saisie=stroul(&buffer, NULL, 10)

ceci fonctionne mais ne selectionne que les X chiffres présents avant le caractère génant
par exemple :

si buffer = 1234d555
p.saisie = 1234
et non 1234555 <
ce que je veux faire comme correction automatique justement pour éviter les utilisateurs porteurs de moufles


j'ai fouiller le fichier sting.h pour trouver une fonction capable de supprimer un caractere dans un char buffer[X]; mais je n'ai rien trouvé de tout ça...

Je pense donc qu'il faut créer une fonction
du style
for(i=0;i<strlen(buffer);i++)
{
switch(buffer[i])
{
case '0' :
strcat(buffer2[i],buffer[i]);
break ;
// .... etc ... pour les 10 chiffres
default : // ne rien faire
break;
}
}

en utilisant la fonction strcat.
puis
P.saisie=stroul(&buffer2, NULL, 10)

est ce une bonne méthode ?
y'a t'il plus simple ?
  • # str what ?

    Posté par  . Évalué à 2.

    Salut, bonne année la santé tout ça ...

    N'est-ce pas strtoul que tu veux utiliser ?
    Dans ce cas là (juste pour chipoter), tu veux une saisie d'un
    unsigned long int

    Quand tu dis que la méthode 2 ne te permet pas de traiter l'erreur, tu veux dire gérer errno ?
    Si tu vérifies que tous les caractères sont des chiffres et que tu ne dépasses pas ULONG_MAX (auquel cas errno serait positionné à ERANGE par strtoul), qu'est-ce qui t'empêche de faire ça à la main ?

    unsigned long resultat=0
    unsigned long limite=0
    Tant que parcours de la chaine
    Si le caractère est compris entre '0' et '9'alors
    result *= 10
    result += valeur portée par le caractère testé
    finsi
    si result < limite alors
    depassement ERANGE et tout le toutim puis on sort
    sinon
    limite = result
    finsi
    fin tant que
  • # Pas beaucoup plus simple...

    Posté par  . Évalué à 5.

    Si j'ai bien compris, tu veux tolérer la présence de caractères non numériques dans la chaîne, en les effaçant avant de passe à strtoul. Ok, pourquoi pas. Comme tu veux traiter un nombre entier positif ou nul, c'est assez simple (pour les flottants, je te dis pas ;) ).
      Premier truc, pour ta boucle de copie, la norme C garantit que '1' == '0' + 1, '2' == '0' + 2... (cf. 5.2.1p3 du n1124 :
      In both the source and execution basic character sets, the value of each character after 0 in the above list of decimal digits shall be one greater than the value of the previous.
      ). Donc tu n'as pas besoin de switch, un if (c >= '0' && c <= '9') est suffisant. Et, encore mieux, isdigit fourni par l'en-tête ctype.h.
        Deuxième truc : for(i=0;i<strlen(buffer);i++) Il y a de fortes chances que strlen soit appelée à chaque itération, à moins que le compilo arrive à se prouver que tu ne modifies pas le contenu de buffer à l'intérieur de ta boucle (ce qui n'est pas gagné). Il est mieux de faire :
        size_t  len = strlen(buffer);
        for (int i = 0; i < len; i++)
        {
                /* ... */
        }
        Enfin, pour strtoul, j'ai un doute en voyant tes bouts de code. Le premier paramètre est une chaînes de caractères, donc un char*. Si buffer2 est de ce type, ou un tableau défini par quelque chose comme char buffer2[N], alors le & est une erreur :
        #include <stdlib.h>
        char tab[50] = "a";
        unsigned long i = strtoul(tab, NULL, 10);   /* pas de '&' */ 
        • [^] # Re: Pas beaucoup plus simple...

          Posté par  . Évalué à 1.

          ok j'ai compris

          je vous remercie

          pendant ce temps j'ai aussi vu sur un autre forum une solution utilisant une fonction simple également :

          void SupprimeNonChiffre2(char * const szDest, char const * const sczSrc)
          { size_t i,j;
          for(i=0,j=0 ; sczSrc[i] != '\0' ; i++ )
          {
          char c = sczSrc[i];
          int ic = (int)(unsigned char)c; /* isdigit() réclame un int */

          if(isdigit(ic))
          { szDest[j] = c; j++; }
          } szDest[j] = '\0'; }

          je vous remercie j'ai compris les deux méthodeje vais donc m'en sortir maintenant.



          Merci
          • [^] # Re: Pas beaucoup plus simple...

            Posté par  . Évalué à 2.

            bien, mais a propos de :
            } szDest[j] = '\0'; }
            je ne vois pas pourquoi tu place ton zero terminateur a chaque iteration, et en plus tu le place même quand c'est pas un digit.
            alors qu'il suffit de la placer apres ton for()

            sinon, ok.
            moi perso, j'aime pas ecrire '\0', j'utilise NULL, ou carrement 0, mais ca c'est une question de gout je pense.
            • [^] # Re: Pas beaucoup plus simple...

              Posté par  . Évalué à 2.

              oups! pardons, j'avais mal compté le nombre d'accolades...
              (en fait j'avais pas vu que l'accolade fermante n'etait pas celle du for mais celle de la definition de fonction.)

              désolé.
            • [^] # Re: Pas beaucoup plus simple...

              Posté par  . Évalué à 2.

              moi perso, j'aime pas ecrire '\0', j'utilise NULL, ou carrement 0, mais ca c'est une question de gout je pense.
              Pour '\0' et 0, c'est en effet histoire de goût. Pour NULL, c'est une erreur, car c'est une constante de type pointeur.

              La macro NULL peut en effet être définie par 0, auquel cas tu n'as pas de problème, mais aussi par (void *) 0, auquel cas tu fais alors une conversion d'une valeur de type pointeur en un type entier, ce qui est implementation-defined. Peu dangereux en pratique, mais autant utiliser les bons types dès le début.
          • [^] # Re: Pas beaucoup plus simple...

            Posté par  . Évalué à 1.

            isdigit réclame en effet un int, ce qui m'a un peu surpris.
            J'ai regardé la macro (qui fait le cast en unsigned char) et le tableau _ctype_ associé (bon c'est sur du OpenBSD, mais j'ai pas de Linux là sous la main). J'ai fait le test suivant:

            isdigit(-250) : La réponse est positive.

            Comme quoi le test d'un int avec ( >= '0' && <= '9') est quand même différent de isdigit().
            • [^] # Re: Pas beaucoup plus simple...

              Posté par  . Évalué à 2.

              isdigit(-250) : La réponse est positive.

              Dixit 7.4p1 :
              The header <ctype.h> declares several functions useful for classifying and mapping characters.168) In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.

              Donc:
              - Si EOF ne vaut pas -250 sur ton implémentation, alors tu viens de tester un comportement indéfini.
              - Si EOF vaut -250, alors ton implémentation est buggée.

              Je plaide pour la première possibilité (J'ai du mal à croire que la libc d'OpenBSD puisse être aussi buggée pour renvoyer vrai pour EOF) (et j'ai aussi du mal à croire qu'EOF puisse valoir -250, c'est plus probablement -1).

      Suivre le flux des commentaires

      Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.