【问题标题】:Getting a dangling pointer by returning a pointer from a local C-style array通过从本地 C 样式数组返回指针来获取悬空指针
【发布时间】:2018-09-13 01:27:31
【问题描述】:

我对下面的代码有点困惑:

#include <iostream>

const char* f()
{
    const char* arr[]={"test"};
    return arr[0];
}

int main()
{
    auto x = f();
    std::cout << x;
}

在我看来,这段代码应该是 UB(未定义的行为)。我们返回一个指向本地范围内的 C 样式数组元素的指针。事情应该出错了。但是,我测试过的编译器都没有抱怨(我在 g++ 和 clang 上都使用了-Wall -Wextra -pedantic)。 valgrind 也不抱怨。

上面的代码是有效的还是像人们想象的那样是 UB?

PS:运行它似乎会产生“正确”的结果,即显示“测试”,但这并不表示正确性。

【问题讨论】:

  • FWIW 它在实践中“工作”的原因是常量字符串“test”被存储在可执行文件的静态数据区域中,因此即使在函数返回后字符串仍然有效。 (当然,语言规范是否保证它可以工作是另一个问题)
  • 问这些问题没有坏处,而且这个问题写得很好。 +1。
  • @JesperJuhl 我知道 UB 是什么,以及月球可能因此而爆炸的事实。我在问代码是否真的是UB。看起来不是。看起来很多人认为代码是 UB……所以我认为这个问题很有用。
  • @Bathsheba 看来我们还在学习 :) 确实代码 不是 UB
  • @vsoftco:没想到是这样,但需要像 Barry 这样的专家来指出原因。

标签: c++ pointers memory undefined-behavior


【解决方案1】:

不,这不是 UB。

这个:

const char* f()
{
    const char* arr[]={"test"};
    return arr[0];
}

可以改写成等价的:

const char* f()
{
    const char* arr0 = "test";
    return arr0;
}

所以我们只是返回一个本地指针,指向一个字符串文字。字符串文字有static storage duration,没有任何悬垂。功能真的是一样的:

const char* f()
{
    return "test";
}

如果你做了类似这个的事情:

const char* f() {
    const char arr[] = "test"; // local array of char, not array of char const*
    return arr;
}

现在 是 UB - 我们正在返回一个悬空指针。

【讨论】:

  • "字符串字面量具有静态存储持续时间" - 我知道所有的编译器都这样做;但在标准中,字符串文字必须具有静态持续时间吗?
  • @UKMonkey 是的,添加了参考。
  • 不要迂腐,但这并不是真正的“等效”。从功能上讲,在这种情况下,当然,但数组就是数组。 ;)
  • @LightnessRacesinOrbit,在这两种情况下,都有一个指向 const char 的本地指针,在这两种情况下,本地指针都被初始化为指向一个文字字符串,并且在这两种情况下都返回了它的值。唯一的区别是,在原始示例中,本地指针是单元素数组的成员,而在替代版本中,它是标量。那么,如果在某种意义上它们不是“等价的”呢?这里重要的不是局部变量的确切类型。重要的是字符串文字在函数返回后是否仍然有效。
  • C 还保证字符串文字具有静态存储持续时间,请参阅port70.net/~nsz/c/c11/n1570.html#6.4.5p6
【解决方案2】:

数组arr 具有本地存储持续时间,并将在范围结束时消失。然而,字符串文字"test" 是指向静态存储位置的指针。在返回之前将此指针临时存储在本地数组arr 中不会改变这一点。它始终是一个静态存储位置。

请注意,如果函数要返回 C++ 样式字符串类型而不是 C 样式 const char *,则根据 C++ 临时规则,额外的转换/簿记可能会使您的值在生命周期内受到限制。

【讨论】:

    猜你喜欢
    • 2012-10-02
    • 1970-01-01
    • 2011-03-08
    • 2014-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-13
    相关资源
    最近更新 更多