c中的不同输出

时间:2018-05-29 20:51:51

标签: c output

这4个程序都创建了一个包含10000个char元素的数组,并且都有不同的输出。谁能解释为什么?

1号:

int main()
{
char buffer[10000];
printf("address: %p\n", buffer);
return 0;
}

2号:

char buffer[10000];

int main()
{
    printf("address: %p\n", buffer);
    return 0;
}

3号:

char buffer[10000] = { 'a', 'b', 'c', '\0' };
int main()
{
    printf("address: %p\n", buffer);
    return 0;
}

4号:

int main()
{
    char* buffer = (char*)malloc(10000);
    printf("address: %p\n", buffer);
    free(buffer);
    return 0;
}

4 个答案:

答案 0 :(得分:1)

正如其他人所提到的那样,原因是缓冲区的地址是 印刷,它不总是一样的。但问题是,为什么?

要回答这个问题,我们可以猜测编译器将缓冲区放在哪里 每个案例。

作为背景,有多个'部分'在汇编文件中告诉 计算机生成的可执行文件中每个系列的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'''' 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

答案 1 :(得分:0)

分配内存的地址总是不同,这取决于可用内存以及操作系统为程序提供的内存范围。

编辑:还要考虑在函数中分配的每个变量都在堆栈中分配,而其他变量在堆中分配。

答案 2 :(得分:0)

对于示例2和3,数组是全局声明的,即在执行期间不在堆栈上。另外两个在程序运行时在堆栈上声明了它。这两种方案将产生截然不同的结果。每对结果之间的差异更加微妙,并且完全取决于编译器。

答案 3 :(得分:0)

printf("address: %p\n", buffer);打印的文本在所有程序中都可能是相同的(尽管不太可能),并且如OP所示,它们可能是不同的。

许多编译器将数据排列在不同的组(例如段)中。这是编译器的属性而不是C.这些组通常基于变量的生命周期以及如何(如果)初始化。

研究编译器以获取详细信息。

char global_initialized_to_zero[10000];
char global_initialized[10000] = { 'a', 'b', 'c', '\0' };

int main() {
  char local_uninitialized[10000];
  char* allocated = malloc(10000);
  ...