【问题标题】:C++ functions returning arraysC++ 函数返回数组
【发布时间】:2012-09-26 04:01:34
【问题描述】:

我对 C++ 有点陌生。我习惯用 Java 编程。这个特殊的问题给我带来了很大的问题,因为 C++ 在处理数组时不像 Java。在 C++ 中,数组只是指针。

但是为什么会出现这样的代码:

#include <iostream>
#define SIZE 3
using namespace std;

void printArray(int*, int);
int * getArray();
int ctr = 0;

int main() {
  int * array = getArray();

  cout << endl << "Verifying 2" << endl;
  for (ctr = 0; ctr < SIZE; ctr++)
    cout << array[ctr] << endl;

  printArray(array, SIZE);
  return 0;
}

int * getArray() {
  int a[] = {1, 2, 3};
  cout << endl << "Verifying 1" << endl;
  for (ctr = 0; ctr < SIZE; ctr++)
    cout << a[ctr] << endl;
  return a;
}

void printArray(int array[], int sizer) {
  cout << endl << "Verifying 3" << endl;
  int ctr = 0;
  for (ctr = 0; ctr < sizer; ctr++) {
    cout << array[ctr] << endl;
  }
}

为验证 2 和验证 3 打印任意值。也许这与数组真正作为指针处理的方式有关。

【问题讨论】:

  • 数组不是指针。无论如何,如果您想要 Java 之类的东西,请使用 std::array 之类的容器。
  • 至于随机打印,我看到的一件事是:stackoverflow.com/questions/6441218/…
  • 你返回的是一个指针,而不是一个数组。更糟糕的是,当getArray 返回时,它是一个不再存在的内存指针,因此尝试使用返回值会导致未定义的行为。
  • 阅读这篇文章,消除了我对数组与指针的混淆......c-faq.com/aryptr/aryptr2.html

标签: c++ arrays pointers return


【解决方案1】:

问题是不能返回本地数组:

int a[] = {1, 2, 3};
...
return a;

无效。您需要在返回之前将a 复制到动态内存中。目前,由于a 分配在自动 存储中,因此一旦函数返回,数组的内存就会被回收,从而使返回的值无效。 Java 没有同样的问题,因为包括数组在内的所有对象都是在动态存储中分配的。

更好的是,您应该避免使用数组来支持旨在替换它们的 C++ 类。在这种情况下,使用std::vector&lt;int&gt; 会是更好的选择。

【讨论】:

  • 我以为 C++ 没有垃圾收集器?还是这更像是一个范围/生命周期问题?
  • 这不是常规的垃圾收集。事实上,当一个方法返回时,堆栈中的空间包含未指定的内容,并且会在调用另一个函数时发生变化。
  • @Sam 这就是生命周期问题:您在自动存储中分配的变量(也称为“堆栈变量”)一旦超出范围就会变得无效。另一方面,动态存储中的数据可以比指向它的变量的范围更长。
  • 感谢您的解释。
【解决方案2】:

因为您的数组是堆栈分配的。从 Java 迁移到 C++,您必须非常小心对象的生命周期。在 Java 中,所有内容都是堆分配的,并且在没有对它的引用时进行垃圾收集。

然而,在这里,您定义了一个堆栈分配的数组 a,当您退出函数 getArray 时该数组被销毁。这是向量优于普通数组的(许多)原​​因之一——它们为您处理分配和释放。

#include <vector>

std::vector<int> getArray() 
{
    std::vector<int> a = {1, 2, 3};
    return a;
}

【讨论】:

    【解决方案3】:

    内存中有两个地方可以存放变量:栈和堆。堆栈包含在方法中创建的局部变量。堆在其他条件下保存其他变量,例如静态变量。

    当您在GetArray() 中创建a 时,它是存储在堆栈中的局部变量,a 是指向该位置的指针。当方法返回指针时,堆栈的该层被释放(包括指针指向的实际值)。

    相反,您需要动态分配数组,然后值将在函数返回时不会清除的堆中,a 将指向它们。

    int * GetArray() {
      int* a = new int[3];
      a[0] = 1;
      a[1] = 2;
      a[2] = 3;
      cout << endl << "Verifying 1" << endl;
      for (int ctr = 0; ctr < 3; ctr++)
        cout << a[ctr] << endl;
      return a;
    }
    

    现在您在函数之间传递这些整数的地址,而这些值都位于堆中,直到程序结束或(最好)您 delete 他们才释放它们。

    p>

    【讨论】:

    • C++ 是如何知道将什么放入堆中以及将什么放入堆栈。花括号符号不只是此处显示的按元素数组分配的显式元素的语法糖吗?
    • 根据内存的分配方式,有哪些去哪里的规则。花括号符号不是动态分配的,因此它进入堆栈。在编译时为数组设置空间。我所拥有的将在运行时分配该空间,并将内容存储在堆中。
    猜你喜欢
    • 2012-06-04
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-31
    • 2012-04-01
    • 1970-01-01
    相关资源
    最近更新 更多