我不是C程序员,所以我对C字符串不太熟悉,但现在我必须使用C库,所以这里是我的代码的缩短版本来演示我的问题:
char** ReadLineImpl::my_completion () {
char* matches[1];
matches[0] = "add";
return matches;
}
我收到这个警告:
警告-与本地变量"matches"关联的堆栈内存地址返回
我的程序似乎无法正常工作(可能是因为上面提到的警告)。
这个警告意味着什么?它会引起什么问题吗?
变量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
和friends),并将所有权传递给调用方函数,调用方函数在不再需要时必须释放此空间(使用free
)。
返回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;
}
因此,如果库根据readline
接口需要char **
,则使用以下内容:
char** ReadLineImpl::my_completion ()
{
char **matches = static_cast<char **>malloc(1 * sizeof(char *));
matches[1] = "add";
return matches;
}
问题解决了!
使用堆而不是堆栈
最好在堆上为分配内存,这种情况下使用:
int* someDataForParams(void *_params) {
// ...
int* charCounts = (int*) calloc(96, sizeof(char*));
// ...
return charCounts;
}
96只是一个字符串长度(只是一个幻数)。
有两种解决方案:
第一种方法是使用关键字static
将变量声明为静态变量。
第二种解决方案是与malloc
或calloc
一起使用动态分配。