非静态局部变量c语言,C语言程序里全局变量、局部变量、堆、栈的存储区域

一、存储区域介绍C语言在内存中一共分为如下几个区域

区域作用内存栈区存放局部变量名

内存堆区存放new或者malloc出来的对象

常数区存放局部变量或者全局变量的值

静态区用于存放全局变量或者静态变量

代码区二进制代码区域的解释栈区(stack)–由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。堆区(heap)–般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式类似于链表。全局区(静态区)(static)–全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域(RW),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(ZI)。程序结束后有系统释放。 和“栈”一样,通常是用于那些在编译期间就能确定存储大小的变量的存储区,但它用于的是在整个程序运行期间都可见的全局变量和静态变量。文字常量区–常量字符串就是放在这里的。程序结束后由系统释放 (RO)程序代码区–存放函数体的二进制代码。 (RO)常量存储区—和“全局/静态存储区”一样,通常是用于那些在编译期间就能确定存储大小的常量的存储区,并且在程序运行期间,存储区内的常量是全局可见的。这是一块比较特殊的存储去,他们里面存放的是常量,不允许被修改。内存存在两种属性:静态分配内存和动态分配内存。静态分配内存:是在程序编译和链接时就确定好的内存。

动态分配内存:是在程序加载、调入、执行的时候分配/回收的内存。堆栈

堆和栈都是动态分配内存,两者空间大小都是可变的。Stack: 栈,存放Automatic Variables,按内存地址由高到低方向生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。

通常是用于那些在编译期间就能确定存储大小的变量的存储区,用于在函数作用域内创建,在离开作用域后自动销毁的变量的存储区。通常是局部变量,函数参数等的存储区。他的存储空间是连续的,两个紧密挨着定义的局部变量,他们的存储空间也是紧挨着的。栈的大小是有限的,通常Visual C++编译器的默认栈的大小为1MB,所以不要定义int a[1000000]这样的超大数组。Heap: 堆,自由申请的空间,按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。

通常是用于那些在编译期间不能确定存储大小的变量的存储区,它的存储空间是不连续的,一般由malloc(或new)函数来分配内存块,并且需要用free(delete)函数释放内存。如果程序员没有释放掉,那么就会出现常说的内存泄漏问题。需要注意的是,两个紧挨着定义的指针变量,所指向的malloc出来的两块内存并不一定的是紧挨着的,所以会产生内存碎片。另外需要注意的一点是,堆的大小几乎不受限制,理论上每个程序最大可达4GB。

每个线程都会有自己的栈,但是堆空间是共用的。Text & Data & Bss.text: 也称为代码段(Code),用来存放程序执行代码,同时也可能会包含一些常量(如一些字符串常量等)。该段内存为静态分配,只读(某些架构可能允许修改)。 这块内存是共享的,当有多个相同进程(Process)存在时,共用同一个text段。.data: 也有的地方叫GVAR(global value),用来存放程序中已经初始化的非零全局变量。静态分配。 data又可分为读写(RW)区域和只读(RO)区域。

-> RO段保存常量所以也被称为.constdata

-> RW段则是普通非常全局变量,静态变量就在其中 .bss: 存放程序中为初始化的和零值全局变量。静态分配,在程序开始时通常会被清零。从低地址到高地址

209879703_1_20201214091610728

二、在ubuntu系统中输出信息进行验证输入代码main.c

#include #include #include void before(){ } char g_buf[16];char g_buf2[16];char g_buf3[16];char g_buf4[16];char g_i_buf[]='123';char g_i_buf2[]='123';char g_i_buf3[]='123'; void after(){ } int main(int argc, char **argv){ char l_buf[16]; char l_buf2[16]; char l_buf3[16]; static char s_buf[16]; static char s_buf2[16]; static char s_buf3[16]; char *p_buf; char *p_buf2; char *p_buf3; p_buf = (char *)malloc(sizeof(char) * 16); p_buf2 = (char *)malloc(sizeof(char) * 16); p_buf3 = (char *)malloc(sizeof(char) * 16); printf('g_buf: 0x%x\n', g_buf); printf('g_buf2: 0x%x\n', g_buf2); printf('g_buf3: 0x%x\n', g_buf3); printf('g_buf4: 0x%x\n', g_buf4); printf('g_i_buf: 0x%x\n', g_i_buf); printf('g_i_buf2: 0x%x\n', g_i_buf2); printf('g_i_buf3: 0x%x\n', g_i_buf3); printf('l_buf: 0x%x\n', l_buf); printf('l_buf2: 0x%x\n', l_buf2); printf('l_buf3: 0x%x\n', l_buf3); printf('s_buf: 0x%x\n', s_buf); printf('s_buf2: 0x%x\n', s_buf2); printf('s_buf3: 0x%x\n', s_buf3); printf('p_buf: 0x%x\n', p_buf); printf('p_buf2: 0x%x\n', p_buf2); printf('p_buf3: 0x%x\n', p_buf3); printf('before: 0x%x\n', before); printf('after: 0x%x\n', after); printf('main: 0x%x\n', main); if (argc > 1) { strcpy(l_buf, argv[1]); } return 0;}1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

691

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

l_buf/l_buf2/l_buf3 ,直接定义,是由编译器自动分配的,存储在栈中

s_buf/s_buf2/s_buf3,定义static,编译器编译时分配内存。为全局变量,在全局初始化区

p_buf/p_buf2/p_buf3,他们指向的空间,通过malloc申请空间,存放在堆中

g_buf/g_buf2/g_buf3/g_buf4/,定义的为全局变量,在全局初始化区运行结果

209879703_2_20201214091610900

分析结果

栈存放区域是由高地址到低地址向下增长

堆存放区是由低地址到高地址像上增长

静态变量地址从高地址到低地址向下增长

函数地址是从低地址到高地址向上增长

三、在Keil中针对stm32系统进行验证总结

内存高地址栈区堆区

.bss段

.data段

常量区

内存低地址代码区在MDK中编译后可以看到Code、RO-data、RW-data、ZI-data的大小Code是存储程序代码的;

RO-data是存储const常量和指令

RW-data是存储初始化值不为0的全局变量

ZI-data是存储未初始化的全局变量或初始化值为0的全局变量

209879703_3_2020121409161141keil中的代码#include 'delay.h'#include 'usart.h'#include 'string.h'#include #include int k1 = 1;int k2;static int k3 = 2;static int k4;int main(void) {delay_init();     //延时函数初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2uart_init(115200); //串口初始化为115200  while(1){    static int m1=2, m2;    int i = 1;    char *p;    char str[10] = 'hello';    char *var1 = '123456';    char *var2 = 'abcdef';    int *p1=malloc(4);    int *p2=malloc(4);    free(p1);    free(p2);    printf('栈区-变量地址');printf('   i:%p\r\n', &i);printf('                p:%p\r\n', &p);printf('              str:%p\r\n', str);    printf('堆区-动态申请地址');    printf('  %p\r\n', p1);    printf('                   %p\r\n', p2);    printf('\r\n.bss段\r\n');printf('全局外部无初值 k2:%p\r\n', &k2);printf('静态外部无初值 k4:%p\r\n', &k4);printf('静态内部无初值 m2:%p\r\n', &m2);    printf('\r\n.data段\r\n');    printf('全局外部有初值 k1:%p\r\n', &k1);    printf('静态外部有初值 k3:%p\r\n', &k3);    printf('静态内部有初值 m1:%p\r\n', &m1);    printf('\r\n常量区\r\n');    printf('文字常量地址     :%p\r\n',var1);    printf('文字常量地址     :%p\r\n',var2);    printf('\r\n代码区\r\n');    printf('程序区地址       :%p\r\n',&main);}}12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849501234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950 串口调试结果

209879703_4_20201214091611134

分析结果可知,stm32的栈区的地址值是从上到下减小的,堆区则是从上到下增长的。

四、总结

通过这次学习让我对C程序的内存分配有进一步的认识,知道一个C程序内存包括的部分,了解了栈和堆地址变化的不同。而且在不同系统中,区域内的地址值变化不一定是相同的。

五、参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值