C – ¿Error de segmentación con strcmp?

Parece que estoy obteniendo una falla de segmentación en algún lugar con la función strcmp. Todavía soy muy nuevo en C y no puedo ver por qué me da el error.

int linear_probe(htable h, char *item, int k){ int p; int step = 1; do { p = (k + step++) % h->capacity; }while(h->keys[p] != NULL && strcmp(h->keys[p], item) != 0); return p; } 

gdb:

 Program received signal SIGSEGV, Segmentation fault. 0x0000003a8e331856 in __strcmp_ssse3 () from /lib64/libc.so.6 (gdb) frame 1 #1 0x0000000000400ea6 in linear_probe (h=0x603010, item=0x7fffffffde00 "ksjojf", k=-1122175319) at htable.c:52 

Editar: código de inserción y estructura htable

 int htable_insert(htable h, char *item){ unsigned int k = htable_word_to_int(item); int p = k % h->capacity; if(NULL == h->keys[p]){ h->keys[p] = (char *)malloc(strlen(item)+1); strcpy(h->keys[p], item); h->freqs[p] = 1; h->num_keys++; return 1; } if(strcmp(h->keys[p], item) == 0){ return ++h->freqs[p]; } if(h->num_keys == h->capacity){ return 0; } if(h->method == LINEAR_P) p = linear_probe(h, item, k); else p = double_hash(h, item, k); if(NULL == h->keys[p]){ h->keys[p] = (char *)malloc(strlen(item)+1); strcpy(h->keys[p], item); h->freqs[p] = 1; h->num_keys++; return 1; }else if(strcmp(h->keys[p], item) == 0){ return ++h->freqs[p]; } return 0; } 

  struct htablerec{ int num_keys; int capacity; int *stats; char **keys; int *freqs; hashing_t method; }; 

Gracias

Editar: valgrind – me ingresa valores aleatorios para agregar a la tabla

 sdkgj fgijdfh dfkgjgg jdf kdjfg ==25643== Conditional jump or move depends on uninitialised value(s) ==25643== at 0x40107E: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== fdkjb kjdfg kdfg nfdg lkdfg oijfd kjsf vmf kjdf kjsfg fjgd fgkjfg ==25643== Invalid read of size 8 ==25643== at 0x400E0E: linear_probe (htable.c:51) ==25643== by 0x401095: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== Address 0x4c342a0 is not stack'd, malloc'd or (recently) free'd ==25643== ==25643== Invalid read of size 8 ==25643== at 0x400E2B: linear_probe (htable.c:51) ==25643== by 0x401095: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== Address 0x4c342a0 is not stack'd, malloc'd or (recently) free'd ==25643== ==25643== Invalid read of size 1 ==25643== at 0x4A06C51: strcmp (mc_replace_strmem.c:426) ==25643== by 0x400E3C: linear_probe (htable.c:51) ==25643== by 0x401095: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== Address 0x210 is not stack'd, malloc'd or (recently) free'd ==25643== ==25643== ==25643== Process terminating with default action of signal 11 (SIGSEGV) ==25643== Access not within mapped region at address 0x210 ==25643== at 0x4A06C51: strcmp (mc_replace_strmem.c:426) ==25643== by 0x400E3C: linear_probe (htable.c:51) ==25643== by 0x401095: htable_insert (htable.c:87) ==25643== by 0x400AB7: main (main.c:75) ==25643== If you believe this happened as a result of a stack ==25643== overflow in your program's main thread (unlikely but ==25643== possible), you can try to increase the size of the ==25643== main thread stack using the --main-stacksize= flag. ==25643== The main thread stack size used in this run was 8388608. ==25643== ==25643== HEAP SUMMARY: ==25643== in use at exit: 1,982 bytes in 28 blocks ==25643== total heap usage: 28 allocs, 0 frees, 1,982 bytes allocated ==25643== ==25643== LEAK SUMMARY: ==25643== definitely lost: 0 bytes in 0 blocks ==25643== indirectly lost: 0 bytes in 0 blocks ==25643== possibly lost: 0 bytes in 0 blocks ==25643== still reachable: 1,982 bytes in 28 blocks ==25643== suppressed: 0 bytes in 0 blocks ==25643== Rerun with --leak-check=full to see details of leaked memory ==25643== ==25643== For counts of detected and suppressed errors, rerun with: -v ==25643== Use --track-origins=yes to see where uninitialised values come from ==25643== ERROR SUMMARY: 7 errors from 4 contexts (suppressed: 6 from 6) Segmentation fault (core dumped) 

 static unsigned int htable_word_to_int(char *word){ unsigned int result = 0; while(*word != '\0'){ result = (*word++ + 31 * result); } return result; } 

    Aparte de la posibilidad de que los valores en su htable puedan ser punteros no válidos (es decir, ni NULL ni un puntero a una cadena C decente), tiene un serio problema de encontrar un bucle infinito si no contiene ni un NULL ni la cadena que ‘ que estas buscando.

    Para el problema inmediato, intente cambiar el código a:

     #define FLUSH fflush (stdout); fsync (fileno (stdout)) int linear_probe (htable h, char *item, int k) { int pos = k; do { pos = (pos + 1) % h->capacity; printf ("========\n"); FLUSH; printf ("inpk: %d\n", k); FLUSH; printf ("posn: %d\n", pos); FLUSH; printf ("cpct: %d\n", h->capacity); FLUSH; printf ("keyp: %p\n", h->keys[pos]); FLUSH; printf ("keys: '%s'\n", h->keys[pos]); FLUSH; printf ("item: '%s'\n", item); FLUSH; printf ("========\n"); FLUSH; } while ((pos != k) && (h->keys[pos] != NULL) && (strcmp (h->keys[pos], item) != 0)); return pos; } 

    Esas declaraciones de depuración deberían darte una indicación de lo que está pasando mal.


    Ya que estás obteniendo:

     inpk: -2055051140 posn: -30 cpct: 113 keyp: 0x100000001 

    justo antes del accidente, es evidente que alguien está transmitiendo un valor falso para k . La operación de módulo en números negativos es implementación definida en el estándar C, por lo que también obtiene un valor negativo para pos . Y como h->pos[-30] va a ser un comportamiento indefinido, todas las apuestas están desactivadas.

    Busque o corrija el código que pasa en ese valor falso (probablemente una variable no inicializada) o proteja su función cambiando:

     int pos = k; 

    dentro:

     int pos; if ((k < 0) || (k >= h->capacity)) k = 0; pos = k; 

    al comienzo de tu función. En realidad, haría ambas cosas, pero luego estoy bastante paranoico 🙂


    Y, en base a otra actualización (el cálculo de la clave hash, si genera una unsigned int y luego usa ciegamente eso como una int firmada, tiene buenas posibilidades de obtener valores negativos:

     #include  int main (void) { unsigned int x = 0xffff0000U; int y = x; printf ("%u %d\n", x, y); return(0); } 

    Esto produce:

     4294901760 -65536 

    Mi sugerencia es usar enteros sin signo para valores que están claramente destinados a ser unsigned.

    Si estás en linux, prueba valgrind. Puede informarle sobre accesos no válidos, memory leaks, variables no inicializadas, etc. La salida puede parecer desordenada y difícil de leer, pero si sigue intentándolo, lo recompensará. Que esta pasando:

    1. comstack tu progtwig con el -g para incluir información de depuración
    2. ejecutar el progtwig usando valgrind: valgrind ./myprogram
    3. beneficio al leer la salida

    Como dije, la salida puede parecer muy desordenada, así que tal vez primero intente un progtwig simple (principal vacío simple) para ver cómo se ve cuando todo está bien, luego intente bloquear su progtwig deliberadamente, como:

     int *bullet = 0; *bullet = 123; 

    y ver la salida.


    Una buena introducción básica con ejemplos se puede encontrar aquí .


    A medida que proporcionó la salida de Valgrind, comenzaría a solucionar los problemas allí enumerados. Primero, el Conditional jump or move depends on uninitialised value(s) error de los Conditional jump or move depends on uninitialised value(s) . Puede volver a ejecutar valgrind con --track-origins=yes ya que valgrind sugiere ver más detalles, luego arreglarlo (no tiene números de línea en los fragmentos de código, no puedo ayudarlo más).

     ./valgrind --track-origins=yes ./myprogram #don't switch parameters! 

    Luego, el Invalid read of size 1 significa que ya estás accediendo a la memoria que no es tuya, pero leyéndola solo, por lo que “no te importa”. Pero sigue siendo un error que no debería ocurrir, por lo tanto, corríjalo (si no lo soluciona la primera corrección de error).

    Y finalmente, el Access not within mapped region es una escritura en la memoria que no está asignada.

    Ahora intente corregir los errores (en el orden valgrind los enumera) siguiendo las sugerencias valgrind (como volver a ejecutarlo con los interruptores).

    bien, no incluiste el código alrededor de htable alrededor de llenar esta tabla hash, etc. strcmp probablemente segfaulted porque o le diste una cadena NULL o una matriz de caracteres que no termina correctamente con un 0 ….

    ¿Las teclas h-> están completamente inicializadas con NULLs? De lo contrario, tienes punteros aleatorios dentro.

    Por cierto,

     h->keys[p] = (char *)malloc(strlen(item)+1); strcpy(h->keys[p], item); 

    Siempre verifique la validez de la devolución de una función si indica un error, sin importar cuán improbable sea el caso de error. malloc() devuelve NULL en caso de error.

    A primera vista, supongo que tu segfault proviene de p ; nunca estás inicializando esa variable, por lo que no se garantiza que comience en cero; podría comenzar en -123456 por todo lo que sabe, y luego estaría accediendo a una dirección de memoria no válida. EDITAR: leer mal el ciclo do-while. Ignora este párrafo.

    En un segundo vistazo, verificaría si h->keys[p] es una cadena terminada en nulo – strcmp continúa leyendo los valores hasta que llega a un byte cero; si no existe dicho byte, puede seguir funcionando hasta que llegue a una dirección de memoria no válida.