4

为什么要在堆上拥有一个数组?我的教授给了我们两个理由:

  1. 将数组传递给函数,而不是传递副本
  2. 使数组超出范围

不能通过以下方式解决这两个问题:

  1. 将指针传递给堆栈上的数组
  2. 返回数组的值而不是数组本身(即使用复制构造函数)

有人可以给我一个必须在堆中使用数组的例子吗?

4

6 回答 6

4

堆中的数组用于延长函数的作用域。仅当您不想稍后在前一个(上层)调用者中使用它时,将指针传递到堆栈上的数组才有效。并且不能从函数返回数组,可以返回指向数组的指针,但是如果分配在栈中,函数返回后会指向无效的内存位置。

第一个原因是错误的:数组永远不会通过副本传递。当您调用函数时,数组名称总是衰减为指向其第一个元素的指针,正是为了避免复制整个数组。如果要通过副本传递数组,则必须将其嵌入到 a 中struct并改为传递 a struct

如果您事先不知道数组的大小,动态数组分配也很有用(尽管在 C99 引入可变长度数组之后这不是真的 - 但仍然,可变长度数组分配在堆栈上,所以你会有相同的问题)。

使用堆分配的另一个好理由是,对于非常大的数组,您很容易耗尽堆栈内存。堆通常较大。

于 2013-11-05T19:37:44.737 回答
1

An array in C is represented as a pointer that references the location of the array data (it points to the first item in the array). In the case of stack-based arrays, the array pointer and data are in the same location. In the case of heap-allocated arrays, the array pointer is on the stack and points to the location on the heap where the array data begins.

For point (2), you cannot return the value of the array. What is returned instead is the location of the array in memory or on the stack. Thus, allocating it on the heap ensures that the data is preserved when returning the array from a function.

A std::vector on the other hand works functionally like an array. With this, the array data is allocated on the heap, but the object that manages the array is on the stack. Thus, the lifetime of the array is controlled by the lifetime of the vector object.

The std::vector has the behaviour you describe:

  1. passing a vector by value to a function causes the data to be copied when passing it to the function;

  2. the vector data only lives for the lifetime of the function.

Passing the vector from a function can cause the array data to be copied. However, this can be optimised using things like return value optimisation and R-value references, which avoid the copy.

于 2013-11-05T19:37:55.373 回答
0

如果此代码运行时没有崩溃,您可以在堆栈上分配所有数组。

#include <string.h>
int main() {
    volatile char buf[1024 * 1024 * 64];
    memset(buf, 0, sizeof(buf));
}
于 2013-11-05T19:43:27.470 回答
0

除非您需要让数组超出声明和初始化它的函数的范围,否则编译器可以进行一些优化,这些优化很可能最终会比程序员可以猜到的效率更高。除非您有时间进行基准测试和试验,并且您的应用程序对性能至关重要,否则请将优化留给编译器。

于 2013-11-05T19:43:38.440 回答
0
#include <assert.h>
#include <stdlib.h>

int * f(int* array) {
    assert(array[0] == 1); // OK

    int static_array[] = {1, 2, 3};
    //return static_array = {1, 2, 3}; //BAD: only lives in this function

    int * dynamic_array = malloc(sizeof(int) * 2);
    dynamic_array[0] = 1;
    dynamic_array[1] = 2;
    return dynamic_array; // OK: lives outside also
}

int main()
{
    int static_array[] = {1, 2, 3};
    int * returned_array;
    returned_array = f(static_array);
    assert(returned_array[0] == 1);
    free(returned_array);
}
于 2013-11-05T19:40:18.177 回答
0

您希望在堆而不是堆栈上分配数组的原因:

  1. 数组很大
  2. 数组的生命周期超出了任何一个函数的范围;
  3. 数组大小在编译时是未知的,VLA要么不可用,要么不能在特定情况下使用(例如,不能声明 VLAstatic或在文件范围内);
  4. 该数组旨在调整大小。
于 2013-11-05T21:45:48.550 回答