使用 C 字符串给出警告:“与返回的局部变量相关的堆栈内存地址”

Posted

技术标签:

【中文标题】使用 C 字符串给出警告:“与返回的局部变量相关的堆栈内存地址”【英文标题】:Using C-string gives Warning: "Address of stack memory associated with local variable returned" 【发布时间】:2013-08-05 03:40:18 【问题描述】:

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

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

    return matches;

我收到此警告:

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

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

警告意味着什么?会不会有什么问题?

【问题讨论】:

您将地址返回到第一个字符指针,该指针分配在堆栈上,退出函数后不再存在。 【参考方案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;
    
    
    1234563 987654335@)。

【讨论】:

谢谢我知道了。最糟糕的是这是第二次遇到这种问题了:)无论如何,非常感谢您 假设是GNU readline,这会导致崩溃,因为readline会释放完成函数返回的内存。 @MatsPetersson 这看起来确实像 readline - 在这种情况下你是对的。我会支持你的答案! matches 声明为static 将在静态空间上分配空间,而不是在堆上。 第三个选项是调用 calloc 在堆中分配内存【参考方案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;

编辑:因此,如果库根据readline 接口需要char **,则使用此:

char** ReadLineImpl::my_completion ()

    char **matches = static_cast<char **>malloc(1 * sizeof(char *));
    matches[1] = "add";
    return matches;

问题解决了!

【讨论】:

我会使用向量作为 C++ 程序员,但库需要 char**,所以我必须转换为 char**。 因此,假设您使用的是readline 接口,那么您必须使用malloc 分配内存,因为readline 稍后会释放它。我会编辑。 好,只有一件事,我不得不使用 (char**)malloc(1 * sizeof(char *)) 但是谢谢,你的回答更好,虽然我不会改变【参考方案3】:

用堆代替栈

这种情况最好在堆中分配内存,方法是:

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

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

【讨论】:

【参考方案4】:

改变

char* matches[1];

char *matches = new matches[1];

【讨论】:

为什么?也许,你应该描述这样做的原因。

以上是关于使用 C 字符串给出警告:“与返回的局部变量相关的堆栈内存地址”的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用字符串初始化没有 const 的数组时 gcc 不给出警告?

为啥 gcc 给出警告:函数 qsort_r 的隐式声明?

为啥 nameof() 在 Linq 表达式中给出一个模棱两可的调用警告,但当我使用与字符串相同的值时却没有?

警告:mysqli_query() 至少需要 2 个参数,1 个在第 10 行的 C:\wamp64\www\OBJEPRO\dbcrud.php 中给出

为啥写作主要;在 C 中给出一个段错误

警告:mysql_num_rows() 期望参数 1 是资源,在第 189 行给出布尔值 [重复]