2012-01-12 9 views
5

Lo siento por la simple pregunta, pero estoy tratando de encontrar una manera elegante de evitar la entrada de mi programa de ver como "14asdf" y aceptar que al igual que 14.enteros que están al lado de caracteres usando sscanf()

if (sscanf(sInput, "%d", &iAssignmentMarks[0]) != 0) 

¿Hay alguna manera fácil de evitar que sscanf saque números enteros de cadenas destrozadas como esa?

+0

¿Quieres decir que hay una forma de que sscanf solo recoja los caracteres numéricos en una cadena como esa? También es posible que desee aclarar si desea que "53sd2" devuelva 53 o 532. – Ian

+0

Lo siento, debería ser más claro, quiero que "14asdf" se reconozca como entrada no válida, al igual que "53sd2". Solo quiero reconocer enteros independientes (al menos delimitados por espacios) sin que los caracteres que no sean dígitos los toquen. – ARW

+0

Esto sería fácil en C++.¿Tal vez la etiqueta 'C++' debería eliminarse de esta pregunta? @AdamWathan, ¿solo quieres respuestas que funcionen en C? –

Respuesta

3

No se puede parar directamente sscanf() de hacer lo que se diseña y especifica que hacer. Sin embargo, se puede utilizar una característica poco conocida y rara vez utilizada de sscanf() para que sea fácil de descubrir que había un problema:

int i; 

if (sscanf(sInput, "%d%n", &iAssignmentMarks[0], &i) != 1) 
    ...failed to recognize an integer... 
else if (!isspace(sInput[i]) && sInput[i] != '\0') 
    ...character after integer was not a space character (including newline) or EOS... 

Los %n informes directiva sobre el número de caracteres que consume hasta ese momento y no cuenta como una conversión (por lo que solo hay una conversión en ese formato). El %n es estándar en sscanf() desde C89.

Para extraer un solo entero, también puede usar strtol() - cuidadosamente (detectar las condiciones de error con él es sorprendentemente difícil, pero es mejor que sscanf() que no informará ni detectará desbordamientos). Sin embargo, esta técnica se puede usar varias veces en un solo formato, que a menudo es más conveniente.

2

Quiere leer enteros de cadenas. Es más fácil hacer esto con strtol en lugar de sscanf. strtol devolverá, indirectamente a través de endptr, la dirección justo después del último carácter que se leyó con éxito en el número. Si, y solo si, la cadena era un número, entonces endptr apuntará al final de su cadena de números, es decir, *endptr == \0.

char *endptr = NULL; 
long n = strtol(sInput, &endptr, 10); 
bool isNumber = endptr!=NULL && *endptr==0 && errno==0; 

(espacio en blanco inicial se ignora. Ver una strtol man page para más detalles.

+0

Agregué un poco de texto a la respuesta para explicar el código. Espero que no te importe @ Serge-appTranslator. Siéntase libre de editar más o eliminarlo. –

+1

¿Qué? ¿texto? ¡Por qué no comentar el código mientras lo hace! :-) Gracias Aaron –

0

scanf no es tan inteligente. Vas a tener que leer la entrada como texto y utilizar strtol para convertirlo. Una de las argumentos a strtol es un char * que apunte al primer carácter que no se convierte, si que carácter no es un espacio en blanco o 0, entonces la cadena de entrada no era un número entero válido:

char input[SIZE]; // where SIZE is large enough for the expected values plus 
        // a sign, newline character, and 0 terminator 
... 
if (fgets(input, sizeof input, stdin)) 
{ 
    char *chk; 
    long val = strtol(input, &chk, 10); 
    if (*chk == NULL || !isspace(*chk) && *chk != 0) 
    { 
    // input wasn't an integer string 
    } 
} 
+0

La pregunta es sobre 'sscanf', no' scanf', y por lo tanto los datos ya están en una cadena. Ver la respuesta de @ Serge. –

+0

Esto no es correcto: puede usar '[fs] scanf()' para esto OK: solo tiene que intentar leer algo después del número y verificar el número de elementos leídos. –

2

Esto es fácil. ¡No se requiere C++ lujoso! Sólo hacer:

char unusedChar; 
if (sscanf(sInput, "%d%c", &iAssignmentMarks[0], &unusedChar) == 1) 
Cuestiones relacionadas