2010-05-18 12 views
29

Para un proyecto, estoy tratando de leer un int y una cadena de una cadena. El único problema es que sscanf parece romper la lectura un% s cuando ve un espacio. ¿Hay alguna forma de evitar esta limitación? He aquí un ejemplo de lo que estoy tratando de hacer:leyendo una cadena con espacios con sscanf

#include<stdio.h> 
#include<stdlib.h> 

int main(int argc, char** argv) { 
    int age; 
    char* buffer; 
    buffer = malloc(200 * sizeof(char)); 
    sscanf("19 cool kid", "%d %s", &age, buffer); 

    printf("%s is %d years old\n", buffer, age); 
    return 0; 
} 

Lo que se imprime es: "No es genial 19 años" donde necesito "chico cool es de 19 años de edad". ¿Alguien sabe cómo arreglar esto?

+0

Verificar el resultado de 'sscanf()' es un buen primer paso para asegurar que 'age', etc. escanee con éxito. – chux

Respuesta

34

La siguiente línea empezará a leer un número (%d), seguido de algo diferente de lengüetas o saltos de línea (%[^\t\n]).

sscanf("19 cool kid", "%d %[^\t\n]", &age, buffer); 
+0

Gracias. También por alguna razón% d dejó de funcionar, así que utilicé% [0-9]. Gracias de nuevo. – SDLFunTimes

+1

Pero ... ¡pero esto es desastrosamente incorrecto! El especificador '% [0-9]' (y otros similares) solo se pueden usar para leer cadenas. Y estás leyendo un 'int' (' age') con él. Esto no puede funcionar y no funcionará. – AnT

+0

Si quiere leer un 'int', necesita'% d' (o tal vez '% i' o cualquier otro int-compatible). Pero no '% []'. – AnT

11

desea que el especificador %c conversión, que simplemente lee una secuencia de caracteres, sin espacios en blanco para un manejo especial.

Tenga en cuenta que primero debe llenar el búfer con ceros, porque el especificador %c no escribe un terminador nul. También es necesario especificar el número de caracteres a leer (en caso contrario el valor predeterminado es solamente 1):

memset(buffer, 0, 200); 
sscanf("19 cool kid", "%d %199c", &age, buffer); 
+9

Bueno, eso no va a funcionar para mi primo, que sospechosamente se llama "George Fortescue Aloxy Broomhilda Doreen Beelzebub ... Johanssen MacGregor" :-) – paxdiablo

+3

De hecho, su primo debe quejarse ante el OP por solo asignar un búfer de 200 bytes ;) – caf

+0

Buen punto y, como has detectado el problema de desbordamiento del búfer con el mío y las respuestas de Bruno, +1. Ven, únete a nosotros :-) – paxdiablo

8

Si desea escanear al final de la cadena (excluyendo un salto de línea si hay), sólo tiene que utilizar:

char *x = "19 cool kid"; 
sscanf (x, "%d %[^\n]", &age, buffer); 

Eso es porque %s única partidos caracteres no está en blanco y no se detendrá en el primer espacio en blanco que encuentra. El especificador de formato %[^\n] coincidirá con todos los caracteres que no lo son (debido a ^) en la selección dada (que es una nueva línea). En otras palabras, coincidirá con cualquier otro personaje.


Tenga en cuenta que debe haber asignado suficiente espacio en su memoria intermedia para tomar la cuerda ya no se puede estar seguro de cuánto será leído (una buena razón para mantenerse alejado de scanf/fscanf a menos que utilice ancho de los campos específicos) .

Se podría hacer eso con:

char *x = "19 cool kid"; 
char *buffer = malloc (strlen (x) + 1); 
sscanf (x, "%d %[^\n]", &age, buffer); 

(que no es necesario * sizeof(char) ya que eso es siempre 1 por definición).

+4

Así que aquí, ¿tu primo causa un choque en lugar de sufrir la indignidad de tener su nombre truncado? Además, mi primo, que tiene un nombre aún más sospechoso (el tercer personaje de su segundo nombre es una nueva línea) es infeliz. – caf

+0

@caf ummm ¿qué? – SDLFunTimes

+1

El comentario debe leerse en el contexto de los comentarios a mi respuesta. – caf

1

Dado que desea la cadena final de la entrada, puede usar %n (número de caracteres consumidos hasta el momento) para obtener la posición en la que se inicia la secuencia final. Esto evita las copias de memoria y los problemas de tamaño del búfer, pero tiene el costo que puede necesitar para hacerlos explícitamente si desea una copia.

const char *input = "19 cool kid"; 
int age; 
int nameStart = 0; 
sscanf(input, "%d %n", &age, &nameStart); 
printf("%s is %d years old\n", input + nameStart, age); 

salidas:

cool kid is 19 years old 
+0

Buena captura @chux. He actualizado la respuesta para inicializar 'nameStart = 0'. Eso al menos evitará una falla de segmentación en la entrada incorrecta. –

0

supongo que esto es lo que quiere, que hace exactamente lo que ha especificado.

#include<stdio.h> 
#include<stdlib.h> 

int main(int argc, char** argv) { 
    int age; 
    char* buffer; 
    buffer = malloc(200 * sizeof(char)); 
    sscanf("19 cool kid", "%d cool %s", &age, buffer); 
    printf("cool %s is %d years old\n", buffer, age); 
    return 0; 
} 

El formato de espera: en primer lugar un número (y la pone en & puntos de edad a), después de espacio en blanco (cero o más), entonces la cadena literal "fresco", a continuación, los espacios en blanco (cero o más) de nuevo , y finalmente una cadena (y poner eso en cualquier punto de buffer a). Olvidó la parte "interesante" en su cadena de formato, por lo que el formato asume que esa es la cadena que quería asignar al búfer. Pero no desea asignar esa cadena, solo sáltese.

alternativa, también podría tener una cadena de formato como: "% d% s% s", pero entonces debe asignar otro búfer para él (con otro nombre), e imprimirlo como: "% s% s es% d años \ n ".