Rah*_*hul 66 c memory arrays c99 variable-length-array
我写了一个C程序,它接受来自用户的整数输入,用作整数数组的大小,并使用该值声明给定大小的数组,我通过检查数组的大小来确认它.
码:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n;
scanf("%d",&n);
int k[n];
printf("%ld",sizeof(k));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
而且令人惊讶的是它是正确的!该程序能够创建所需大小的数组.
但是所有静态内存分配都是在编译时完成的,并且在编译期间,其值n
是未知的,那么为什么编译器能够分配所需大小的内存呢?
如果我们能够分配所需的内存就是这样,然后有什么用使用动态分配的malloc()
和calloc()
?
AnT*_*AnT 73
这不是"静态内存分配".您的数组k
是可变长度数组(VLA),这意味着此数组的内存在运行时分配.大小将由运行时值决定n
.
语言规范没有规定任何特定的分配机制,但在典型的实现中,您k
通常最终会成为一个简单的int *
指针,实际的内存块在运行时被分配在堆栈上.
对于VLA sizeof
运算符,也会在运行时进行评估,这就是您在实验中从中获取正确值的原因.只需使用%zu
(不%ld
)打印类型的值size_t
.
malloc
(和其他动态内存分配函数)的主要目的是覆盖适用于本地对象的基于范围的生存期规则.即分配的内存malloc
仍然是"永久"分配的,或直到你明确地释放它为止free
.分配的内存malloc
不会在块结束时自动释放.
在您的示例中,VLA不提供这种"范围失败"功能.您的阵列k
仍然遵循常规的基于范围的生命周期规则:其生命周期在块的末尾结束.因此,在一般情况下,VLA不可能替换malloc
和其他动态内存分配功能.
但是在特定情况下,当您不需要"击败范围"并且只是用于malloc
分配运行时大小的阵列时,VLA可能确实被视为替代malloc
.请记住,VLA通常是在堆栈上分配的,并且到目前为止在堆栈上分配大块内存仍然是一个相当可疑的编程实践.
Pet*_*ter 11
在C中,编译器支持VLA(可变长度数组)的方法取决于编译器 - 它不必使用malloc()
,并且可以(并且经常)使用有时称为"堆栈"的内存 - 例如使用系统这样的特定函数alloca()
不是标准C的一部分.如果它确实使用堆栈,则数组的最大大小通常比使用的小得多malloc()
,因为现代操作系统允许程序的堆栈内存配置小得多.
plu*_*ash 10
可变长度数组的内存显然不能静态分配.然而,它可以在堆栈上分配.通常,这涉及使用"帧指针"来在动态确定的对堆栈指针的改变的情况下跟踪功能堆栈帧的位置.
当我尝试编译你的程序时,似乎实际发生的是可变长度数组被优化了.所以我修改了你的代码以强制编译器实际分配数组.
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n;
scanf("%d",&n);
int k[n];
printf("%s %ld",k,sizeof(k));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
Godbolt使用gcc 6.3编译手臂(使用arm因为我可以阅读arm ASM)将其编译为https://godbolt.org/g/5ZnHfa.(评论我的)
main:
push {fp, lr} ; Save fp and lr on the stack
add fp, sp, #4 ; Create a "frame pointer" so we know where
; our stack frame is even after applying a
; dynamic offset to the stack pointer.
sub sp, sp, #8 ; allocate 8 bytes on the stack (8 rather
; than 4 due to ABI alignment
; requirements)
sub r1, fp, #8 ; load r1 with a pointer to n
ldr r0, .L3 ; load pointer to format string for scanf
; into r0
bl scanf ; call scanf (arguments in r0 and r1)
ldr r2, [fp, #-8] ; load r2 with value of n
ldr r0, .L3+4 ; load pointer to format string for printf
; into r0
lsl r2, r2, #2 ; multiply n by 4
add r3, r2, #10 ; add 10 to n*4 (not sure why it used 10,
; 7 would seem sufficient)
bic r3, r3, #7 ; and clear the low bits so it is a
; multiple of 8 (stack alignment again)
sub sp, sp, r3 ; actually allocate the dynamic array on
; the stack
mov r1, sp ; store a pointer to the dynamic size array
; in r1
bl printf ; call printf (arguments in r0, r1 and r2)
mov r0, #0 ; set r0 to 0
sub sp, fp, #4 ; use the frame pointer to restore the
; stack pointer
pop {fp, lr} ; restore fp and lr
bx lr ; return to the caller (return value in r0)
.L3:
.word .LC0
.word .LC1
.LC0:
.ascii "%d\000"
.LC1:
.ascii "%s %ld\000"
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4308 次 |
最近记录: |