Frage

Ich habe in einige Code ausführen und frage mich, was der ursprüngliche Entwickler vorhatte. Im Folgenden ist ein vereinfachtes Programm dieses Muster mit:

      #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;  
  }

Die Manpage Scanf rel="nofollow hat relevante Informationen, aber ich habe Probleme es lesen. Was ist der Zweck dieser Art von Notation zu verwenden? Was versucht, es zu erreichen?

War es hilfreich?

Lösung

Der Hauptgrund für die Charakterklassen ist so, dass die% s-Notation in den ersten Raumzeichen hält, auch wenn Sie Feldlängen angeben, und Sie ziemlich oft wollen es nicht. In diesem Fall kann die Zeichenklasse Notation extrem hilfreich sein.

Mit diesem Code Betrachten wir eine Reihe von bis zu 10 Zeichen zu lesen, überschüssige verwerfen, aber halten Räume:

#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);
}

Dies war tatsächlich Beispielcode für eine Diskussion über comp.lang.c.moderated (circa Juni 2004) im Zusammenhang Varianten getline().


Wenigstens einige Verwirrung herrscht. Die ersten Format-Spezifizierer, %10[^\n] lesen bis 10 Nicht-Zeilenende-Zeichen und sie sind zu puffern zugeordnet, zusammen mit einer nachgestellten null. Die zweiten Format-Spezifizierer, %*[^\n] enthält die Zuordnung Unterdrückungszeichen (*) und liest null oder mehrere verbleibenden nicht-Zeilenende-Zeichen von dem Eingang. Wenn die scanf() Funktion abgeschlossen ist, wird die Eingabe am nächsten Newline-Zeichen zeigt. Der Körper der Schleife liest und druckt das Zeichen, so dass, wenn die Schleife neu gestartet wird, wird der Eingang am Anfang der nächsten Zeile suchen. Der Prozess wiederholt sich dann. Wenn die Zeile kürzer als 10 Zeichen ist, werden diese Zeichen kopiert zu puffern und die ‚Null oder mehr Nicht-Zeilenumbrüche‘ -Format verarbeitet Null nicht-Zeilenumbrüche.

Andere Tipps

Die Konstrukte wie %[a] und %[^a] vorhanden sein, damit scanf() kann als eine Art von lexikalischer Analysator verwendet werden. Dies sind ein bisschen wie %s, aber statt eine Spannweite von so vielen „faserig“ Zeichen wie möglich zu sammeln, sammeln sie nur eine Spanne von Zeichen, wie durch die Zeichenklasse beschrieben. Es kann Fälle geben, in denen Schrift %[a-zA-Z0-9] Sinn machen könnten, aber ich bin nicht sicher, ob ich einen überzeugenden Anwendungsfall für komplementäre Klassen mit scanf() zu sehen.

IMHO, scanf() ist einfach nicht das richtige Werkzeug für diesen Job. Jedes Mal, wenn ich gesetzt habe aus eine seiner leistungsfähigeren Funktionen zu benutzen, ich habe schließlich am Ende zerreißt es aus und die Fähigkeit, in einer anderen Art und Weise umzusetzen. In einigen Fällen, die lex gemeint mit einem echten Lexer zu schreiben, aber in der Regel zu einer Zeit, I / O und brechen es grob in Token mit strtok(), bevor Sie Wertumwandlung war ausreichend.

tun Linie

Edit: I ended herauszureißen scanf() die Regel, weil, wenn sie mit den Benutzern des Beharren auf der Bereitstellung falsche Eingaben konfrontiert, es ist einfach nicht gut darin, das Programm gibt gutes Feedback über das Problem zu helfen, und mit einem Assembler print "Fehler, beendet." als einzige Nachricht hilfreich Fehler würde über nicht gut mit meinem Benutzer. (Me, in diesem Fall).

Es ist wie Zeichensätze von regulären Ausdrücken; [0-9] entspricht eine Folge von Ziffern, [^aeiou] paßt alles, das kein Klein Vokal ist, etc.

Es gibt alle Arten von Anwendungen, wie zum Beispiel das Herausziehen Nummern, Identifikatoren, Brocken von Leerzeichen, etc.

Sie können darüber lesen in der ISO / IEC9899 Standard online zur Verfügung.

Hier ist ein Absatz I aus dem Dokument über [ zitieren (Seite 286):

  

Spiele eine nicht leere Folge von Zeichen aus einem Satz von erwarteten   Zeichen.

     

Der Konvertierungsspezifizierer umfasst alle nachfolgenden Zeichen in der   Formatzeichenkette, bis zu und einschließlich der passende rechte Klammer (]). Das   Zeichen zwischen den Klammern (der Abtastliste) bilden den Scanset,   es sei denn, das Zeichen nach der linken Klammer ist ein Zirkumflex (^), in   welcher Fall enthält die Scanset alle Zeichen, die nicht erscheinen in   die Abtastliste zwischen dem Zirkumflex und der rechten Klammer. wenn die   Konvertierungsspezifizierer beginnt mit [] oder [^], der rechten Klammer   Charakter ist in der Scan-Liste und die nächstfolgende eckige Klammer   Zeichen ist die passende rechte Klammer, die die Spezifikation endet;   ansonsten die erste Folge rechte Klammer Charakter ist derjenige,   endet die Spezifikation. Wenn ein - Zeichen in der Scan-Liste und ist nicht   die erste, noch die zweite, auf der das erste Zeichen ein ^, noch die   letzte Zeichen, das Verhalten ist die Implementierung definiert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top