Question

J'ai couru dans un code et je me demandais ce que le développeur d'origine était jusqu'à. Ci-dessous un programme simplifié utilisant ce modèle:

      #include <stdio.h>

      int main()  {     

      char title[80] = "mytitle";      
      char title2[80] = "mayataiatale";      
      char mystring[80]; 

      /* hugh ? */
      sscanf(title,"%[^a]",mystring);
      printf("%s\n",mystring); /* Output is "mytitle" */


      /* hugh ? */
      sscanf(title2,"%[^a]",mystring); /* Output is "m" */
      printf("%s\n",mystring);


      return 0;  
  }

Le scanf a des informations pertinentes, mais je ne parviens pas En le lisant. Quel est le but d'utiliser ce type de notation? Qu'est-ce qu'il tente d'accomplir?

Était-ce utile?

La solution

La raison principale pour les classes de caractères est ainsi que la notation de l'% arrête au premier caractère d'espace blanc, même si vous spécifiez les longueurs de champ, et que vous voulez bien souvent ne pas à. Dans ce cas, la notation de classe de caractères peut être extrêmement utile.

Considérez ce code pour lire une ligne de 10 caractères au maximum, en écartant tout excès, mais les espaces garder:

#include <ctype.h>
#include <stdio.h>

int main(void)
{
    char buffer[10+1] = "";
    int rc;
    while ((rc = scanf("%10[^\n]%*[^\n]", buffer)) >= 0)
    {
            int c = getchar();
            printf("rc = %d\n", rc);
            if (rc >= 0)
                    printf("buffer = <<%s>>\n", buffer);
            buffer[0] = '\0';
    }
    printf("rc = %d\n", rc);
    return(0);
}

était en fait un exemple de code pour une discussion sur comp.lang.c.moderated (vers Juin 2004) lié à getline() variantes.


Au moins une certaine confusion règne. Le premier spécificateur de format, %10[^\n], lit jusqu'à 10 caractères de non-retour à la ligne et ils sont affectés au tampon, et aussi d'une valeur nulle de suivi. Le second spécificateur de format, %*[^\n] contient le caractère de suppression d'affectation (*) et lit zéro ou plusieurs autres caractères non-retour à la ligne de l'entrée. Lorsque la fonction scanf() est terminée, l'entrée est dirigée vers le prochain saut de ligne. Le corps de la boucle lit et imprime ce caractère, de sorte que lors du redémarrage de la boucle, l'entrée est à la recherche au début de la ligne suivante. Le processus se répète alors. Si la ligne est plus courte de 10 caractères, alors ces caractères sont copiés dans le tampon et le format «zéro ou plusieurs non-retour à la ligne de procédés zéro non-retour à la ligne.

Autres conseils

Les constructions comme %[a] et %[^a] existent pour que scanf() peuvent être utilisés comme une sorte d'analyseur lexical. Ce sont un peu comme %s, mais au lieu de recueillir une période d'autant de caractères « filandreux » que possible, ils recueillent juste une période de caractères tel que décrit par la classe de caractères. Il pourrait y avoir des cas où %[a-zA-Z0-9] d'écriture peut être une solution, mais je ne suis pas sûr que je vois un cas d'utilisation convaincante pour les classes complémentaires avec scanf().

à mon humble avis, scanf() est tout simplement pas le bon outil pour ce travail. Chaque fois que je l'ai mis à utiliser l'une de ses fonctions les plus puissantes, j'ai fini finalement déchirer dehors et mettre en œuvre la capacité d'une manière différente. Dans certains cas, cela signifiait en utilisant lex d'écrire un véritable analyseur lexical, mais en faisant généralement ligne à la fois d'E / S et le casser grossièrement en jetons avec strtok() avant de faire la conversion de la valeur était suffisante.

Modifier j'ai fini à scanf() généralement déchirais parce que lorsqu'ils sont confrontés à des utilisateurs en insistant sur la fourniture d'une entrée incorrecte, il est tout simplement pas bon à aider le programme donne de bons commentaires sur le problème, et ayant un assembleur print "erreur, fin." comme message d'erreur unique n'a pas été utile d'aller plus bien avec mon utilisateur. (Me, dans ce cas.)

Il est comme les jeux de caractères à partir d'expressions régulières; [0-9] correspond à une chaîne de chiffres, [^aeiou] correspond à tout ce qui n'est pas une voyelle minuscule, etc.

Il y a toutes sortes d'utilisations, comme tirant des chiffres, des identifiants, des morceaux de blancs, etc.

Vous pouvez lire à ce sujet dans le ISO / norme IEC9899 disponible en ligne.

Voici un paragraphe que je cite le document au sujet [ (Page 286):

  

correspond à une séquence non vide de caractères à partir d'un ensemble d'attendre   caractères.

     

Le spécificateur de conversion comprend tous les caractères suivants dans la   chaîne de format, jusqu'à et y compris le support fermante (]). le   caractères entre les consoles (la liste de scrutation) composent le scanset,   à moins que le caractère après le crochet gauche est un circonflexe (^), en   auquel cas le scanset contient tous les caractères qui ne figurent pas dans   la Scanlist entre le circonflexe et le support droit. Si la   spécificateur de conversion commence par [] ou [^], le support droit   le caractère est dans la liste de scrutation et la prochaine tranche droite suivante   caractère est le crochet droit correspondant qui met fin à la spécification;   sinon, le premier suivant le caractère de support droit est celui qui   la spécification se termine. Si un - caractère est dans la liste de scrutation et n'est pas   le premier, ni le second où le premier caractère est un ^, ni la   dernier caractère, le comportement est défini par l'implémentation.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top