Angabe der maximalen Stringlänge, um scanf dynamisch in C zu scannen (wie "% * s" in printf)

9

Ich kann die maximale Anzahl von Zeichen für scanf angeben, die mit dieser Technik in ein buffer gelesen werden:

%Vor%

Aber was, wenn wir die Pufferlänge nicht kennen, wenn wir den Code schreiben? Was ist, wenn es sich um den Parameter einer Funktion handelt?

%Vor%

Dieser Code ist anfällig für Pufferüberläufe , da fscanf nicht weiß, wie groß der Puffer ist.

Ich erinnere mich, das vorher gesehen zu haben und dachte mir, dass es die Lösung des Problems ist:

%Vor%

Mein erster Gedanke war, dass die * in "%*[*^\n]" bedeutet, dass die maximale Stringgröße ein Argument (in diesem Fall n ) übergeben wird. Dies ist die Bedeutung von * in printf .

Als ich die Dokumentation für scanf überprüfte, fand ich heraus, dass scanf das Ergebnis von [^\n] verwerfen sollte.

Dies hat mich etwas enttäuscht, da ich denke, dass es eine sehr nützliche Funktion wäre, die Puffergröße dynamisch für scanf zu übergeben.

Gibt es eine Möglichkeit, die Puffergröße dynamisch an scanf zu übergeben?

    
wefwefa3 11.02.2015, 16:55
quelle

2 Antworten

8

Grundlegende Antwort

Es gibt kein Analog zum printf() Formatbezeichner * in scanf() .

In Die Praxis des Programmierens empfehlen Kernighan und Pike die Verwendung von snprintf() Erstellen Sie die Formatzeichenfolge:

%Vor%

Zusätzliche Informationen

Aktualisieren Sie das Beispiel auf eine vollständige Funktion:

%Vor%

Dies betont, dass die Größe in der Formatspezifikation um eins kleiner ist als die Größe des Puffers (es ist die Anzahl von Nicht-Null-Zeichen, die gespeichert werden können, ohne die abschließende Null zu zählen). Beachten Sie, dass dies im Gegensatz zu fgets() steht, wobei die Größe (ein int , übrigens; nicht ein size_t ) die Größe des Puffers ist, nicht weniger. Es gibt mehrere Möglichkeiten, die Funktion zu verbessern, aber es zeigt den Punkt. (Sie können s im Format mit [^\n] ersetzen, wenn Sie das möchten.)

Auch als Tim Čas im Kommentare , wenn Sie möchten (der Rest von) Als Eingabezeile ist es normalerweise besser, wenn Sie fgets() verwenden, um die Zeile zu lesen, aber denken Sie daran, dass sie die Newline in ihrer Ausgabe enthält (während %63[^\n] die Newline zum Lesen bei der nächsten E / A-Operation lässt). Bei allgemeineren Scans (zB 2 oder 3 Strings) kann diese Technik besser sein - besonders, wenn sie mit fgets() oder getline() und dann sscanf() verwendet wird, um die Eingabe zu analysieren.

Auch die "sicheren" TR 24731-1-Funktionen, die von Microsoft (mehr oder weniger) implementiert und in Anhang K der ISO / IEC 9899-2011 (der C11-Standard) standardisiert sind, erfordern eine explizite Länge:

%Vor%

Dies vermeidet Pufferüberläufe, erzeugt aber wahrscheinlich einen Fehler, wenn die Eingabe zu lang ist. Die Größe könnte / sollte wie zuvor in der Formatzeichenfolge angegeben werden:

%Vor%

Beachten Sie, dass die Warnung (von einigen Compilern unter einigen Merkergruppen) über 'nicht konstante Formatzeichenfolge' für Code, der die generierte Formatzeichenfolge verwendet, ignoriert oder unterdrückt werden muss.

    
Jonathan Leffler 11.02.2015, 17:01
quelle
5

In der Funktionsfamilie scanf ist tatsächlich kein Spezifizierer mit variabler Breite vorhanden. Alternativen sind das dynamische Erstellen der Formatzeichenfolge (obwohl das ein wenig albern erscheint, wenn die Breite eine Kompilierzeitkonstante ist) oder das einfache Akzeptieren der magischen Zahl. Eine Möglichkeit besteht darin, Präprozessor-Makros zum Angeben der Puffer- und Formatzeichenfolgebreite zu verwenden:

%Vor%     
Arkku 11.02.2015 17:08
quelle

Tags und Links