C/C++变量在内存中的分布在笔试时经常考到,虽然简单,但也容易忘记,因此在这作个总结,以加深印象。
一:
#include <stdio.h> #include <malloc.h> int g_i = 100; int g_j = 200; int g_k, g_h; int main() { const int MAXN = 100; int *p = (int*)malloc(MAXN * sizeof(int)); static int s_i = 5; static int s_j = 10; static int s_k; static int s_h; int *pi = new int(1); int *pj = new int(1); int i = 5; int j = 10; int k = 20; int f, h; char *pstr1 = "MoreWindows123456789"; char *pstr2 = "MoreWindows123456789"; char *pstr3 = "Hello"; printf("堆中数据地址:0x%08x\n", p); printf("堆中数据地址:0x%08x\n", pi); printf("堆中数据地址:0x%08x\n", pj); putchar('\n'); printf("栈中数据地址(有初值):0x%08x = %d\n", &i, i); printf("栈中数据地址(有初值):0x%08x = %d\n", &j, j); printf("栈中数据地址(有初值):0x%08x = %d\n", &k, k); printf("栈中数据地址(无初值):0x%08x = %d\n", &f, f); printf("栈中数据地址(无初值):0x%08x = %d\n", &h, h); putchar('\n'); printf("静态数据地址(有初值):0x%08x = %d\n", &s_i, s_i); printf("静态数据地址(有初值):0x%08x = %d\n", &s_j, s_j); printf("静态数据地址(无初值):0x%08x = %d\n", &s_k, s_k); printf("静态数据地址(无初值):0x%08x = %d\n", &s_h, s_h); putchar('\n'); printf("全局数据地址(有初值):0x%08x = %d\n", &g_i, g_i); printf("全局数据地址(有初值):0x%08x = %d\n", &g_j, g_j); printf("全局数据地址(无初值):0x%08x = %d\n", &g_k, g_k); printf("全局数据地址(无初值):0x%08x = %d\n", &g_h, g_h); putchar('\n'); printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr1, pstr1, pstr1); printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr2, pstr2, pstr2); printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr3, pstr3, pstr3); free(p); return 0; }
运行结果(不同的机器运行的结果(相对位置)会略有不同,因为堆栈、全局变量等分布是由操作系统决定的)
总之,字符串常量和栈中数据相邻(栈中无论有无初值总是在一起);有初值全局和静态变量一起,无处置的全局和静态变量一起,并且相邻;堆自己再占一块,并且不是连续的,是链表的形式。除了栈中的变量(局部变量和参数),先声明的地址在高位,后声明在低位。
二:
#include <stdio.h> void fun(int i) { int j = i; static int s_i = 100; static int s_j; printf("子函数的参数: 0x%p = %d\n", &i, i); printf("子函数 栈中数据地址: 0x%p = %d\n", &j, j); printf("子函数 静态数据地址(有初值): 0x%p = %d\n", &s_i, s_i); printf("子函数 静态数据地址(无初值): 0x%p = %d\n", &s_j, s_j); } int main() { int i = 5; static int s_i = 100; static int s_j; printf("主函数 栈中数据地址: 0x%p = %d\n", &i, i); printf("主函数 静态数据地址(有初值): 0x%p = %d\n", &s_i, s_i); printf("子函数 静态数据地址(无初值): 0x%p = %d\n", &s_j, s_j); putchar('\n'); fun(i); return 0; }
总之,主函数中栈的地址都要高于子函数中参数及栈地址,证明了栈的伸展方向是由高地址向低地址扩展的。主函数和子函数中静态数据的地址也是相邻的,说明程序会将已初始化的全局变量和表态变量分配在一起,未初始化的全局变量和表态变量分配在另一起。
三 知识补充:
c++内存到底分几个区?
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由os回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放。
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放。
5、程序代码区—存放函数体的二进制代码
1 变量可以存储在内存的不同地方,这依赖于它们的生成期。在函数上部定义的变量(全局变量或static外部变量)和在函数内部定义的static变量,其生存期就是程序运行的全过程。这些变量被存储在数据段(Data Segment)中。数据段是在内存中为这些变量留出的一段大小固定的空间,它分为二部分,一部分用来初始化变量,另一部分用来存放未初始化的变量。
2 在函数内部定义的auto变量(没有用关键字static定义的变量)的生成期从程序开始执行其所在的程序块代码时开始,到程序离开该程序块时为止。作为函数参数的变量只在调用该函数期间存在。这些变量被存储在栈(stack)中。栈是内存中的一段空间,开始很小,以后逐渐自动变大,直到达到某个预定义的界限。
3 当用malloc等函数给指针分配一个地址空间的时候,这个分配的内存块位于一段名为“堆(heap)”的内存空间中。堆开始时很小,但调用malloc或clloc等内存分配函数时它就会增大。堆可以和数据段或栈共用一个内存段,也可以有它自己的内存段,这完全取决于编译选项和操作系统。与栈相似,堆也有一个增长界限,并且决定这个界限的规则与栈相同。