正如其他人提到的那样,原因是缓冲区的地址是
打印出来的,并不总是一样的。但问题是,为什么?
要回答这个问题,让我们猜测一下编译器会将缓冲区放在哪里
每个案例。
作为背景,程序集文件中有多个“部分”告诉
计算机生成的可执行文件中每个系列的 1 和 0 的含义。
其中一个部分是“数据”部分。这包含初始化的读/写
数据(在某些情况下它是只读的并且读/写有另一个名称)。
另一个部分是“文本”部分。这是只读的,包含
您正在运行的实际代码,转换为二进制。静态常量可以放
在这里,因为它可以在运行时访问。
第三部分是“bss”部分。这包含读/写数据,但
未初始化。当代码设置为运行时,计算机不必
不必担心将数据复制到此部分,只需确保它存在即可。
当代码执行时,这些部分中的每一个都将映射到内存中的某个地址
运行。这并没有描述您将看到的所有地址
然而,执行过程。还有两个!
“堆”是您的程序可以专门要求的内存的名称
在它开始运行之后。这很有用,因为您的程序可能不知道
在它开始之前它需要多少内存。
“堆栈”是程序启动时给内存的名称
从本质上节省临时工作。这是保存局部变量的地方。
因此,我们可以将正在运行的可执行文件的内存可视化为:
|_00_| Program Code
|_01_|
|_02_|
|_03_|
|....|
|_04_| Initialized Memory
|_05_|
|_06_|
|_07_|
|....|
|_08_| Uninitialized Memory
|_09_|
|_10_|
|_11_|
....
|_38_| Dynamic Memory (from malloc)
|_39_|
|_40_|
|_41_|
....
|_96_| Program Stack (local variables)
|_97_|
|_98_|
|_99_|
现在让我们看看每个例子。
1 号
缓冲区是在 main 的堆栈中声明的。因此缓冲区可能是
位于那里(尽管它足够大,一些编译器可能会移动它
别处)。堆栈通常位于可寻址末尾附近的内存中
向静态代码增长的内存。
2号
缓冲区是在全局范围内声明的。它是未初始化的,所以它可以进入
未初始化的数据部分。如果它被放在初始化数据部分
那么操作系统必须先初始化所有 10kb 的内存
启动代码,会浪费时间。
3 号
缓冲区已在全局范围内声明,但已初始化。它可以进入
初始化数据部分。操作系统将必须初始化所有 10kb
专用于“a”、“b”、“c”的缓冲区的内存,然后是一堆零。
4 号
缓冲区是通过请求更多内存来声明的,因此它将是一些块
操作系统允许它使用。
请注意,由于虚拟寻址,数字的结果可能
每次运行代码时,1-3 都是相同的,但几乎可以肯定的是
当操作系统找到不同的块时,在每次执行时进行更改
给你的记忆。
可视化所有这些,我们看到不同的地址:
|_00_| Program Code
|_01_|
|_02_|
|_03_|
|....|
|_04_| Initialized Memory
|_05_|
|_06_|
|_07_| <-- Number 3
|....|
|_08_| Uninitialized Memory
|_09_|
|_10_|
|_11_| <-- Number 2
....
|_38_| Dynamic Memory (from malloc)
|_39_|
|_40_|
|_41_| <-- Number 4
....
|_96_| Program Stack (local variables)
|_97_|
|_98_|
|_99_| <-- Number 1