Wie fast jeder sagt, ist es besser, fgets(..., stdin)
zu verwenden, um dieses Problem zu behandeln.
In den folgenden Link, ich habe eine sichere und richtige Technik vorgeschlagen, die Sie lassen durch eine sicherere Methode scanf()
zu ersetzen, durch eine solide Makro:
A macro that safely replaces scanf()
Das Makro Ich habe Text (die Arbeit mit kompatibel C99 Compilern) ist safe_scanf()
, wie in dem folgende Programm gezeigt:
#include <stdio.h>
#define safe_scanf(fmt, maxb, ...) { \
char buffer[maxb+1] = { [maxb - 1] = '\0' }; \
fgets(buffer, maxb+1, stdin); \
if ((buffer[maxb - 1] != '\0') && (buffer[maxb - 1] != '\n')) \
while(getchar() != '\n') \
; \
sscanf(buffer, fmt, __VA_ARGS__); \
}
#define MAXBUFF 20
int main(void) {
int x; float f;
safe_scanf("%d %g", MAXBUFF+1, &x, &f);
printf("Your input was: x == %d\t\t f == %g", x, f);
return 0;
}
möchten Sie Melodie haben der Wert MAXBUFF
nach Ihren Bedürfnissen ...
Obwohl das Makro safe_scanf()
ziemlich solide ist,
gibt es einige Schwächen in den Makro-Ansatz:
Fehlende für Parameter Typ-Überprüfung , fehlende "Return" -Werte (die sich kaum von der "echten" scanf()
-Funktion unterscheiden, die einen int zurückgibt, mit wertvollen Informationen zur Fehlerüberprüfung) und so weiter.
Alle, die Probleme haben, Lösung, aber es Teil eines anderen Thema ...
Vielleicht ist die genaueste Lösung ist eine Funktion my_scanf()
mit variabler Anzahl von Parametern zu definieren, durch die Berufung auf stdarg.h
Bibliothek, Gelenk- einer Kombination von fgets()
und vsscanf()
. Hier haben Sie den Code:
#include <stdio.h>
#include <stdarg.h>
int my_scanf(const char* fmt, const unsigned int maxbuff, ...) {
va_list ptr;
int ret;
if (maxbuff <= 0)
return EOF; /* Bad size for buffer[] */
char buffer[maxbuff+1];
buffer[maxbuff-1] = '\0'; /* Quick buffer cleaning... */
if (fgets(buffer, maxbuff+1, stdin) == NULL)
return EOF; /* Error detected */
else {
if ((buffer[maxbuff-1] != '\n') && (buffer[maxbuff-1] != '\0'))
/* Condition logically equivalent to:
fgets() has not reached an '\n'
*/
while (getchar() != '\n')
; /* "Flushing" stdin... */
va_start(ptr, maxbuff);
ret = vsscanf(buffer, fmt, ptr);
va_end(ptr);
return ret;
}
}
#define MAXBUFF 20
int main(void) {
int x;
float z;
int scanf_ret = my_scanf("%d %g", MAXBUFF, &x, &z);
printf("\nTest:\n x == %d\n z == %g\n scanfret == %d", x, z, scanf_ret);
getchar();
return 0;
}
Die Funktion my_scanf() hat den Prototyp
int my_scanf(const char* fmt, const int maxbuff, ...);
Es akzeptiert eine Format-String fmt
, die auf die gleiche Art und Weise verhält sich wie jeder andere scanf()
-ähnlichen tut.
Der zweite Parameter ist die maximale Anzahl von Zeichen, die effektiv von der Standardeingabe (Tastatur) akzeptiert werden.
Der Rückgabewert ist ein Int, die EOF
ist, wenn maxbuff
keinen Sinn hat, oder auch einige Eingabefehler passiert. Wenn ein nicht negativer Wert zurückgegeben wird, ist dies der gleiche Wert, der von den Standardfunktionen sscanf()
oder zurückgegeben würde.
Innerhalb der Funktion wird maxbuff
in 1 inkrementiert, weil fgets()
Platz für ein zusätzliches '\ 0'-Zeichen bietet.
Nicht positive Werte von maxbuff
werden sofort verworfen.
fgets()
wird eine Zeichenfolge gelesen wird gelesen von stdin
(Tastatur) mit Platz für höchstens maxbuff
Zeichen, einschließlich '\ n'.
Wenn der Benutzer einen sehr langen String eingegeben hat, wird er gekürzt, und es ist eine Art "Flush" -Mechanismus erforderlich, um alle Zeichen zum nächsten '\ n' (ENTER) zu verwerfen. Wenn nicht, könnte das nächste Tastaturlesen ältere Zeichen haben, die überhaupt nicht erwünscht sind.
Die Bedingung für "Spülen" ist, dass fgets()
'\ n' nach dem Lesen stdin
nicht erreicht hat.
Dies ist der Fall, wenn und nur wenn buffer[maxbuff - 1]
nicht gleich '\ 0' oder '\ n' ist.
(Check it!)
Schließlich ist eine sachgemäße Kombination aus stdarg.h
Makros und der Funktion vsscanf()
verwendet wird, um die variable Parameterliste zu verarbeiten.
Diskutiert [hier] (http://stackoverflow.com/questions/9457325/how-to-use-sscanf-correctly-and-safely). –
Wie können Sie 'MAX_STR_LEN' innerhalb einer Formatzeichenfolge verwenden? – amulous
@amulous, da es strenge ANSI C ist, habe ich nicht wirklich Zugriff auf echte String-Variable. Ich muss tun: char * somestring und dann malloc ... – tomdavies