年,兮 发表于 2023-4-4 18:53:22

栈的存储是怎样的?

代码如下:
#include<stdio.h>

int main()
{
        char c=0, a=0,b=0;
        int *p=(int *)&b;
        *p=256;
        printf("%d %d %d\n",c,a,b);


        return 0;
}//
为啥输出为:1,0,0
同样:
#include<stdio.h>

int main()
{
        char a=0,b=0;
        int *p=(int *)&b;
        *p=256;
        printf("%d %d %d\n",c,a,b);


        return 0;
}//为啥输出为:1,0

歌者文明清理员 发表于 2023-4-4 18:55:53

这两个程序都包含了指针的类型转换和越界访问,导致输出结果与预期不符。具体解释如下:

第一个程序中,将整型指针p指向了变量b的地址,但b只有一个字符大小,因此指针p指向的内存空间越界了。接着,将p所指向的内存空间赋值为256,即在该内存空间写入了一个int类型的值,但由于该内存空间越界,可能会覆盖其他变量的值。最后输出了三个变量c、a、b的值,其中c和b都被修改过,而a没有修改,因此输出结果为1,0,0。

第二个程序中,与第一个程序类似,也将一个整型指针p指向了变量b的地址并进行了越界访问,写入了一个int类型的值256。然而这里没有定义变量c,编译器会自动将其初始化为0。最终输出了三个变量c、a、b的值,其中c的初始值为0,b被修改过,而a没有修改,因此输出结果为1,0,0。

isdkz 发表于 2023-4-4 18:56:53

栈的存储是一种后进先出(LIFO)的数据结构,用于在程序中存储局部变量、参数、返回地址等。栈是向低地址方向增长的。

对于这两段代码,我们先分析第一个代码段。在这段代码中,定义了三个字符变量c、a、b,分别初始化为0。接着,你创建了一个指向b的整数指针p,然后将整数256写入*p。由于b的类型是char,它只能存储1个字节的数据(范围为-128到127,或0到255),所以将整数256存储到b中会导致溢出。整数256的二进制表示为0000 0001 0000 0000,将其存储到一个char类型的变量中时,低8位被截断,只保留高8位。因此,b的值将为0,而a的值将变为1(高8位的数据)。

在第二段代码中,你移除了变量c,这导致a和b在栈上的相对位置发生了变化。当你再次执行类似的操作时,依然会导致溢出,但这次是a的值变为1,而b的值保持为0。

输出的原因在于内存中变量的存储顺序和栈的增长方向。在这种情况下,a和b在栈上的相对位置发生了变化,从而导致了不同的输出结果。

年,兮 发表于 2023-4-4 19:08:28

isdkz 发表于 2023-4-4 18:56
栈的存储是一种后进先出(LIFO)的数据结构,用于在程序中存储局部变量、参数、返回地址等。栈是向低地址方 ...

小甲鱼说的是:栈是由高地址往低地址发展;堆则相反;这确实是栈为啥是从低地址开始发展的呢?

isdkz 发表于 2023-4-4 19:11:27

年,兮 发表于 2023-4-4 19:08
小甲鱼说的是:栈是由高地址往低地址发展;堆则相反;这确实是栈为啥是从低地址开始发展的呢?

栈是从高地址向低地址发展,而堆是从低地址向高地址发展。

栈从高地址向低地址发展的原因主要与计算机内存的组织方式和系统调用栈的设计有关。


[*]内存分配策略:在大多数操作系统中,栈和堆位于不同的内存区域。栈通常位于高地址空间,而堆位于低地址空间。

这种设计策略有助于提高内存利用率,因为栈和堆可以相互靠近,共享可用的内存空间。

这种设计方式使得栈和堆在内存中可以自由地扩展,只要它们没有相互碰撞。


[*]系统调用栈:操作系统在处理系统调用时,会为每个调用创建一个栈帧,其中包含函数参数、局部变量和返回地址。

这些栈帧通常以后进先出(LIFO)的顺序存储,因此栈从高地址向低地址发展。

这种设计有助于保持栈帧的连续性和内存访问的局部性,从而提高性能。


这些设计原则是为了提高内存管理效率、简化内存分配和释放过程以及保持栈帧的连续性。

jhq999 发表于 2023-4-4 19:45:41

盒子装东西先进后出,后进先出
页: [1]
查看完整版本: 栈的存储是怎样的?