2010-02-09 12 views
14

¿Alguien puede explicar por qué estoy obteniendo un error de segmentación en el siguiente ejemplo?Fallo de segmentación al utilizar strtok_r

#include <stdio.h> 
#include <string.h> 

int main(void) { 
    char *hello = "Hello World, Let me live."; 
    char *tokens[50]; 
    strtok_r(hello, " ,", tokens); 
    int i = 0; 
    while(i < 5) { 
    printf("%s\n", tokens[i++]); 
    } 
} 

Respuesta

22

Prueba esto:

#include <stdio.h> 
#include <string.h> 

int main(void) { 
     char hello[] = "Hello World, Let me live."; // make this a char array not a pointer to literal. 
     char *rest; // to point to the rest of the string after token extraction. 
     char *token; // to point to the actual token returned. 
     char *ptr = hello; // make q point to start of hello. 

     // loop till strtok_r returns NULL. 
     while(token = strtok_r(ptr, " ,", &rest)) { 

       printf("%s\n", token); // print the token returned. 
       ptr = rest; // rest contains the left over part..assign it to ptr...and start tokenizing again.  
     } 
} 
/* 
Output: 
Hello 
World 
Let 
me 
live. 
*/ 
+0

Gracias una tonelada :) –

+0

Este ejemplo me da un segfault en la línea printf. El token de impresión de gdb muestra 0xffffffffffffdad0 También recibe estas dos advertencias cuando compilo proj1.c: 33: 2: advertencia: declaración implícita de la función 'strtok_r' [-Wimplicit-function-declaration] proj1.c: 33: 14: advertencia: asignación hace puntero desde entero sin un molde [habilitado por defecto] – schwiz

+1

Lo siento, soy un novato, ¿por qué no debería ser 'char * ptr = Hola;' con mayúscula H? Además, la respuesta de Alok dice que la primera vez que el primer parámetro necesita ser "tokenizado" y luego las llamadas subsiguientes debe ser NULO, pero parece que tu ejemplo simplemente lo llama de una sola manera en el ciclo while. Gracias por el código btw –

0

yo creo que puede ser el char *tokens[50]; debido a que se está declarando que un puntero cuando ya es un puntero. Una matriz ya es un puntero al declararse. Quiere decir char tokens[50];. Eso debería hacer el truco.

+1

Tu comprensión de C parece incluso más débil que yo ... –

3

strtok_r intenta escribir caracteres nulos en hola (que es ilegal porque es una cadena const)

+0

Intenté 'char hello [50]'. La falla de segmentación se ha desvanecido, pero ahora el problema es 'printf' solo imprime tristes líneas en blanco. :( –

2

Has comprendido el uso de strtok_r incorrectamente. Selecciona esta example y documentación

Y tratar & ver esto:

#include <stdio.h> 
#include <string.h>  

int main(void) 
{ 
    char hello[] = "Hello World, let me live."; 

    char *tmp; 
    char *token = NULL; 
    for(token = strtok_r(hello, ", ", &tmp); 
     token != NULL; 
     token = strtok_r(NULL, ", ", &tmp)) 
    { 
     printf("%s\n", token); 
    } 

    return 0; 
} 
5

Un manojo de cosas mal:

  1. hello puntos a una cadena literal, que debe ser tratada como inmutable. (Podría vivir en la memoria de solo lectura). Dado que strtok_r muta su cadena de argumentos, no puede usar hello con ella.

  2. Llame al strtok_r una sola vez y no inicialice su matriz tokens para apuntar a nada.

Prueba esto:

#include <stdio.h> 
#include <string.h> 

int main(void) { 
    char hello[] = "Hello World, Let me live."; 
    char *p = hello; 
    char *tokens[50]; 
    int i = 0; 

    while (i < 50) { 
    tokens[i] = strtok_r(p, " ,", &p); 
    if (tokens[i] == NULL) { 
     break; 
    } 
    i++; 
    } 

    i = 0; 
    while (i < 5) { 
    printf("%s\n", tokens[i++]); 
    } 

    return 0; 
} 
+0

Gracias por la respuesta. Ojalá SO permitiera marcar múltiples respuestas como correctas. :) –

14
  • es necesario llamar a strtok_r en un bucle. La primera vez que le das la cadena para ser tokenizada, le das el NULL como primer parámetro.
  • strtok_r toma un char ** como el tercer parámetro. tokens es una matriz de 50 char * valores. Cuando pasa tokens a strtok_r(), lo que se pasa es un valor char ** que apunta al primer elemento de esa matriz. Esto está bien, pero estás desperdiciando 49 de los valores que no se usan en absoluto. Debería tener char *last; y usar &last como el tercer parámetro para strtok_r().
  • strtok_r() modifica su primer argumento, por lo que no puede pasar algo que no se puede modificar. Los literales de cadena en C son de solo lectura, por lo que necesita algo que pueda modificarse: char hello[] = "Hello World, Let me live."; por ejemplo.
+1

Gracias por la respuesta. Ojalá SO permitiera marcar múltiples respuestas como correctas. :) –

+0

+1, la mejor respuesta. –

+0

@Scrub: me alegro de ser de ayuda. Asegúrese de comprender mi segundo punto anterior (sobre 'char * tokens [50];' es equivalente a 'char **' cuando se pasa a una función). –

Cuestiones relacionadas