In ihrem Buch The Practice of Programming (das es wert ist, gelesen zu werden) diskutieren Kernighan und Pike dieses Problem und lösen es, indem sie snprintf()
den String mit der richtigen Puffergröße für die Übergabe an die scanf()
Funktionsfamilie erstellen . In der Tat:
int scanner(const char *data, char *buffer, size_t buflen)
{
char format[32];
if (buflen == 0)
return 0;
snprintf(format, sizeof(format), "%%%ds", (int)(buflen-1));
return sscanf(data, format, buffer);
}
Beachten Sie, dass dies die Eingabe weiterhin auf die als "Puffer" angegebene Größe beschränkt. Wenn Sie mehr Speicherplatz benötigen, müssen Sie die Speicherzuweisung durchführen oder eine nicht standardmäßige Bibliotheksfunktion verwenden, die die Speicherzuweisung für Sie übernimmt.
Beachten Sie, dass die POSIX 2008 (2013) Version der scanf()
Familie von Funktionen ein Format Modifikator unterstützt m
(eine Zuweisung Zuweisungszeichen) für String - Eingänge ( %s
, %c
, %[
). Anstatt ein char *
Argument zu verwenden, wird ein char **
Argument verwendet und der erforderliche Speicherplatz für den gelesenen Wert zugewiesen:
char *buffer = 0;
if (sscanf(data, "%ms", &buffer) == 1)
{
printf("String is: <<%s>>\n", buffer);
free(buffer);
}
Wenn die sscanf()
Funktion nicht alle Konvertierungsspezifikationen erfüllt, wird der gesamte Speicher, den sie für %ms
ähnliche Konvertierungen zugewiesen hat, freigegeben, bevor die Funktion zurückkehrt.
buflen-1
- Danke. Sie müssen sich dann um einen nicht signierten Unterlauf (Umhüllung auf eine ziemlich große Anzahl) kümmern, daher derif
Test. Ich wäre sehr versucht, dies durch ein zu ersetzenassert()
oder es durch einassert()
vor demif
während der Entwicklung ausgelöstes zu sichern, wenn jemand nachlässig genug ist, um 0 als Größe zu übergeben. Ich habe die Dokumentation nicht sorgfältig geprüft, was dies%0s
bedeutetsscanf()
- der Test könnte besser sein alsif (buflen < 2)
.