51

我不是 C 程序员,所以我对 C 字符串不太熟悉,但现在我必须使用 C 库,所以这里是我的代码的缩短版本来演示我的问题:

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

    return matches;
}

我收到此警告:

警告 - 返回与局部变量“匹配”相关的堆栈内存地址

而且我的程序似乎无法正常工作(可能是因为上面提到的警告)。

警告意味着什么?它会引起任何问题吗?

4

5 回答 5

71

变量char* matches[1];在堆栈上声明,当当前块超出范围时,它会自动释放。

这意味着当您返回时matches,保留的内存matches将被释放,并且您的指针将指向您不想要的东西。

您可以通过多种方式解决此问题,其中一些是:

  1. 声明matches[1]staticstatic char* matches[1];- 这将matches在静态空间中分配空间,而不是在堆栈上(如果您使用不当,这可能会咬到您,因为所有my_completion函数实例都将共享相同的matches变量)。

  2. 在调用函数中分配空间并将其传递给my_completion 函数my_completion(matches)::

    char* matches[1];
    matches = my_completion(matches);
    
    // ...
    
    char** ReadLineImpl::my_completion (char** matches) {
         matches[0] = "add";
    
         return matches;
    }
    
  3. 在堆上的被调用函数中分配空间(使用malloccalloc和朋友)并将所有权传递给调用者函数,当不再需要时(使用free)必须释放该空间。

于 2013-08-04T08:27:32.423 回答
11

返回matches数组时,返回的是第一个元素的地址。这是存储在堆栈里面的my_completion。一旦您从my_completion该内存返回,将被回收并且(很可能)最终将被重用于其他东西,覆盖存储在其中的值matches- 是的,这很可能是您的应用程序无法工作的原因 - 如果不是现在,可能会在您修复了一些其他问题,或对其进行了一些更改或其他一些事情之后,因为这不是您可以安全忽略的那些小警告之一。

您可以通过几种不同的方式解决此问题。最明显的是简单地使用std::vector<char *>[or better yet 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;
}

问题解决了!

于 2013-08-04T08:31:12.790 回答
0

使用堆而不是堆栈

在这种情况下,最好使用以下方法在堆中分配内存:

int* someDataForParams(void *_params) {
    
    ...
    int* charCounts = (int*) calloc(96, sizeof(char*));
    ...
    
    return charCounts;
}

96 只是一个字符串长度(只是一个幻数)

于 2016-08-29T11:05:55.537 回答
0

有两个解决方案:第一个是使用关键字将变量声明为静态变量, static 第二个解决方案是使用动态分配malloccalloc

于 2022-01-24T16:29:20.550 回答
-2

改变

char* matches[1];

char *matches = new matches[1];
于 2015-04-26T00:59:32.593 回答