堆:由程序员分配和释放。容易产生碎片,使用方便,地址分配使用从下到上
栈:用来存放函数地址和局部参数,主函数使用时,要对函数的首地址断点保存,地址分配从上到下,用完自动释放
静态存储区:它主要存放静态数据、全局数据和常量。
全局变量:全局变量存放在静态存储区,作用域是全局,整个声明周期都可以使用,其他文件如需要使用,需要添加extern
全局静态变量 (static):分配的内存与全局变量一样,也是在静态存储内存上,其生命周期也是与整个程序同在的,从程序开始到结束一直起作用,
全局静态变量作用域只在定义它的一个源文件内,其他源文件不能使用它
相同点
是由编译器自动分配和释放的,
初始化的全局变量和静态变量放在同一块内存区中
在调用main之前,内存先从FASH copy 数据(全局/静态变量),和复制全0段的(全局/静态变量)
全局变量和静态变量从0x2000,000开始存
分配内存是分配在栈存储区上的,其作用域也只是在局部函数内,在定义该变量的函数内,只要出了该函数,该局部变量就不再起作用,该变量的生命周期也只是和该函数同在。
在栈里,临时给a 分配空间,
分配的内存也是在静态存储内存上的,其第一次初始化后就一直存在直到程序结束,该变量的特点是其作用域只在定义它的函数内可见,出了该函数就不可见了。
volatile int a = 0;// 全局初始化区 ①存放在内存起始单元0x2000,0000
volatile char *p1; //全局未初始化区 ②存放在起始单元00x2000,0004
void test(void)
{
volatile int t1=10; //局部变量 ④存放在栈空间 0x2000,0600
volatile static int t2 =0;//局部静态变量 ③存放在起始单元0x2000,0008
// printf("%d %d ",t1,t2);//防止代码被优化
}
void main()
{
volatile int b = 0; //栈 ⑥存放在栈空间 0x20000620
volatile char s[] = "abc"; // 栈 ⑤存放在栈空间 0x2000061C
volatile char *p2; //栈 存放在堆空间 0x20000618
volatile char *p3 = "123456"; //123456\0在常量区,p3在栈上。 0x20000614
volatile static int c =0; //局部(静态)初始化区 ④存放在起始单元00x2000,000c
test();
//分配得来得10和20字节的区域就在堆区。
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
volatile char *p4= (char *)malloc(20); //存放在堆空间 0x20000610
strcpy(p2, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
printf("%d %d %d %d %d %d %d ",a,s[0],&p3,c,p1,b,&p2,&p4);//防止代码被优化
}
来自文心一言的解答
这段代码中的变量存储位置以及内存分配涉及到C语言的内存布局和内存管理。首先,我们逐一回答您的问题。
栈空间的起始地址和大小通常是在程序启动时由操作系统配置的。具体的配置方式依赖于操作系统和硬件架构。在嵌入式系统或低级编程中,可能会直接设置栈指针寄存器来指定栈的起始和结束位置。在高级操作系统中,如Linux或Windows,这通常是进程创建时的一部分自动管理。
2. p2,p3,p4 都是堆空间分配地址的吗?
p2
和 p4
是通过 malloc
分配的,所以它们指向的地址是在堆空间中的。而 p3
是一个指向字符串常量 "123456" 的指针,这个字符串常量通常存放在程序的常量区,不是堆空间。
3. 这个地址位置也和栈在一个地址范围吗?
不一定。堆和栈通常是两个不同的内存区域,它们有自己的起始和结束地址。具体的位置和大小取决于操作系统、编译器设置和硬件架构。在某些架构和操作系统中,堆和栈可能是相邻的,但它们仍然是逻辑上分离的区域。
现在,关于代码中的内存布局:
a
和 p1
是全局变量,它们存放在全局/静态存储区。
t1
是局部变量,存放在当前函数的栈帧中。
t2
是局部静态变量,存放在全局/静态存储区,但其生命周期局限于定义它的函数内。
b
, s
, p2
, p3
, 和 c
都是在 main
函数内的局部变量。其中,s
和 b
存放在栈上;p2
和 p3
本身存放在栈上,但它们通过 malloc
分配的内存位于堆上;c
是局部静态变量,存放在全局/静态存储区。
p4
也是一个局部变量,存放在栈上,但通过 malloc
分配的内存位于堆上。
请注意,具体的内存地址(如0x2000,0000、0x2000,0004等)在代码中只是示例,实际运行时可能会有所不同。另外,当您提到 "防止代码被优化" 时,使用 volatile
和打印变量的方式确实可以防止某些编译器优化,但这不是一个通用的或推荐的方法。更好的方法是使用适当的编译器优化设置和/或编译器特定的属性或注解来确保代码的正确性和性能。