solucionar solucion segmentation generado error dumped c string segmentation-fault

solucion - ¿Por qué este código C de inversión de cadena provoca un error de segmentación?



segmentation fault(core dumped) c++ (8)

¿Estás probando esto algo así?

int main() { char * str = "foobar"; reverse(str); printf("%s/n", str); }

Esto hace que str una cadena sea literal y probablemente no podrá editarla (segfaults para mí). Si define char * str = strdup(foobar) debería funcionar bien (lo hace para mí).

Intento escribir código para invertir una cadena en su lugar (estoy tratando de mejorar en la programación C y la manipulación del puntero), pero no puedo entender por qué estoy obteniendo una falla de segmentación :

#include <string.h> void reverse(char *s); int main() { char* s = "teststring"; reverse(s); return 0; } void reverse(char *s) { int i, j; char temp; for (i=0,j = (strlen(s)-1); i < j; i++, j--) { temp = *(s+i); //line 1 *(s+i) = *(s+j); //line 2 *(s+j) = temp; //line 3 } }

Son las líneas 2 y 3 las que están causando la falla de segmentación. Entiendo que puede haber mejores formas de hacerlo, pero estoy interesado en descubrir qué es lo que específicamente en mi código está causando la falla de segmentación.

Actualización : he incluido la función de llamada según lo solicitado.


¿Qué compilador y depurador estás usando? Usando gcc y gdb, compilaría el código con el indicador -g y luego lo ejecutaría en gdb. Cuando se segmenta, simplemente haría una traza inversa (comando bt en gdb) y vería cuál es la línea ofensiva que causa el problema. Además, simplemente ejecutaba el código paso a paso, mientras "miraba" los valores del puntero en gdb y sabía dónde estaba exactamente el problema.

Buena suerte.


Como algunas de las respuestas proporcionadas anteriormente, la memoria de cadena es de solo lectura. Sin embargo, algunos compiladores ofrecen una opción para compilar cadenas de escritura. Por ejemplo, con gcc , las versiones 3.x son compatibles -fwritable-strings pero las versiones más nuevas no.


Creo que strlen no puede funcionar dado que s no tiene terminación NULL. Entonces, el comportamiento de su iteración no es el que espera. Como el resultado de strlen será superior a la longitud, escribirás en la memoria donde no deberías estar.

Además, s apunta a una cadena constante retenida por una memoria de solo lectura. No puedes modificarlo. Intente iniciar s utilizando la función strlen como se hace en el ejemplo de strlen


No hay forma de decir solo de ese código. Lo más probable es que esté pasando un puntero que apunta a memoria no válida, memoria no modificable u otro tipo de memoria que simplemente no se puede procesar de la manera en que se procesa aquí.

¿Cómo llamas a tu función?

Agregado: está pasando un puntero a un literal de cadena. Los literales de cadena no son modificables. No puede invertir un literal de cadena.

Pase un puntero a una cadena modificable en su lugar

char s[] = "teststring"; reverse(s);

Esto ya ha sido explicado hasta la muerte aquí. "teststring" es un literal de cadena. El literal de cadena en sí es un objeto no modificable. En la práctica, los compiladores pueden (y lo harán) ponerlo en la memoria de solo lectura. Cuando inicializas un puntero como ese

char *s = "teststring";

el puntero apunta directamente al comienzo del literal de la cadena. Cualquier intento de modificar lo que está apuntando se considera que falla en el caso general. Puedes leerlo, pero no puedes escribir en él. Por esta razón, se recomienda encarecidamente que apunte a literales de cadena únicamente con variables de puntero a const.

const char *s = "teststring";

Pero cuando declaras tu s como

char s[] = "teststring";

obtienes una matriz totalmente independiente s ubicada en la memoria ordinaria modificable, que acaba de inicializarse con una cadena literal. Esto significa que esa matriz modificable independiente obtendrá su valor inicial copiado de la cadena literal. Después de eso, su matriz y el literal de cadena continuarán existiendo como objetos completamente independientes. El literal sigue siendo no modificable, mientras que el conjunto de s es modificable.

Básicamente, la última declaración es funcionalmente equivalente a

char s[11]; strcpy(s, "teststring");


Su código podría estar segfaulting por una serie de razones. Aquí están los que vienen a la mente

  1. s es NULL
  2. s apunta a una cadena const que se mantiene en la memoria de solo lectura
  3. s no es NULL terminado

Creo que el # 2 es el más probable. ¿Puede mostrarnos el sitio de llamada de reversa?

EDITAR

Basado en su muestra n. ° 2 es definitivamente la respuesta. Un literal de cadena en C / C ++ no es modificable. El tipo correcto es en realidad const char* y no char* . Lo que tienes que hacer es pasar una cadena modificable a ese buffer.

Ejemplo rápido:

char* pStr = strdup("foobar"); reverse(pStr); free(pStr);


Tu declaración es completamente incorrecta:

char* s = "teststring";

"Teststring" se almacena en el segmento de código, que es de solo lectura, como el código. Y, s es un puntero a "testingtring", al mismo tiempo, está intentando cambiar el valor de un rango de memoria de solo lectura. Por lo tanto, falla de segmentación.

Pero con:

char s[] = "teststring";

s se inicializa con "testtring", que por supuesto está en el segmento de código, pero hay una operación de copia adicional en curso, a la pila en este caso.


Vea la pregunta 1.32 en la lista de preguntas frecuentes de C:

¿Cuál es la diferencia entre estas inicializaciones?

char a[] = "string literal"; char *p = "string literal";

Mi programa se bloquea si trato de asignar un nuevo valor a p[i] .

Responder:

Un literal de cadena (el término formal para una cadena de comillas dobles en origen C) se puede usar de dos maneras diferentes:

Como iniciador de una matriz de char, como en la declaración de char a[] , especifica los valores iniciales de los caracteres en esa matriz (y, si es necesario, su tamaño).

En cualquier otro lugar, se convierte en una matriz estática no nombrada de caracteres, y esta matriz sin nombre se puede almacenar en la memoria de solo lectura, y que, por lo tanto, no se puede modificar necesariamente . En un contexto de expresión, la matriz se convierte a la vez en un puntero, como es habitual (ver sección 6), por lo que la segunda declaración inicializa p para apuntar al primer elemento de la matriz sin nombre.

Algunos compiladores tienen un interruptor que controla si los literales de cadena son editables o no (para compilar código antiguo), y algunos pueden tener opciones para hacer que los literales de cadena se traten formalmente como matrices de const char (para una mejor captura de errores).

( énfasis mío )

Ver también Back to Basics por Joel .