web-dev-qa-db-fra.com

Using C-string: "Adresse de la mémoire de pile associée à la variable locale renvoyée"

Je ne suis pas un programmeur C, je ne connais donc pas très bien C-string, mais je dois maintenant utiliser une bibliothèque C. Voici donc une version abrégée de mon code pour illustrer mon problème: 

char** ReadLineImpl::my_completion () {

    char* matches[1];


    matches[0] = "add";

    return matches;

}

Je reçois un avertissement:

Avertissement - adresse de la mémoire de pile associée à la variable locale 'correspond' renvoyée

Et mon application ne semble pas fonctionner correctement (peut-être à cause de cet avertissement).

Quel est l'avertissement et va-t-il causer des problèmes?

19
khajvah

La variable char* matches[1]; est déclarée sur la pile et elle sera automatiquement libérée lorsque le bloc actuel sortira de la portée.

Cela signifie que lorsque vous renvoyez matches, la mémoire réservée à matches sera libérée et votre pointeur indiquera quelque chose que vous ne souhaitez pas.

Vous pouvez résoudre ce problème de nombreuses manières, et certaines d’entre elles sont:

  1. Déclarez matches[1] en tant que static: static char* matches[1]; - this Allouera de l'espace pour matches sur le tas (cela peut vous mordre si vous L'utilisez de manière inappropriée, car toutes les instances de la fonction my_completion .__ partageront la même variable matches.

  2. Allouez de l'espace dans la fonction appelant et transmettez-le à my_completion Function: my_completion(matches):

    char* matches[1];
    matches = my_completion(matches);
    
    // ...
    
    char** ReadLineImpl::my_completion (char** matches) {
         matches[0] = "add";
    
         return matches;
    }
    
  3. Allouez de l'espace dans la fonction appelée sur le tas (en utilisant malloc, calloc et amis) et transmettez la propriété à la fonction appelant, qui devra libérer cet espace lorsqu'elle n'est plus nécessaire (en utilisant free). 

30
Nemanja Boric

Lorsque vous renvoyez le tableau matches, vous retournez l'adresse du premier élément. Ceci est stocké sur la pile dans my_completion. Une fois que vous retournez de my_completion cette mémoire est récupérée et sera (très probablement) éventuellement réutilisée pour autre chose, écrasant les valeurs stockées dans matches - et oui, c'est peut-être pourquoi votre application ne fonctionne pas maintenant, ce sera probablement une fois que vous aurez corrigé un autre problème, ou que vous l'avez modifié un peu, ou autre chose, car il ne s'agit pas d'un de ces petits avertissements que vous pouvez ignorer en toute sécurité. 

Vous pouvez résoudre ce problème de différentes manières. La plus évidente consiste simplement à utiliser std::vector<char *> [ou encore mieux std::vector<std::string>]:

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

Edit: Donc, si la bibliothèque nécessite un char ** conformément à l'interface readline , utilisez ceci:

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

Problème résolu!

8
Mats Petersson

changement

char* matches[1];

à

char *matches = new matches[1];
0
Shammel Lee

Utilisez tas au lieu de pile

Il vaut mieux allouer de la mémoire dans le tas pour dans ce cas en utilisant:

int* someDataForParams(void *_params) {

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

    return charCounts;
}

96 est juste une longueur de chaîne (juste un nombre magique)

0
Mike Glukhov