Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 何时/何地分配本地阵列?_C_Arrays_Gcc_Memory - Fatal编程技术网

C 何时/何地分配本地阵列?

C 何时/何地分配本地阵列?,c,arrays,gcc,memory,C,Arrays,Gcc,Memory,描述局部变量的自动分配。我知道局部变量通常是在堆栈上分配的。我可以想象如何在堆栈上分配int;只要推动它的价值。但是如何分配阵列呢 例如,如果您声明一个数组charstr[10],这10个字节的空间是放在堆栈上,还是分配到其他地方,只有str指针被推送到堆栈?如果是后者,10字节的空间分配在哪里 此外,包括数组在内的局部变量究竟是何时分配的?我通常将堆分配称为“动态分配”,这意味着不会动态分配自动变量。但自动变量可能在控制结构和函数体流中声明,因此编译器在运行前不可能确切知道自动变量将占用多少空

描述局部变量的自动分配。我知道局部变量通常是在堆栈上分配的。我可以想象如何在堆栈上分配
int
;只要推动它的价值。但是如何分配阵列呢

例如,如果您声明一个数组
charstr[10]
,这10个字节的空间是放在堆栈上,还是分配到其他地方,只有
str
指针被推送到堆栈?如果是后者,10字节的空间分配在哪里

此外,包括数组在内的局部变量究竟是何时分配的?我通常将堆分配称为“动态分配”,这意味着不会动态分配自动变量。但自动变量可能在控制结构和函数体流中声明,因此编译器在运行前不可能确切知道自动变量将占用多少空间。所以自动变量也必须动态分配,对吗

编辑:我想强调这个问题的前半部分。我最感兴趣的是了解本地阵列的空间在何时何地分配。在堆栈上?其他地方


<> > >编辑2:< /强>,当我最初包含C++标记用于这个问题时,我犯了一个错误。我只是想问一下C语言及其实现。我为您的任何困惑道歉。

您所要求的取决于语言实现(编译器)。为了回答您的问题,以下是编译器通常对编译语言(如C/C++)所做的(简化概述):

当编译器完成对函数的解析时,它会保存一个包含该函数中声明的所有局部变量的符号表,即使是那些在函数的指令流中“按语法”声明的变量(如局部循环变量)。稍后,当需要生成最终(汇编)代码时,它会生成必要的指令,以便为所有局部变量推送(或只是移动堆栈指针)足够的空间。因此,例如,当循环开始执行时,不会分配局部循环变量。相反,它们是在包含循环的函数开始执行时分配的。编译器还添加指令,以在从函数返回之前删除此分配的堆栈空间

因此,在这个(常见的)场景中,自动变量(如char数组)完全分配在堆栈上

[编辑]可变长度数组(C99之前)

上面的讨论是针对编译时已知长度的数组,如下所示:

void f () {
    char n[10];
    ....
}
void f() {
    char *n;
    ... //array is later allocated using some kind of memory allocation construct
}
如果我们使用C语言术语(C99之前),可变长度数组(其长度在编译时未知,但在运行时未知的数组)将声明为如下指针:

void f () {
    char n[10];
    ....
}
void f() {
    char *n;
    ... //array is later allocated using some kind of memory allocation construct
}
实际上,这只是声明了一个指向数组的指针。编译器知道指针的大小。因此,正如我上面所说的,编译器将能够为堆栈上的指针(只是指针,而不是真正的数组)保留必要的存储空间,而不管运行时数组的大小如何。当执行到达分配数组的行时(例如,使用malloc),数组存储将动态地分配到堆上,其地址存储在本地自动变量
n
中。在没有垃圾收集的语言中,这需要手动从堆中释放(取消分配)保留存储(即,当不再需要阵列时,程序员应该在程序中添加一条指令)。对于常量大小的数组(在堆栈上分配的数组),这是不必要的,因为编译器在从函数返回之前会删除堆栈帧,正如我前面所说的

[编辑二]

无法在堆栈上声明C99可变长度数组。编译器必须向生成的机器代码中添加一些代码,以便在运行时处理其动态创建和销毁

例如,如果声明一个数组char str[10];,这10字节的空间是放在堆栈上,还是分配到其他地方,只有str指针被推送到堆栈?如果是后者,10字节的空间分配在哪里

通常,阵列的存储是在堆栈上分配的,就像任何其他局部变量一样。这是特定于编译器和目标的。即使在x86_64机器上,也可能没有在堆栈上分配40亿字节的数组。我期望其中之一:编译错误、链接错误、运行时错误,或者它以某种方式工作。在最后一种选择中,它可能调用
new[]
malloc()
,并将指向堆栈上数组的指针保留在数组的位置


请注意,数组的分配和它的指针是相同的,因此您添加的分配到了其他地方,只有str-pointer可能表示混淆。分配发生,其名称不是独立的数据。

在C 2018标准中,第6.2.4条第6和第7段告诉我们具有自动存储持续时间的对象的寿命。第6段涵盖了非可变长度数组的对象:

…其生存期从进入与其关联的块开始,一直到该块的执行以任何方式结束。(输入封闭块或调用函数会暂停但不会结束当前块的执行。)如果以递归方式输入块,则每次都会创建对象的新实例

因此,如果我们有此代码:

{
    PointA;
    int x = 3;
    PointB;
}
{
    PointA;
    int x[n]; // n is some variable.
    PointB;
}
然后,当执行到达
点A
时,
x
就存在于C模型中-输入了它的块,也就是
x
的生存期开始时。但是,尽管
x
已存在于
a点
,但其值不确定。初始化仅在达到定义时发生

第7段介绍了可变长度数组:

?