结构和内存管理,C

Structures and memory management, C

我想了解一些关于结构和内存管理的事情。我有三个版本代码,其结果是相同的。它们仅在结构的 definition/allocation 上有所不同。在版本一中,结构分配有此代码:resultValue_t *resultVal = malloc(sizeof(resultValue_t));。在版本二中,结构是在函数内部创建的:resultValue_t resultVal;。在版本三中 resultValue_t resultVal; 是全局创建的。 请问这三个定义到底有什么区别?哪一个给出了哪些可能性?哪个更受欢迎? 我知道如果通过指针访问结构,则应使用 -> 运算符等。但在这里我对这些定义之间的差异和可能性感到好奇。

//version_1

typedef struct
{
    int valOne;
    int valTwo;
}resultValue_t;

void twoSum(int *array, int sum)
{
    int baseVal, tempSum;
    int arrLen = sizeof(array);
  
    resultValue_t *resultVal = malloc(sizeof(resultValue_t));
    
    //...
    if (tempSum == sum)
    {
        resultVal->valOne = array[index];
        resultVal->valTwo = array[nIndex];
        printf("%d + %d\n", resultVal->valOne, resultVal->valTwo);
    }
    //...

    free(resultVal);
}

//version_2

typedef struct
{
    int valOne;
    int valTwo;
}resultValue_t;

void twoSum2(int *array, int sum)
{
    int baseVal, tempSum;
    
    resultValue_t resultVal;
    
    //...
    if (tempSum == sum)
    {
        resultVal.valOne = array[index];
        resultVal.valTwo = array[nIndex];
        printf("%d + %d\n", resultVal.valOne, resultVal.valTwo);
    }
    //...
}

//version_3

typedef struct
{
    int valOne;
    int valTwo;
}resultValue_t;
resultValue_t resultVal;
  • 版本 1 从堆中分配内存。
  • 版本 2 从堆栈分配内存。
  • 版本 3 使用 bss 部分的内存(在我使用的每个编译器实现中,但它可能来自其他地方)。它也是唯一初始化对象的版本(在本例中为全零)。

区别在于“存储时长”,即对象的生命周期。

在版本 1 中使用“分配的存储持续时间”。这意味着对象 resultVal 存在于 malloc returns 之后,直到某些代码通过调用 free 显式“杀死它”。在大多数系统上,内存分配在称为堆的区域中。分配通常很慢(即,除非有充分的理由,否则不要使用它 - 稍后见)。

在版本 2 中使用“自动存储持续时间”。这意味着对象 resultVal 一直存在,直到相关块的执行结束。在这种情况下,直到函数 returns。换句话说 - 在这种情况下,对象 resultVal 在执行进入函数时自动创建,并在执行离开函数时自动销毁。 在大多数系统上,内存分配在称为堆栈的区域中。分配通常非常快。

在版本 3 中使用“静态存储持续时间”。这意味着对象 resultVal 从执行开始到执行结束都存在。因此可以在代码中的任何位置随时访问该对象。作为程序启动的一部分,内存通常分配在一些特殊区域,而且速度也非常快。

显然这 3 种类型都有用例。

通常应避免使用版本 3,但在某些特殊情况下静态对象是有意义的。使用时,通常最好使用关键字 static.

将它们的使用限制在“文件范围”

在大多数情况下,您应该选择版本 2,因为它既快速又安全。但是,如果对象的大小(在本例中 resultVal)非常大,由于堆栈溢出的风险,应避免使用版本 2。在那种情况下使用版本 1.

如果您希望对象在函数 returns 之后“存活”,版本 1 也很有用(实际上是必需的)。然而,问题中的示例并非如此,因为在离开函数之前调用了 free

结论:

因为 resultValue_t; 是一个相当小的对象类型,并且对象 resultVal 在函数调用后不需要“活着”,你应该选择版本 2。