内存分配的差异

时间:2018-01-08 14:58:29

标签: c memory allocation

我想知道是否有人可以解释ai*pai的内存分配之间的差异

int ai[10];
int *pai = (int * ) calloc (10, sizeof(int));

我理解第二个是动态分配但我很难解释原因。

5 个答案:

答案 0 :(得分:3)

让我们看看标准中指定的是什么(差异化)

来自7.22.3.1(在内存管理功能下)

  

...分配对象的生命周期从分配中扩展   直到解除分配。

所以是的,这是动态分配的内存。它们的寿命与局部变量的寿命不同。通过免费呼叫他们被解除分配。在那之前他们将活着。不依赖于创建它们的范围的生命周期。

第一个是自动存储持续时间。这是主要的区别。因此,在声明它的函数范围内,当它结束时,它的生命周期将结束。

也有人说有堆和堆栈 - 但是(un)幸运的是C标准没有提到它。它完全实现了C标准所期望的功能。实施可以是任何事情。所提出的差异对这类事物的影响最小。

作为概念性redpill(取自电影Matrixpai具有自动存储持续时间,但其包含的内存地址不是。执行定义它的函数时,变量pai将丢失。但它指出的记忆并没有。

为什么称为动态分配?

知道一件事 - 在编程中我们在语言环境中说dynamic - 这意味着我们在运行时做了一些事情。同样,我们在运行时通过调用malloccalloc等函数来分配一些内存。这就是动态分配的原因。

答案 1 :(得分:0)

数组ai在堆栈上分配,当到达函数末尾时,它隐式超出范围。指针pai 指向指向内存位置,该位置可以是指向的类型的数组或单个元素,内存在堆上分配,且必须为free d以后。第二个可以传递回函数末尾的函数调用者,甚至可以使用realloc调整大小(realloc不会像calloc那样清除新内存,{{ 1}}就像malloc而没有清零新内存)。第一种是快速数组计算,大部分时间都应该在缓存中。第二个是调用函数时未知的数组长度。当大小已知时,许多程序员倾向于在调用者中定义一个数组并将其传递给函数,该函数修改它。调用函数时,数组被隐式转换为指针。

某些库实现在全局部分中存储指向数组的指针,可以重新分配。或者它们在全球空间中具有固定长度的阵列。建议这些变量为calloc。用户不必关心其他库变量的内存管理。

<强> library.h

thread_local

<强> LIBRARY.C

const char* getResourceString(int id);

答案 2 :(得分:0)

一般来说,自动分配的对象将位于堆栈上,而动态分配的对象将位于上。虽然这种区别是实现(非标准)依赖,但堆栈和堆是在C程序中管理内存的最常用方法。它们基本上是两个不同的内存区域,第一个专用于自动分配第二个专用于动态分配。因此,当您调用函数(例如,main函数)时,在此函数范围内声明的所有对象将被堆叠(在堆栈中自动分配)。如果在此函数中发生了一些动态分配,则将在堆中分配内存,以便指向此区域的所有指针都将指向堆栈外部的对象。当您的函数返回时,堆栈中的所有对象也会自动取消堆叠,并且几乎不再存在。但是,在解除分配它们之前,堆中的所有对象都将存在(或者当程序结束时,它们将被OS强制释放)。 数组是可以自动或动态分配的结构。见这个例子:

int * automaticFactor() //wrong, see below
{
    int x[10];
    return &x[0];
}

int * dynamicFactor()
{
    int * y = (int *) malloc(sizeof(int) * 10);
    return &y[0];
}

int main()
{
    //this will not work because &x[0] points to the stack
    //and that area will be unstacked after the function return
    int * n = automaticFactor();

    //this will work because &y[0] points to the heap
    //and that area will be in the heap until manual deallocation
    int * m = dynamicFactor();

    return 0;
}

请注意,指针本身位于堆栈中。堆中的内容是它们指向的区域。因此,当您在函数内部声明一个指针(例如示例的 y )时,它也会在函数末尾被取消堆栈。但是由于它的值(即分配区域的地址)被返回到函数外部的指针(即 m ),因此您不会忘记函数在堆中分配的区域。

答案 3 :(得分:0)

在第一行中,您创建一个数组类型的变量,但符号ai是指向此变量的常量指针。

在第二行中,您创建一个指针类型变量。然后用calloc()动态分配一个数组,并将它的地址放在指针中。

答案 4 :(得分:0)

这些是完全不同的操作:

int ai[10];

声明一个10个整数的数组对象。如果它在块内声明,它将具有自动存储持续时间,这意味着它将在块结束时消失(标识符和数据)。如果它在任何块之外声明(在文件级别)它将具有静态存储持续时间并且将存在于所有程序中。

int *pai = calloc (10, sizeof(int));  // DON'T CAST MALLOC IN C

声明一个指向已分配的内存区域的指针,该区域可以包含十个整数。您可以使用pai作为指向数组第一个元素的指针,并在其上执行指针算术。但sizeof(pai)sizeof(int *)。该阵列将具有动态存储持续时间,这意味着它的生命将结束:

  • 如果已释放已分配的内存块
  • 如果它被重复用于存储其他对象

    double * pd = pai;
    for (int i=1; i<5; i++) {      // assuming sizeof(double) == 2 * sizeof(int) here
        pd[i] = i;                 // the allocated memory now contains 5 double
    }
    

因此,在这两种情况下,你可以使用标识符指向10个整数的数组,但第一个是整数数组对象,而第二个只是指向动态内存块的指针(没有声明类型的内存可以获取将在那里复制/创建的对象的类型。