usa - return string in c
Strtok de C() y solo literales de cadena (5)
Un punto importante que se infiere pero no se menciona explícitamente:
Según tu pregunta, supongo que eres bastante nuevo en la programación en C, por lo que me gustaría explicarte un poco más sobre tu situación. Perdóname si estoy equivocado; C puede ser difícil de aprender sobre todo debido a sutiles malentendidos en los mecanismos subyacentes, así que me gusta hacer las cosas lo más claras posible.
Como usted sabe, cuando escribe su programa C, el compilador crea todo para usted en función de la sintaxis. Cuando declara una variable en cualquier parte de su código, por ejemplo:
int x = 0;
El compilador lee esta línea de texto y se dice a sí mismo: OK, necesito reemplazar todas las ocurrencias en el alcance del código actual de x
con una referencia constante a una región de la memoria que he asignado para contener un número entero.
Cuando se ejecuta su programa, esta línea conduce a una nueva acción: necesito establecer la región de la memoria que x
referencia al valor int
0
.
Tenga en cuenta la sutil diferencia aquí: la ubicación de la memoria que contiene el punto de referencia x
es constante (y no se puede cambiar). Sin embargo, el valor de x
puntos se puede cambiar. Lo haces en tu código mediante asignación, por ejemplo, x = 15;
. También tenga en cuenta que la única línea de código equivale a dos comandos separados para el compilador.
Cuando tienes una declaración como:
char *name = "Tom";
El proceso del compilador es así: OK, necesito reemplazar todas las ocurrencias en el alcance del código actual del name
con una referencia constante a una región de memoria que he asignado para mantener un valor de puntero de char
. Y lo hace.
Pero está ese segundo paso, que equivale a esto: necesito crear una matriz constante de caracteres que contenga los valores ''T'', ''o'', ''m'' y NULL
. Entonces necesito reemplazar la parte del código que dice "Tom"
con la dirección de memoria de esa cadena constante.
Cuando se ejecuta su programa, se produce el último paso: configurar el puntero al valor de char
(que no es constante) a la dirección de la memoria de esa cadena creada automáticamente (que es constante).
Entonces, un char *
no es de solo lectura. Solo un const char *
es de solo lectura. Pero su problema en este caso no es que los caracteres son de solo lectura, sino que su puntero hace referencia a regiones de memoria de solo lectura.
Traigo todo esto a colación porque entender este problema es la barrera entre que miras la definición de esa función de la biblioteca y entiendes el problema tú mismo en lugar de tener que preguntarnos. Y de alguna manera he simplificado algunos de los detalles con la esperanza de hacer el tema más comprensible.
Espero que esto haya sido útil. ;)
char * strtok (char * s1, const char * s2)
las llamadas repetidas a esta función dividen la cadena s1 en "tokens", es decir, la cadena se divide en subcadenas, cada una terminando con un ''/ 0'', donde ''/ 0'' reemplaza cualquier carácter contenido en la cadena s2. La primera llamada usa la cadena para ser tokenizada como s1; las llamadas subsiguientes usan NULL como primer argumento. Se devuelve un puntero al comienzo del token actual; Se devuelve NULL si no hay más tokens.
Hola,
He estado tratando de usar strtok
ahora y descubrí que si paso un char*
en s1
, s1
un error de segmentación. Si paso un char[]
, strtok
funciona bien.
¿Por qué es esto?
Busqué en Google y la razón parece ser algo acerca de cómo char*
es de solo lectura y char[]
es escribible. Una explicación más completa sería muy apreciada.
Culpo al estándar C
char *s = "abc";
podría haber sido definido para dar el mismo error que
const char *cs = "abc";
char *s = cs;
sobre la base de que los literales de cadena no son modificables. Pero no fue así, se definió para compilar. Imagínate. [Editar: Mike B ha figurado - "const" no existía en absoluto en K & R C. ISO C, además de todas las versiones de C y C ++ ya que, ha querido ser compatible con versiones anteriores. Entonces tiene que ser válido.]
Si se hubiera definido que proporcionara un error, entonces no podría haber llegado tan lejos como segfault, porque el primer parámetro de strtok es char *, por lo que el compilador le habría impedido pasar el puntero generado a partir del literal.
Puede ser de interés que haya un plan en C ++ para que este sea desaprobado ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1996/N0896.asc ). Pero 12 años después no puedo persuadir ni a gcc ni a g ++ para que me den algún tipo de advertencia para asignar un carácter literal a no const *, por lo que no es tan obvio.
[Editar: aha: -Wwrite-strings, que no está incluido en -Wall o -Wextra]
En breve:
char *s = "HAPPY DAY";
printf("/n %s ", s);
s = "NEW YEAR"; /* Valid */
printf("/n %s ", s);
s[0] = ''c''; /* Invalid */
Si observa la documentación de su compilador, hay una opción que puede configurar para que esas cadenas puedan escribirse.
¿A qué inicializaste el char *
?
Si algo como
char *text = "foobar";
entonces tienes un puntero a algunos caracteres de solo lectura
por
char text[7] = "foobar";
entonces tienes una matriz de siete elementos de personajes con los que puedes hacer lo que quieras.
strtok
escribe en la cadena que le da, sobrescribiendo el carácter separador con null
y manteniendo un puntero al resto de la cadena.
Por lo tanto, si le pasa una cadena de solo lectura, intentará escribirle y obtendrá una segfault.
Además, dado que strtok
guarda una referencia al resto de la cadena, no es reeentrante; puede usarlo solo en una cadena a la vez. Lo mejor es evitarlo, realmente - considere strsep (3) en su lugar - vea, por ejemplo, aquí: http://www.rt.com/man/strsep.3.html (aunque eso todavía se escribe en la cadena así que tiene la misma lectura) -sólo / problema de segfault