2011-05-08 14 views
6

Tengo dos funciones auxiliares para separar cadenas en el formato de precios decimales, es decir. "23.00", "2.30"Problema con strtok y falla de segmentación

Considera:

char price[4] = "2.20"; 

    unsigned getDollars(char *price) 
    { 
     return atoi(strtok(price, ".")); 
    } 

    unsigned getCents(char *price) 
    { 
     strtok(price, "."); 
     return atoi(strtok(NULL, ".")); 
    } 

Ahora en que funciono el siguiente recibo un fallo de segmentación:

printf("%u\n", getDollars(string)); 
printf("%u\n", getCents(string)); 

Sin embargo, cuando ellos se ejecutan por separado sin uno después de la otros, funcionan bien ¿Que me estoy perdiendo aqui? ¿Tengo que hacer algún tipo de reinicio de strtok?

Mi solución:

Con el conocimiento sobre strtok he obtenido de la respuesta elegí a continuación, he cambiado la implementación de las funciones de ayuda para que copiar la cadena transferida en primer lugar, protegiendo así la cadena original y la prevención de este problema:

#define MAX_PRICE_LEN 5 /* Assumes no prices goes over 99.99 */ 

unsigned getDollars(char *price) 
{ 
    /* Copy the string to prevent strtok from changing the original */ 
    char copy[MAX_PRICE_LEN]; 
    char tok[MAX_PRICE_LEN]; 

    /* Create a copy of the original string */ 
    strcpy(copy, price); 

    strcpy(tok, strtok(copy, ".")); 

    /* Return 0 if format was wrong */ 
    if(tok == NULL) return 0; 
    else return atoi(tok); 
} 

unsigned getCents(char *price) 
{ 
    char copy[MAX_PRICE_LEN]; 
    char tok[MAX_PRICE_LEN]; 
    strcpy(copy, price); 

    /* Skip this first part of the price */ 
    strtok(copy, "."); 
    strcpy(tok, strtok(NULL, ".")); 

    /* Return 0 if format was wrong */ 
    if(tok == NULL) return 0; 
    else return atoi(tok); 
} 

Respuesta

5

Debido strtok() modifica la cadena de entrada, se encuentra con problemas cuando no puede encontrar el delimitador en la función getCents() después de llamar getDollars().

Tenga en cuenta que strtok() devuelve un puntero nulo cuando no puede encontrar el delimitador. Su código no verifica que strtok() haya encontrado lo que estaba buscando, lo que siempre es riesgoso.


su actualización a la pregunta demuestra que usted ha aprendido sobre al menos algunos de los peligros (males?) De strtok(). Sin embargo, sugeriría que una mejor solución usaría solo strchr().

En primer lugar, podemos observar que atoi() dejará de convertir en el '.' de todos modos, por lo que podemos simplificar getDollars() a:

unsigned getDollars(const char *price) 
{ 
    return(atoi(price)); 
} 

Podemos utilizar strchr() - que no modifica la cadena - de encontrar la '.' y luego procesar el texto después de que:

unsigned getCents(const char *price) 
{ 
    const char *dot = strchr(price, '.'); 
    return((dot == 0) ? 0 : atoi(dot+1)); 
} 

bastante simple, creo.


Una más gotcha: suppose the string is 26.6; usted va a tener que trabajar más duro que el getCents() revisada justo por encima de no conseguir que volver a 60 en lugar de 6. Además, dada 26.650, devolverá 650, no 65.

+0

Gracias por la sugerencia, lo he llevado a bordo. – Chris

5

Este:

char price[4] = "2.20"; 

omite el terminador nulo en price.Creo que quieres esto:

char price[5] = "2.20"; 

o mejor:

char price[] = "2.20"; 

Por lo tanto, se ejecutará fuera de la final de la memoria intermedia de la segunda vez que se intenta obtener un token de price. Simplemente tienes suerte de que getCents() no segfault cada vez que lo ejecutas.

Y casi siempre debe hacer una copia de una cadena antes de usar strtok en ella (para evitar el problema que señaló Jonathan Leffler).

+0

Creo que ambas respuestas/problemas son factores. El mío es el problema genérico de (re) usar 'strtok()' en la misma cadena. El tuyo es un caso especial con esta particular no cadena. –

Cuestiones relacionadas