范围、数组和堆

Posted

技术标签:

【中文标题】范围、数组和堆【英文标题】:Scope, arrays, and the heap 【发布时间】:2009-07-10 06:26:23 【问题描述】:

所以,我有这个数组。它需要在此函数范围之外访问。我一直在将指向它的指针拍成一对,然后放入双端队列。但是一旦我超出了作用域,本地堆栈就消失了,数组无效了,我只是得到了一个无用的指针,对吧?

所以我试图把这个数组放到超越范围的堆上,它会一直保留在那里,直到我以后删除它。但我在让这个工作时遇到问题。现在 g++ 正在吐出关于从 'int' 到 'int*' 的无效转换的错误。

void randomFunction(int x, int y, int width, int height)

  int **blah[4] = x, y, width, height;
  std::pair <foobar*, int* > tempPair (foobar1, blah);
  randomDeque.push_front(tempPair);

我也试过这样初始化它:

int *blah[4] = new int[4];

...它说数组必须用大括号括起来的初始化程序进行初始化。

我真的不习惯使用指针。我做错了什么?

【问题讨论】:

【参考方案1】:

有两个问题。首先,确实,您对指针/数组感到困惑:

int a[4]; // this is an array of 4 integers, a is the name of the array
int *a[4]; // This is an array of 4 *pointers* to int

所以你的声明:

int **blah[4];

定义一个由 4 个指向指针数组的指针组成的数组。也许你对以下事实感到困惑(我知道我在学习 C 时就是这样)。如果你声明一个变量:

int *a;

这是一个指向整数的指针的声明。但是如果你有一个变量 a 是一个指针,你可以使用 *a 得到它指向的东西(这里是一个整数):

*a = 1; // a is a pointer (i.e. an address), *a is the value pointed to by a.

所以 * in 声明用于声明指针,而 * in 语句用于引用值。

但是您的第二个问题与指针本身无关。它是关于资源管理(内存是一个,但文件,锁是其他)。当超出范围时,在堆栈上分配的任何内容都不再存在。在纯 C 中,您实际上只有一个解决方案:使用 malloc 在堆上分配,然后确保释放。所以你会做这样的事情:

// foo is a struct
foo *init_foo()

    foo* tmp;
    tmp = malloc(sizeof(*tmp));
    // initialize tmp

    return tmp;

然后,您将使用另一个功能对其进行清理:

foo *a;
a = init_foo();
// do stuff
clean_foo(a);

示例:FILE* 句柄和 fopen/fclose(除了分配东西,还有一些与操作系统相关的东西来处理文件)。另一种解决方案是使用 alloca,它不是标准 C,但被许多工具链支持。

在 C++ 中,您可以使用智能指针,例如使用引用计数来进行资源管理。我对 C++ 不太熟悉,我相信人们会参与其中。引用计数的想法是它仍然具有自动指针的一些优点(您不必自己调用 delete,这对于不平凡的项目非常容易出错),但不是纯粹基于范围的。一种基于引用计数的智能指针是 boost 中的 shared_ptr。

【讨论】:

【参考方案2】:

整个概念对我来说看起来很奇怪。如果您在堆栈上声明数组,它将不存在于您的函数范围之外。如果您使用“新”分配它 - 请确保在某个时候“删除”它,否则会导致 内存泄漏! 带有“新”的正确代码是:

int *blah = new int[4];
...
// don't forget to:
delete [] blah;

【讨论】:

【参考方案3】:

我不确定我是否做对了你想做的事,但如果你想返回一个在 randomFunction 返回后有效的 int 数组的引用,那么使用 Boost 是一个好方法:

#include <boost/shared_ptr.hpp>
#include <vector>

boost::shared_ptr<std::vector<int> > randomFunction(int x, int y, int width, int height)

  boost::shared_ptr<std::vector<int> > blahPtr(new std::vector<int>(4));
  (*blahPtr)[0] = x;
  (*blahPtr)[1] = y;
  (*blahPtr)[2] = width;
  (*blahPtr)[3] = height;
  return blahPtr;

您不必记住 deleteing blahPtr -- 当它的所有副本超出范围时,Boost 将自动删除您的 std::vector 对象,并且 C++ 标准库将删除底层数组。

【讨论】:

【参考方案4】:

看起来你想要一个 4x4 数组,在这种情况下你应该像这样创建它(我头脑中的未经测试的代码):

int **blah = new int* [4];
for(int i = 0; i < 4; ++i)

    *blah[i] = new int[4];

或者,您可以创建一维数组并将其视为二维数组:

int *blah = new int[16];
#define ELEM(x,y) w*4+h
blah[ELEM(1,1)] = 123;

【讨论】:

您突出显示代码,然后按 ctrl-k 或 代码示例 按钮来格式化它。 谢谢尼克 我很着急,找不到明显的方法 但是...我不想要 4x4 数组。 ;-) 对不起,我假设你这样做了,因为你使用的是 ** ;)

以上是关于范围、数组和堆的主要内容,如果未能解决你的问题,请参考以下文章

关于数组和堆的常见算法

在java中初始化数组时的堆栈和堆内存[重复]

c_cpp 使用在堆栈上声明的数组(int myArray [3])和堆上的数组(int * myArray = new int [size]

浅析JAVA中栈内存和堆内存

堆和堆排序

堆和堆排序