2010-11-03 15 views
8

Duplicar posibles:
strtok wont accept: char *strstrtok - matriz de caracteres frente puntero char

Al utilizar la función strtok, utilizando un char * en lugar de un char [] da como resultado un fallo de segmentación.

Esto funciona correctamente:

char string[] = "hello world"; 
char *result = strtok(string, " "); 

Esto provoca un fallo de segmentación:

char *string = "hello world"; 
char *result = strtok(string, " "); 

¿Puede alguien explicar por qué causa esta diferencia de comportamiento?

Respuesta

23
char string[] = "hello world"; 

Esta línea inicializa string ser una matriz suficientemente grande de caracteres (en este caso char[12]). Se copia esos caracteres en el array local como si hubiera escrito a cabo

char string[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' }; 

La otra línea:

char* string = "hello world"; 

no inicializa un array local, sólo se inicializa un puntero local. Se permite que el compilador para establecer en un puntero a una matriz, que no se le permite cambiar, como si el código fuera

const char literal_string[] = "hello world"; 
char* string = (char*) literal_string; 

La razón C permite esto sin un reparto es principalmente para dejar antiguo código continuar compilando Debes pretender que el tipo de literal de una cadena en tu código fuente es const char[], que puede convertirse a const char*, pero nunca convertirlo a char*.

+0

Muchas buenas respuestas, pero encontré este el más claro ejemplo del problema fundamental. –

+0

+1 excelente explicación –

10

En el segundo ejemplo:

char *string = "hello world"; 
char *result = strtok(string, " "); 

el puntero string apunta a una cadena literal, lo que no se puede modificar (como strtok() le gustaría hacer).

se podría hacer algo a lo largo de las líneas de:

char *string = strdup("hello world"); 
char *result = strtok(string, " "); 

modo que string está apuntando a una copia modificable de la literal.

+0

Voy a resistir el impulso de -1, pero realmente no me gusta esta respuesta. Creo que lleva a los codificadores novatos a la expresión idiomática de lanzar 'strdup' para resolver segfaults en lugar de aprender a administrar la memoria (y especialmente las cadenas). Pero no estoy seguro de cuál sería una mejor respuesta sin decir "solo use la matriz o asigne dinámicamente memoria para su cadena". Por cierto, 'strdup' no es estándar C, pero por supuesto es bastante fácil de implementar en sistemas que no lo tienen. –

0

El primer caso se crea una matriz de caracteres (no const) que es lo suficientemente grande como para contener la cadena y lo inicializa con el contenido de la cadena. El segundo caso crea un puntero de char y lo inicializa para apuntar al literal de cadena, que probablemente se almacena en la memoria de solo lectura.

Dado que strtok desea modificar la memoria apuntada por el argumento que usted pasa, este último caso causa un comportamiento indefinido (está pasando un puntero que apunta a un (const) cadena literal), por lo que es insuperable que accidentes

3

en el segundo caso (char *), la cadena está en memoria de sólo lectura. El tipo correcta de las constantes de cadena es const char *, y si se ha utilizado ese tipo para declarar la variable que se obtendría advertido por el compilador cuando intentó modificarlo. Por razones históricas, puede usar constantes de cadena para inicializar variables del tipo char * aunque no se puedan modificar. (Algunos compiladores permiten activar esta licencia histórica fuera, por ejemplo con gcc de -Wwrite-strings.)

+0

También vale la pena mencionar que, en el primer caso, hay una copia implícita del literal de cadena en la matriz de caracteres. Por eso no tienes el mismo problema. –

+0

'const char *' en realidad también da como resultado un segfault si se intenta usar con 'strtok', pero al menos da una advertencia de compilación. Pero señaló que la modificación es el problema. –

+0

Sí, debería haber sido menos telegráfico. Respuesta editada. – zwol

0

Debido a que el segundo declara un puntero (que puede cambiar) a una cadena constante ...

Así que dependiendo de su compilador/plataforma/OS/mapa de memoria ... la cadena "hola mundo" será almacenado como una constante (en un sistema embebido, puede ser almacenado en la ROM) y tratando de modificarlo hará que ese error.

4

strtok modifica la cadena se pasa a ella (o trata de todos modos). En su primer código, está pasando la dirección de una matriz que se ha inicializado a un valor particular, pero como se trata de una matriz normal de caracteres, se permite modificarla.

En el segundo código, está pasando la dirección de una cadena literal.Intentar modificar un literal de cadena proporciona un comportamiento indefinido.

Cuestiones relacionadas