全局变量声明如何解决C中的堆栈溢出?

全局变量声明如何解决C中的堆栈溢出?,c,pointers,memory,stack,C,Pointers,Memory,Stack,我有一些C代码。 它所做的很简单,从io获取一些数组,然后对其进行排序 #include <stdio.h> #include <stdlib.h> #define ARRAY_MAX 2000000 int main(void) { int my_array[ARRAY_MAX]; int w[ARRAY_MAX]; int count = 0; while (count < ARRAY_MAX && 1 ==

我有一些C代码。 它所做的很简单,从io获取一些数组,然后对其进行排序

#include <stdio.h>
#include <stdlib.h>

#define ARRAY_MAX 2000000

int main(void) {
    int my_array[ARRAY_MAX];
    int w[ARRAY_MAX];
    int count = 0;

    while (count < ARRAY_MAX && 1 == scanf("%d", &my_array[count])) {
        count++;
    }

    merge_sort(my_array, w, count);
    return EXIT_SUCCESS;
}
我的导师告诉我,这个解决方案做同样的工作:将这两个变量移动到堆中

但我在网上查了一些文件。全局变量,没有初始化,它们将驻留在bss段中,对吗

我在网上查过,这个部分的大小只有几个字节。 它如何防止堆栈溢出

或者,因为这两种类型是数组,所以它们是指针,全局指针驻留在数据段中,这表明数据段的大小也可以动态更改?

bss(由符号启动的块)部分在对象文件中很小(4或8字节)但存储的值是初始化数据之后要分配的零内存字节数

它通过分配存储“不在堆栈上”来避免堆栈溢出。它通常在数据段中,在文本段之后,堆段开始之前,但是现在这个简单的内存图片可能更复杂


在官方层面上,应该对“标准没有规定必须有一个堆栈”和其他各种小片段提出警告,但这不会改变答案的实质内容。bss部分很小,因为它是一个单一的数字,但是这个数字可能代表大量的内存。

全局变量没有在堆栈上分配。它们是在数据段(如果已初始化)或bss(如果未初始化)中分配的。

免责声明:这不是指南,而是概述。这是基于Linux的工作方式,尽管我可能弄错了一些细节。大多数(桌面)操作系统使用非常相似的模型,具有不同的细节。此外,这仅适用于用户空间程序。这就是你要写的,除非你是在为内核开发或者在模块(linux)、驱动程序(windows)、内核扩展(osx)上工作

虚拟内存:我将在下面详细介绍,但要点是每个进程都有一个专用的32-/64位地址空间。显然,进程的整个地址空间并不总是映射到实际内存。这意味着A)一个进程的地址对另一个进程来说毫无意义,B)操作系统决定在任何给定的时间点,进程地址空间的哪些部分加载到实际内存中,哪些部分可以留在磁盘上

可执行文件格式 可执行文件有许多不同的部分。我们在这里关心的是
.text
.data
.bss
.rodata
.text
部分是您的代码。
.data
.bss
部分是全局变量。
.rodata
部分是常量“变量”(也称常量)。常量是类似于错误字符串和其他消息的东西,或者可能是幻数。程序需要引用但从不更改的值。
.data
部分存储具有初始值的全局变量。这包括定义为
=。例如,包含状态变量和初始值的数据结构,您的程序使用它来跟踪自身。
.bss
部分记录没有初始值或初始值为零的全局变量。这包括定义为
的变量
=0。由于编译器和操作系统都知道
.bss
部分中的变量应该初始化为零,因此没有理由实际存储所有这些零。因此,可执行文件仅存储变量元数据,包括应为变量分配的内存量

进程内存布局 当操作系统加载可执行文件时,它会创建六个内存段。bss、数据和文本段都位于一起。数据和文本段是从文件中加载的(实际上不是,请参见虚拟内存)。bss部分分配给所有未初始化/零初始化变量的大小(请参阅VM)。内存映射段类似于数据和文本段,因为它由从文件加载的内存块组成(请参见VM)。这是加载动态库的地方

bss、数据和文本段的大小是固定的。内存映射段的大小实际上是固定的,但当您的程序加载新的动态库或使用另一个内存映射函数时,它会增长。但是,这种情况并不经常发生,而且大小的增加总是要映射的库或文件(或共享内存)的大小

堆栈 堆栈有点复杂。为堆栈保留一个内存区域,其大小由程序决定。堆栈顶部(低内存地址)用主函数的变量初始化。在执行过程中,可以向堆栈底部添加或删除更多变量。将数据推到堆栈上会使其向下“增长”(更高的内存地址),增加堆栈指针(保持堆栈底部的地址)。从堆栈中弹出数据会将其缩小,从而减少堆栈指针。调用函数时,调用函数中下一条指令的地址(文本段内的返回地址)被推送到堆栈上。当函数返回时,它会将堆栈恢复到调用函数之前的状态(它推到堆栈上的所有内容都会弹出),并跳转到返回地址

如果堆栈增长过大,则结果取决于许多因素。有时会出现堆栈溢出。有时运行时(在您的例子中是C运行时)试图为堆栈分配更多内存。这个话题超出了这个答案的范围

机甲废场 堆用于动态内存分配。使用
alloc
函数之一分配的内存位于堆上。所有其他内存分配
    int my_array[ARRAY_MAX];
    int w[ARRAY_MAX];