Использование C-строки: "Адрес памяти стека, связанный с локальной переменной, возвращаемой"

Я не программист на C, поэтому я не знаком с C-строкой, но новичок должен использовать библиотеку C, поэтому здесь показана сокращенная версия моего кода, чтобы продемонстрировать мою проблему:

char** ReadLineImpl::my_completion () {

    char* matches[1];


    matches[0] = "add";

    return matches;

}

Я получаю предупреждение:

Предупреждение - адрес памяти стека, связанный с локальной переменной 'matches' return

И мое приложение не работает должным образом (возможно, из-за этого предупреждения).

Какое предупреждение и вызовет ли какие-либо проблемы?

Ответ 1

Переменная char* matches[1]; объявляется в стеке, и она будет автоматически выпущена, когда текущий блок выходит за пределы области.

Это означает, что при возврате matches память, зарезервированная для matches, будет освобождена, и ваш указатель укажет на то, что вы не хотите.

Вы можете решить это разными способами, а некоторые из них:

  • Объявите matches[1] как static: static char* matches[1]; - это выделит место для matches в куче (это может вас укусить, если вы используйте его ненадлежащим образом, так как все экземпляры функции my_completion будет иметь одну и ту же переменную matches).

  • Выделите пространство в функции вызывающего абонента и передайте его my_completion Функция: my_completion(matches):

    char* matches[1];
    matches = my_completion(matches);
    
    // ...
    
    char** ReadLineImpl::my_completion (char** matches) {
         matches[0] = "add";
    
         return matches;
    }
    
  • Выделите пространство в вызываемой функции в куче (используя malloc, calloc и друзей) и передайте право собственности на функцию вызывающего абонента, которая должна будет освободить это пространство, когда это не понадобится (используя free).

Ответ 2

Когда вы возвращаете массив matches, то, что вы возвращаете, является адресом первого элемента. Это сохраняется в стеке внутри my_completion. Как только вы вернетесь из my_completion, эта память будет восстановлена ​​и, скорее всего, будет повторно использована для чего-то другого, перезаписав значения, хранящиеся в matches, и да, это может быть причиной того, почему ваше приложение не работает - если оно сейчас не будет, возможно, это произойдет, если вы устраните некоторые другие проблемы или немного измените их, или что-то еще, потому что это не одно из тех маленьких предупреждений, которые можно смело игнорировать.

Вы можете исправить это несколькими способами. Наиболее очевидным является просто использовать std::vector<char *> [или еще лучше std::vector<std::string>]:

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

Изменить: Итак, если для библиотеки требуется char ** в соответствии с интерфейсом readline, используйте это:

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

Проблема решена!

Ответ 3

изменить

char* matches[1];

к

char *matches = new matches[1];

Ответ 4

Используйте кучу вместо стека

Лучше выделить память в куче для этого случая, используя:

int* someDataForParams(void *_params) {

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

    return charCounts;
}

96 - это просто длина строки (просто волшебное число)