使用 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 不给出警告?
为啥 nameof() 在 Linq 表达式中给出一个模棱两可的调用警告,但当我使用与字符串相同的值时却没有?
警告:mysqli_query() 至少需要 2 个参数,1 个在第 10 行的 C:\wamp64\www\OBJEPRO\dbcrud.php 中给出