Использование 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 - это просто длина строки (просто волшебное число)