C 何时重新分配堆栈内存?
有如下代码:C 何时重新分配堆栈内存?,c,pointers,stack-memory,C,Pointers,Stack Memory,有如下代码: int fun(){ char* pc = NULL; { char ac[100] = "addjfidsfsfds"; pc = ac; } ... pc[0] = 'd'; printf("%s\n", pc); ... } 那么,在ac范围结束后,我是否可以安全地使用pc?因为我不确定为ac分配的堆栈内存是否会被编译器重新分配用于其他用途。在您的示例中,在内部作用域之外使用pc
int fun(){
char* pc = NULL;
{
char ac[100] = "addjfidsfsfds";
pc = ac;
}
...
pc[0] = 'd';
printf("%s\n", pc);
...
}
那么,在
ac
范围结束后,我是否可以安全地使用pc
?因为我不确定为ac
分配的堆栈内存是否会被编译器重新分配用于其他用途。在您的示例中,在内部作用域之外使用pc
是不安全的。因为ac
在pc=ac
之后立即被销毁,所以您有一个经典的悬空指针。如果启用了足够的警告,我假设大多数编译器都会发出警告
这可能在您的系统上起作用,但并不意味着它是安全的。一些编译器可能会选择一次执行回收所有原语的优化,但并不要求它们这样做。来自C标准6.2.1p4[强调]
每个其他标识符的作用域由其声明的位置(在声明符或类型说明符中)确定。如果声明标识符的声明符或类型说明符出现在任何块或参数列表之外,则该标识符具有文件作用域,该文件作用域终止于翻译单元的末尾如果声明标识符的声明符或类型说明符出现在块内或函数定义中的参数声明列表内,则标识符具有块作用域,其终止于关联块的末尾。
变量ac
是一个局部(自动)非静态变量,其生存期仅限于其范围,即声明它的块。在其生命周期之外访问它的任何尝试都会导致未定义的行为
来自C标准#6.2.4p2[强调矿山]
对象的生存期是程序执行期间保证为其保留存储的部分。对象存在,具有恒定地址33),并在其整个生存期内保留其最后存储的值。34)如果对象在其生存期之外被引用,则行为未定义。当指针指向(或刚刚过去)的对象到达其生命周期结束时,指针的值将变得不确定。
理解上的缺陷与对象的存储时间有关。除非您使用的是线程,否则您需要关注三种类型:静态、自动和分配。通过声明
char ac[100]=“addjfidsfsfds”代码>在块内且无静态
存储类说明符的情况下,存储持续时间是自动的,其生存期在bock执行结束时结束。之后尝试访问该值是未定义的行为
C标准在第6.2.4节中对此进行了详细阐述,例如:
1对象的存储持续时间决定其生存期。那里
有四种存储持续时间:静态、线程、自动和
分配。已分配的存储在中进行了描述
2对象的生存期是程序执行的一部分
在此期间,保证为其保留存储空间。物件
存在,具有恒定地址(33),并保留其最后存储的值
在其整个生命周期内。34)如果对象在其
生存期,行为未定义。指针的值
当指向(或刚刚过去)的对象时变得不确定
到了生命的尽头
3在没有存储类的情况下声明其标识符的对象
说明符_Thread _local,具有外部或内部链接
或者使用存储类说明符static,具有静态存储
期间它的生命周期是程序的整个执行过程及其
在程序启动之前,存储值只初始化一次
(_螺纹_局部细节省略)
5一种对象,其标识符声明时没有链接,也没有
存储类说明符static具有自动存储持续时间,如下所示
做一些复合文字。试图间接地做某事的结果
从其他线程访问具有自动存储持续时间的对象
而不是与对象关联的对象
实现定义
6对于没有可变长度数组的对象
类型,则其生存期从其所在的块的入口开始延长
关联,直到以任何方式结束该块的执行。(进入
封闭块或调用函数将挂起,但不会结束,
执行当前块。)如果以递归方式输入块,
每次都会创建对象的新实例。初始值
对象的属性是不确定的。如果为指定了初始化
对象,它在每次声明或复合时执行
在执行块时达到文本;否则,值
每次到达声明时都变得不确定
7对于具有可变长度数组类型的对象,
它的生存期从对象声明开始一直到
程序的执行离开了声明的范围。35)如果
递归地输入范围,创建对象的新实例
每次都创建。对象的初始值是不确定的
如果有关于是否允许访问某个值的问题,请咨询标准。它可以在块结束后重新分配(当它超出范围时)
是否重新分配它取决于程序和运行它的机器(以及编译器)的体系结构
当您声明另一个局部变量(在堆栈上)时,它很可能被重新分配;和/或进行函数调用时(将参数值和返回地址推送到堆栈上,并让被调用函数声明新变量)
理论上它是有可能的,它可以通过硬战争在伪随机时间重新分配