【问题标题】:Returning Pointer from a Function in C++从 C++ 中的函数返回指针
【发布时间】:2012-01-23 09:15:27
【问题描述】:

当我从函数返回指针时,它的值可以单独访问。但是,当使用循环输出该指针变量的值时,会显示错误的值。我在哪里犯错误,无法弄清楚。

#include <iostream>
#include <conio.h>

int *cal(int *, int*);

using namespace std;

int main()
{
    int a[]={5,6,7,8,9};
    int b[]={0,3,5,2,1};
    int *c;
    c=cal(a,b);

    //Wrong outpur here
    /*for(int i=0;i<5;i++)
    {
        cout<<*(c+i);
    }*/

    //Correct output here
    cout<<*(c+0);
    cout<<*(c+1);
    cout<<*(c+2);
    cout<<*(c+3);
    cout<<*(c+4);

return 0;
}   

int *cal(int *d, int *e)
{
    int k[5];
    for(int j=0;j<5;j++)
    {
        *(k+j)=*(d+j)-*(e+j);
    }
    return k;
}

【问题讨论】:

  • 打开编译器警告,然后阅读它们。
  • 很少有(如果有的话)需要从函数返回指针的情况。以我的经验,返回指针的需求通常源于有缺陷的程序设计。大多数情况下,您会通过其中一个参数返回结果,并让调用者担心在哪里分配数据。
  • @Lundin 有一些值得注意的例外(例如,查找函数可能会失败)。另一方面,只有在绝对必要时才应使用通过其中一个参数返回,当分析器说您别无选择时。大多数时候,正确的解决方案是按值返回。当然,这意味着不使用 C 样式数组(但总的来说这是一个很好的建议)。
  • @Lundin 在 C 中,当然,您的选择要少得多。从历史上看,C 程序会使kcal 中成为静态的。这在他的精确示例中会起作用,但否则会导致“令人惊讶”的行为永无止境。尽管如此,每当标准 C 库必须返回一个指针时,它就是这样做的。

标签: c++ arrays pointers


【解决方案1】:

您正在返回一个指向局部变量的指针。

k 在堆栈上创建。当cal() 退出时,堆栈被展开并且内存被释放。之后引用该内存会导致未定义的行为(如此处精美的解释:https://stackoverflow.com/a/6445794/78845)。

您的 C++ 编译器应该对此发出警告,并且您应该注意这些警告。

对于它的价值,这是我在 C++ 中实现它的方法:

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>

int main()
{
    int a[] = {5, 6, 7, 8, 9};
    int b[] = {0, 3, 5, 2, 1};
    int c[5];
    std::transform (a, a + 5, b, c, std::minus<int>());
    std::copy(c, c + 5, std::ostream_iterator<int>(std::cout, ", "));
}

See it run!

【讨论】:

  • @PoweRoy:不应该“可能”被摧毁吗?它不能保证被摧毁,是吗?这肯定是非法访问...
  • @another.anon.coward:它将被销毁,否则 RAII 将无法工作。无法保证是否有其他任何东西使用该内存。
  • @Johnsyweb:感谢您提供的信息!
【解决方案2】:

int k[5] 数组在堆栈上创建。因此,当它从cal 返回超出范围时,它会被销毁。您可以使用第三个参数作为输出数组:

void cal(int *d, int *e, int* k)
{
    for(int j=0;j<5;j++)
    {
        *(k+j)=*(d+j)-*(e+j);
    }
}

像这样拨打cal

int a[]={5,6,7,8,9};
int b[]={0,3,5,2,1};
int c[5];
cal (a, b, c); // after returning from cal, c will be populated with desired values

【讨论】:

  • 您在 void 返回函数中返回一个值! :)
  • 你还在玩原始指针,没必要这么做!
  • @Johnsyweb 我知道这里不需要使用指针。但是如果提问者想使用指针,这就是要走的路:)
  • 也许 OP 想要使用指针,因为不知道有其他方法。我喜欢this Meta answer 中的建议。
【解决方案3】:

正如其他人所指出的,您正在返回一个指向本地的指针 变量,这是未定义的行为。然而,真正的问题是 您需要返回一个数组,而 C 样式的数组已损坏。 用std::vector&lt;int&gt; 替换你的数组,忘记指针 (因为您正在处理值),并且代码将起作用。

【讨论】:

  • std::vector(甚至 valarray)在这里并不是真正需要的,但你是对的,不需要指针。
  • @Johnsyweb 对于他的特定示例,std::vector&lt;int&gt; 是显而易见且正确的解决方案。
  • 在带有初始值列表的 C++11 中,我可能同意你的观点,但“正确”是主观的。例如,我认为my answer 中提供的代码是“正确的” mut 没有使用标准库中的容器。
  • @Johnsyweb 同意(尽管我会使用 std::beginstd::end)。只要不涉及获取或返回数组的函数(仅迭代器),就可以了。 (或者可能不会:在std::vector&lt;int&gt; 中使用back_inserter 可以避免任何错过目标数组大小的风险。)
  • @Johnsyweb 在 C++11 之前,您将使用个人工具包中的 begin()end()。这些不是 C++11 发明的;它只是标准化了每个人已经在做的事情。
猜你喜欢
  • 2010-12-25
  • 1970-01-01
  • 2015-08-05
  • 1970-01-01
  • 2015-08-07
  • 2016-06-10
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
相关资源
最近更新 更多