El uso de una cadena C da una advertencia: “Se devolvió la dirección de la memoria de pila asociada con la variable local”

4 minutos de lectura

avatar de usuario de khajvah
jajvah

No soy un programador de C, por lo que no estoy tan familiarizado con C-string, pero ahora tengo que usar una biblioteca de C, así que aquí hay una versión abreviada de mi código para demostrar mi problema:

char** ReadLineImpl::my_completion () {
    char* matches[1];
    matches[0] = "add";

    return matches;
}

Recibo esta advertencia:

Advertencia: se devolvió la dirección de la memoria de pila asociada con la variable local ‘coincidencias’

Y mi programa no parece funcionar correctamente (puede deberse a la advertencia mencionada anteriormente).

¿Qué implica la advertencia? ¿Y dará algún problema?

  • Está devolviendo la dirección al primer puntero de carácter que se asigna en la pila y que deja de existir después de salir de la función.

    – Uchia Itachi

    4 de agosto de 2013 a las 8:27

  • Posible duplicado: C++ Devolviendo la referencia a la variable local

    -Peter Mortensen

    22 oct a las 5:00


Avatar de usuario de Nemanja Boric
nemanja bórico

Variable char* matches[1]; se declara en la pila y se liberará automáticamente cuando el bloque actual quede fuera del alcance.

Esto significa que cuando regrese matchesmemoria reservada para matches se liberará y su puntero apuntará a algo que no desea.

Puedes solucionar esto de muchas maneras, y algunas de ellas son:

  1. Declarar matches[1] como static: static char* matches[1]; – esto asignará espacio para matches en el espacio estático y no en la pila (esto puede morderlo si lo usa de manera inapropiada, ya que todas las instancias del my_completion la función compartirá la misma matches variable).

  2. Asigne espacio en la función de llamada y páselo al my_completion función: my_completion(matches):

    char* matches[1];
    matches = my_completion(matches);
    
    // ...
    
    char** ReadLineImpl::my_completion (char** matches) {
         matches[0] = "add";
    
         return matches;
    }
    
  3. Asigne espacio en la función llamada en el montón (usando malloc, callocy amigos) y pasar la propiedad a la función de llamada, que tendrá que desasignar este espacio cuando ya no se necesite (usando free).

  • Gracias lo tengo. Lo peor es que es la segunda vez que tengo este tipo de problema 🙂 de todos modos, muchas gracias

    – khajvah

    4 de agosto de 2013 a las 8:29

  • Suponiendo que es el GNU readlineesto provocará un bloqueo, ya que readline liberará la memoria devuelta por la función de finalización.

    – Mats Peterson

    4 de agosto de 2013 a las 8:49

  • @MatsPetersson Esto parece una línea de lectura, y en ese caso tiene razón. ¡Votaré tu respuesta!

    – Nemanja Boric

    4 de agosto de 2013 a las 9:02

  • declarando matches como static asignará espacio en el espacio estático, no en el montón.

    – MUCHAS LLAVE

    4 de agosto de 2013 a las 9:32

  • La tercera opción es asignar memoria en el montón llamando a calloc

    – Mike Glujov

    29 de agosto de 2016 a las 11:03


Avatar de usuario de Mats Petersson
esteras petersson

Cuando devuelves el matches matriz, está devolviendo la dirección del primer elemento. Esto se almacena en la pila dentro my_completion.

Una vez que regreses de my_completion esa memoria se recupera y (lo más probable) eventualmente se reutilizará para otra cosa, sobrescribiendo los valores almacenados en matches – y sí, esa puede ser la razón por la que su aplicación no funciona – si no funciona ahora, probablemente lo hará una vez que haya solucionado otros problemas, o la haya cambiado un poco, o algo más, porque esto no es una de esas pequeñas advertencias que puedes ignorar con seguridad.

Puedes arreglar esto de diferentes maneras. La más obvia es simplemente usar std::vector<char *> [or better yet std::vector<std::string>] en cambio:

std::vector<std::string> ReadLineImpl::my_completion ()
{
    std::vector<std::string> strings;
    strings.push_back("add");
    return strings;
}

Entonces, si la biblioteca requiere un char ** según el readline interfaz, luego use esto:

char** ReadLineImpl::my_completion ()
{
    char **matches = static_cast<char **>malloc(1 * sizeof(char *));
    matches[1] = "add";
    return matches;
}

¡Problema resuelto!

  • Usaría un vector como programador de C++, pero la biblioteca exige char**, así que tengo que convertirlo a char**.

    – khajvah

    4 de agosto de 2013 a las 8:32


  • Entonces, asumiendo que estás usando el readline interfaz, entonces DEBE asignar la memoria con malloc, como readline lo libera más tarde. voy a editar

    – Mats Peterson

    4 de agosto de 2013 a las 8:46

  • Bien, solo una cosa, tuve que usar (char**)malloc(1 * sizeof(char *)) pero gracias, tu respuesta es mejor, aunque no voy a cambiar

    – khajvah

    4 de agosto de 2013 a las 8:54

Avatar de usuario de Mike Glukhov
mike glujov

Usar el montón en lugar de la pila

Es mejor asignar memoria en el montón para este caso mediante el uso:

int* someDataForParams(void *_params) {

    // ...

    int* charCounts = (int*) calloc(96, sizeof(char*));

    // ...

    return charCounts;
}

96 es solo una longitud de cadena (solo un número mágico).

avatar de usuario de thiere18
thiere18

Hay dos soluciones:

La primera es declarar la variable como variable estática con la palabra clave static.

Y la segunda solución es usar la asignación dinámica con malloc o calloc.

¿Ha sido útil esta solución?