内存概述

C语言的数据在运行之前,编译器会提前预留一些内存(text 代码区,BSS、data等),这些数据不是说编译器就能生成,而是告诉程序在程序启动时先创建并分配内存,这部分数据就是全局区。

全局区分程序区域和数据区域,也就是 text 和 data区域,其中 text 存放二进制代码, data 区域还可以细分成常量区、全局区(全局已初始化区和全局未初始化)区。

常量区存放一些字符串常量。全局区存放全局变量和静态局部变量,其中已经初始化的放在全局已初始化区,未初始化的放在全局未初始化区,在程序开始运行时被初始化成0。

程序运行之后也会生成堆区,堆区可以很大,用处也很多。其中一个作用就是作为栈使用,栈遵循FIFO的内存。

栈区内存由编译器控制,可以理解成编译器自动帮忙生成分配销毁内存的代码,栈区主要是用来存储局部变量和形参。

堆区是程序员主动分配和释放的内存,一般体现在 malloc()之类的内存分配函数上。

结构图如下:

一、全局数据区

全局数据区名称很乱,反正就记住除了堆、栈、代码区,还有一个区域,就是全局数据区,它分为常量区、已初始化区和未初始化区,其存放的数据有:

  • 全局变量(值可以在运行时被动态修改)
  • 静态变量(static修饰的变量,包括静态局部变量,静态全局变量)
  • 字符串常量(字符串常量因为可能在程序中多次被使用,所以在程序运行之前就会提前分配内存)

可以用这张图来理解:

字符串常量区

首先,字符串常量的意义就是在常量区存储一些已经使用了的,且没有指向的字符串常量。

比如说代码:

char *p = "abcde";

这个时候赋值给 p 的是"abcde" 首个元素的地址。

而不使用指针时:

char s[] = "abcde";

此时是在内存中创建了"abcde"并赋值给了 s[]

也就是说 s[] 的内存中记录的就是 "abcde",而p中内存记录的是地址,这也就导致了使用指针的情况下"abcde"无处安放,所以就存储在常量区。

另外,排除编译器设置,按照C语言的原始设计思想,如果有如下情况:

char *p1 = "abc";
char *p2 = "abc";

这种情况下,应该在常量区分配两块不同的内存,而有的编译器做了优化,所以会导致p1和p2指向的内存地址是一样的。

另外,不再需要纠结字符串常量到底存储在哪,只需要记住C语言中变量的赋值原则:非指针变量,拷贝内存中的表现形式(实际的值),指针变量,拷贝内存地址。

关于常量区,来看一段代码:

    char array[] = "aaa"; // "aaa"存放在栈区的array[]内存上char *point = "aaa"; // "aaa"存放在常量区char *arrayP = array; // 栈区的指针变量arrayP指向栈区的内存地址NSLog(@"%s",point); // aaaNSLog(@"%s",arrayP); // aaaNSLog(@"%p",point); // aaaNSLog(@"%p",arrayP); // aaaarrayP[1] = 'b';NSLog(@"%s",arrayP); // abapoint[1] = 'b';

结果:

2020-01-03 17:08:51.949067+0800 XKTTTest[89302:73170332] point的值:aaa
2020-01-03 17:08:51.949212+0800 XKTTTest[89302:73170332] arrayP的值:aaa
2020-01-03 17:08:51.949310+0800 XKTTTest[89302:73170332] 指针point存储的地址值:0x1095541ec
2020-01-03 17:08:51.949402+0800 XKTTTest[89302:73170332] 指针arrayP存储的地址值0x7ffee66aa1ac
2020-01-03 17:08:51.949488+0800 XKTTTest[89302:73170332] aba

其结果是在最后一行崩溃,提示EXC_BAD_ACCESS (code=2, address=0x10493025d)。其原因就是 point 指向常量区,常量区内存中的值不可更改。

可以再看一个例子加深理解:

int main() {@autoreleasepool {char string2[] = "abc"; // abc存储在栈中char *p = "abc"; // "abc"存储在常量区
//        *p = '1'; //崩溃,常量区的值不可改变(那为什么全局变量的值可以改变?)char *p2 = string2;*p2 = '1'; //可以改变,因为string2是局部变量而不是字符串常量
//        string2 = '1'; // 编译报错(Array type 'char [4]' is not assignable),因为string2是一个地址,地址不能改变printf("%s",string2);
}

结果:

1bc

另外,打印出来的两个内存地址可以看出0x1095541ec远远小于
0x7ffee66aa1ac,这是因为内存地址从代码区到栈区是依次增大的。

各个区域内存的举例

例子1

iOS:栈、堆、字符串常量区、全局区相关推荐

  1. c/c++教程 - 2.1 程序的内存模型 内存四区 代码区 全局区 堆区 栈区 new操作符

    第2章为C++核心编程. 本阶段主要针对C++面向对象编程做详细讲解. 目录 1.内存分区模型 1.1 程序运行前(代码区.全局区) 1.2 程序运行后:(栈区.堆区) 1.3 new操作符(堆区内存 ...

  2. 【错误记录】C 语言中通过指针操作字符串常量出错记录 ( 只有 栈内存 或 堆内存 中的数据才能通过指针修改 | 不要通过指针修改常量区的字符串 )

    文章目录 一.报错记录 二.修改方案 一.报错记录 执行下面的代码 , 报错如下 : 执行的错误代码 : #include <stdio.h> #include <stdlib.h& ...

  3. java 字符串 常量_Java进阶——Java中的字符串常量池

    字符串常量池 JVM为了减少字符串对象的重复创建,其内部维护了一个特殊的内存,这段内存被成为字符串常量池(方法区中).实际上还有整型常量池.浮点型常量池等等.字符串常量池存放的是对象的引用,而不是对象 ...

  4. 基于STM32分析栈、堆、全局区、常量区、代码区、RAM、ROM

    目录 总体介绍 栈区(stack) 堆区(heap) 全局区(静态区) .bss段 .data段 常量区 代码区 RAM和ROM.Flash Memory的物理特性 RAM ROM Flash Mem ...

  5. 内存区划分、内存分配、常量存储区、堆、栈、自由存储区、全局区[C++][内存管理]...

    这可以帮助你深入了解程序的运行机制,由于自己还是一个初学者,因此大部分内容都只是转载. http://blog.sina.com.cn/s/blog_7edcf63b0100yhk9.html 一. ...

  6. C/C++内存分配、内存区划分、常量存储区、堆、栈、自由存储区、全局区(静态区)、代码区

    C/C++内存分配.内存区划分.常量存储区.堆.栈.自由存储区.全局区 C++中,内存分成几个区: 栈(stack) 堆(heap) 自由存储区 全局/静态存储区 常量存储区 代码区 对于C++的内存 ...

  7. C和指针之动态内存分配堆、栈、全局区(静态区)、常量区对比总结学习笔记

    一.各个区的介绍   1.栈区(stack)- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(heap) - 一般由程序员分配释放, 若程序员不 ...

  8. 内存区划分、内存分配、常量存储区、堆、栈、自由存储区、全局区[C++][内存管理][转载]...

    http://www.cnblogs.com/JCSU/articles/1051579.html 一. 在c中分为这几个存储区 1.栈 - 由编译器自动分配释放 2.堆 - 一般由程序员分配释放,若 ...

  9. 12.JDK1.8 JVM运行时数据区域概览、各区域介绍、程序计数器、Java虚拟机栈、本地方法栈、堆、堆空间内存分配(默认情况下)、字符串常量池、元数据区、jvm参数配置

    12.JDK1.8 JVM运行时数据区域概览 12.1.JDK1.8 JVM运行时数据区域概览 12.2.各区域介绍 12.3.各区域介绍 12.3.1.程序计数器 12.3.2.Java虚拟机栈 1 ...

  10. 栈区,堆区,全局区,文字常量区,程序代码区详解(程序中不同类型数据所在区)

    一.预备知识-程序的内存分配     一个由C/C++编译的程序占用的内存分为以下几个部分     1.栈区(stack)-   由编译器自动分配释放   ,存放函数的参数值,局部变量的值等.其   ...

最新文章

  1. 《深入理解计算机系统》学习心得二:关于show-bytes的 学习
  2. dijkstra 算法_最短路径问题Dijkstra算法详解
  3. 一个handle使用更新线程的实例
  4. 第一个只出现一次的字符位置
  5. python_ 学习笔记(hello world)
  6. Xcode 不用签名编译程序
  7. api 定位 微信小程序 精度_一行代码区分微信小程序或QQ小程序
  8. scala学习笔记-Map与Tuple(10)
  9. html主要的骨架结构
  10. newtonsoft 数组反序列化_漏洞学习篇之反序列化
  11. 大数据分析平台如何选择
  12. asp.net门诊收费管理系统
  13. Java电商项目-5.内容管理cms系统
  14. 软件开发各类文档模板
  15. 整理一个将qq音乐的歌单导入到苹果音乐中的方法
  16. 集团公司预算控制与网上费用报销系统
  17. 桥接模式和适配器模式的区别
  18. JAVA中多态以及向上转型向下转型、重写的讲解
  19. FTP搜索引擎开发文档(任务概述与需求部分)
  20. CyberArticle(eLib电子图书馆)网文快捕

热门文章

  1. RabbitMQ消息可靠性传输示例
  2. MySQL中的时间函数
  3. 将Unity项目改为aar模块
  4. 云数据库MySQL5.7单机基础版上线
  5. 【Win 10应用开发】提供建议列表的输入控件(AutoSuggestBox)
  6. html中空格的编码
  7. nagios原装配置文件
  8. 新手必看——JAVA排序详解(冒泡排序和插入排序)
  9. 【git体验】git原理及基础
  10. nodejs后台系列--第四篇--koa(四)