内存中程序的结构
以下是任何程序在内存中加载时的基本结构。
 +--------------------------+
 |                          |
 |      command line        |
 |        arguments         |
 |    (argc and argv[])     |
 |                          |
 +--------------------------+
 | Stack                    |
 | (grows-downwards)        |
 |                          |
 |                          |
 |                          |
 |         F R E E          |
 |        S P A C E         |
 |                          |
 |                          |
 |                          |
 |                          |
 |     (grows upwards) Heap |
 +--------------------------+
 |                          |
 |    Initialized data      |
 |         segment          |
 |                          |
 +--------------------------+
 |                          |
 |     Initialized to       |
 |        Zero (BSS)        |
 |                          |
 +--------------------------+
 |                          |
 |      Program Code        |
 |                          |
 +--------------------------+
需要注意的几点:
- 数据段
- 初始化的数据段(由程序员初始化为显式初始值设定项)
- 未初始化的数据段(初始化为零数据段 - BSS [块以符号开头])
 
- 代码段
- 堆栈和堆区域
数据段
数据段包含由包含初始化值的用户显式初始化的全局和静态数据。
数据段的另一部分称为BSS(因为旧的IBM系统已将该段初始化为零)。它是操作系统将内存块初始化为零的内存部分。这就是未初始化的全局数据和静态数据将默认值为零的方式。此区域是固定的,具有静态大小。
数据区域根据显式初始化分为两个区域,因为要初始化的变量可以逐个初始化。但是,未初始化的变量不需要逐个使用 0 显式初始化。取而代之的是,初始化变量的工作留给操作系统。此批量初始化可以大大减少加载可执行文件所需的时间。
大多数情况下,数据段的布局由底层操作系统控制,仍然一些加载器将部分控制权交给用户。此信息在嵌入式系统等应用中可能很有用。
可以使用代码中的指针对该区域进行寻址和访问。Auto 变量在每次需要变量时都会有初始化变量的开销,并且需要代码来执行该初始化。但是,数据区域中的变量没有这样的运行时重载,因为初始化只执行一次,并且在加载时也执行。
代码段
程序代码是可执行代码可供执行的代码区域。这个区域也是固定大小的。这只能通过函数指针访问,而不能由其他数据指针访问。这里要注意的另一个重要信息是,系统可能会将此区域视为只读内存区域,并且在此区域中写入的任何尝试都会导致未定义的行为。
常量字符串可以放在代码或数据区域中,这取决于实现。
尝试写入代码区域会导致未定义的行为。例如(我将仅提供基于示例的示例),以下代码可能会导致运行时错误甚至使系统崩溃。C
int main()
{
    static int i;
    strcpy((char *)main,"something");
    printf("%s",main);
    if(i++==0)
    main();
}
堆栈和堆区域
对于执行,程序使用两个主要部分,堆栈和堆。堆栈帧是在函数的堆栈和用于动态内存分配的堆中创建的。堆栈和堆是未初始化的区域。因此,内存中碰巧存在的任何内容都将成为在该空间中创建的对象的初始(垃圾)值。
让我们看一个示例程序,以显示哪些变量存储在何处,
int initToZero1;
static float initToZero2;
FILE * initToZero3; 
// all are stored in initialized to zero segment(BSS)
double intitialized1 = 20.0;
// stored in initialized data segment
int main()
{
    size_t (*fp)(const char *) = strlen;
    // fp is an auto variable that is allocated in stack
    // but it points to code area where code of strlen() is stored
    char *dynamic = (char *)malloc(100);
    // dynamic memory allocation, done in heap
    int stringLength;
    // this is an auto variable that is allocated in stack
    static int initToZero4; 
    // stored in BSS
    static int initialized2 = 10; 
    // stored in initialized data segment   
    strcpy(dynamic,”something”);    
    // function call, uses stack
    stringLength = fp(dynamic); 
    // again a function call 
}
或者考虑一个更复杂的例子,
// command line arguments may be stored in a separate area  
int main(int numOfArgs, char *arguments[])
{ 
    static int i;   
    // stored in BSS 
    int (*fp)(int,char **) = main;  
    // points to code segment 
    static char *str[] = {"thisFileName","arg1", "arg2",0};
    // stored in initialized data segment
    while(*arguments)
        printf("\n %s",*arguments++);
    if(!i++)
        fp(3,str);
}
希望这有帮助!