八、C语言进阶:内存

2023-11-08

8 内存

8.1 内存四区

在这里插入图片描述

8.1.1 栈区(stack)

由编译器自动分配和释放,主要是存放函数参数的值,局部变量的值。

8.1.2 堆区(heap)

由程序员自己申请分配和释放,需要malloc()、calloc()、realloc()函数来申请,用free()函数来释放如果不释放,可能出现指针悬空/野指针。
函数不能返回指向栈区的指针,但是可以返回指向堆区的指针。

8.1.3 数据区(data)

变量标有static关键字,保存了静态变量。

  1. 初始化的全局变量和初始化的静态变量,在一块区域;
  2. 未初始化的全局变量和未初始化的静态变量,在一块区域,称作BSS(Block Started by Symbol:以符号开始的块);
  3. 静态变量的生命周期是整个源程序,而且只能被初始化一次,之后的初始化会被忽略。
    (如果不初始化,数值数据将被默认初始化为0, 字符型数据默认初始化为NULL)。

整个数据区的数组,在程序结束后由系统统一销毁。

8.1.4 代码区(code)

用于存放编译后的可执行代码,二进制码,机器码。

8.2 堆和栈的比较

比较方面
管理方式 由系统自动管理,以执行函数为单位 由程序员手动控制
空间大小 空间大小编译时确定(参数+局部变量) 具有全局性,总体无大小限制。
分配方式 函数执行,系统自动分配;函数结束,系统立即自动回收。 使用new/malloc()手动分配释放;使用delete/free()手动释放
优点 使用方便,不需要关心内存申请释放。 可以跨函数使用。
缺点 只能在函数内部使用。 容易造成内存泄露。

8.3 实例分析内存四区

#include <stdio.h>
#include <stdlib.h>
int ga = 0;
int gb = 0;
int gc = 0;
void Func1(){
    int a = 1;
    int b = 2;
    int c = 3;
    printf("Func:&a = %p\n",a);
    printf("Func:&b = %p\n",b);
    printf("Func:&c = %p\n",c);
}
void Func2(){}
void Func3(){}

int main(){
    int a;
    int b;
    int c;
    printf("&a = %p\n",&a);
    printf("&b = %p\n",&b);
    printf("&c = %p\n",&c);

    int* p1 = malloc(sizeof(int));
    int* p2 = malloc(sizeof(int));
    int* p3 = malloc(sizeof(int));
    printf("p1 =\t%p\n",p1);
    printf("p2 =\t%p\n",p2);
    printf("p3 =\t%p\n",p3);

   
    printf("&ga =\t%p\n",&ga);
    printf("&gb =\t%p\n",&gb);
    printf("&gc =\t%p\n",&gc);

    static int sa = 0;
    static int sb = 0;
    static int sc = 0;
    printf("&sa =\t%p\n",&sa);
    printf("&sb =\t%p\n",&sb);
    printf("&sc =\t%p\n",&sc);


    printf("Func1 =\t%p\n",&Func1);
    printf("Func2 =\t%p\n",&Func2);
    printf("Func3 =\t%p\n",&Func3);

    char* s1 = "abcd";
    char* s2 = "1234";
    char* s3 = "!@#$";
    printf("s1 =\t%p\n",s1);
    printf("s2 =\t%p\n",s2);
    printf("s3 =\t%p\n",s3);
}
&a = 0x7ffdf94c1d1c //局部变量存放在栈区,相邻变量地址递减
&b = 0x7ffdf94c1d18
&c = 0x7ffdf94c1d14
p1 =	0xe95670  //申请内存存放在堆区
p2 =	0xe95690
p3 =	0xe956b0
&ga =	0x601030  //全局变量存放在数据区
&gb =	0x601034
&gc =	0x601038
&sa =	0x60103c  //静态局部变量存放在数据区
&sb =	0x601040
&sc =	0x601044
Func1 =	0x4005d6  //存放在代码区
Func2 =	0x400632
Func3 =	0x400639
s1 =	0x400978  //字符串地址递增
s2 =	0x40097d
s3 =	0x400982
Func:&a = 0x1
Func:&b = 0x2
Func:&c = 0x3

上面结果每次执行结果会有所变化,不同计算机结果也会不同。但是会有如下规律:

  1. 局部变量、静态变量、动态分配内存、字符串常量与函数分别放在一起,即使在不同的函数中。
  2. 变量的存放地址大小有如下特点:
    字符串常量与代码 < 静态变量 < 动态分配内存 < 局部变量
  3. 静态变量、动态分配内存、字符串常量与函数的相邻变量地址是递增的。局部变量相邻变量地址是递减的。
  4. 字符串常量与函数是在一起的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

八、C语言进阶:内存 的相关文章

随机推荐

  • Run-Time Check Failure #0 错误

    使用VS 遇到过一个错误 如下图 文字描述是这样的 Run Time Check Failure 0 The value of ESP was not properly saved across a function call This i
  • 智能优化算法 — 蜣螂优化算法(Dung beetle optimizer,DBO)

    引言 小时候 蜣螂还是比较多见的 还顽皮地将粪球给它弄走 或者给它来点障碍 现在放牛的几乎看不到了 蜣螂没东西可推了 也慢慢从我们的视线中消失了 DBO介绍 2022年11月27日 东华大学沈波教授团队 继麻雀搜索算法 Sparrow Se
  • 关于Lab5 github上传后文件名大小写不变

    遇到的问题 由于checkstyle等工具检查出本地包名不符合规范 修改了其大小写之后 重新上传到github上发现包内类中package后包名已经改变 但是文件夹名并没有改变 尝试解决一 执行git config global core
  • spring boot升级spring cloud注意事项

    项目升级 从springboot转成springcloud 记录一些过程中遇到的问题和坑 一 确定版本和组件选型 版本不兼容会造成很多问题 所以需要根据项目使用的Spring Boot Version确定相关版本 此处使用的是Spring
  • for循环达到指定循环次数

  • AngularJs ngList、ngRepeat、ngModelOptions

    ngList 在文本输入的分隔的字符串和字符串数组间做转换 可以是一个固定的字符串分隔符 默认逗号 或正则表达式 格式 ng list value value 表达式 通过这个值分隔字符串 使用代码 div div
  • HeadFirst 设计模式学习笔记14——MVC分析

    随笔 346 文章 0 评论 14 本文已搬家至 HeadFirst 设计模式学习笔记 13 MVC分析
  • Numpy下dtype中的str_与string_的区别

    为什么写这篇文章呢 其实简单来说就是因为搜不到别人有这类的文章呗 所以自己研究了一下 在我的某个程序中需要将数据保存成numpy数组 数组中每个元素又必须是字符串的格式 但是当你输入dtype numpy str的时候 你会发现又三个相近的
  • 修改element样式避坑笔记

    一点要添加这个 popper append to body false 否则就算加了 deep 还是加了 important 对于要修改的样式还是不生效的
  • Vue学习 之 MacOS 安装 webpack

    Vue学习 之 MacOS 安装 webpack webpack 简介 Webpack 是一个非常流行的前端构建工具 它可以将多个模块 包括CSS JavaScript 图片等 打包成一个或多个静态资源文件 bundle 以便用于部署到生产
  • Qt帮助文档

    Qt帮助文档 Qt15 3版本 在国产化平台或者自己编译的Qt版本时 没有Qt帮助文档 导致Qt很不好用 很容易把自己气死 在国产化平台或者自己编译的Qt版本时 没有Qt帮助文档 导致Qt很不好用 很容易把自己气死 链接 link 链接 h
  • 2023华为OD机试真题【保密大楼乘坐电梯】

    题目内容 有一座保密大楼 你从0楼到达指定楼层m 必须这样的规则乘坐电梯 给定一个数字序列 每次根据序列中的数字n上升n层或者下降n层 前后两次操作的方向必须相反 规定首次的方向向上 自行组织序列的顺序按规定操作到达指定楼层 求解到达楼层的
  • html5input输入框设置无边框_HTML 中的 box-border 盒子边框详解

    border 盒子边框 复合属性 设置对象边框的特性 盒子边框三要素 边框粗细 边框样式 边框颜色 语法 border border width border style border color 边框四边的粗细 样式 颜色 以及上下左右每
  • Mac更新之后使用终端提示:The default interactive shell is now zsh.

    1 美图 2 概述 升级完系统之后还遇到了另一个问题 就是在终端下查看的时候会在打开输入内容时有提示 默认的交互shell现在是zsh 要更新您的帐户以使用zsh 请运行 chsh s bin zsh 详情请访问https support
  • QT之滑动切换UI框架

    简介 使用QT制作一个UI图片切换框架 思路 主要通过移动像素坐标差值来判断方向 左上角坐标为 0 0 右加左减 松开减去按压时的横坐标大于0则右移 否则左移 代码展示 define X Threshold Direction 4 X方向移
  • 惠普m132nw清零方法_惠普HP打印机墨盒清零方法

    hp816 hp817是惠普多款打印机产品的标配墨盒 由于适应机型多 这两款墨盒是目前非常畅销的 对于很多用户来说 使用原装墨盒未必是最佳能选择 对使用完毕的墨盒进行加墨是很通常的选择 但注墨之后墨盒计数器的清零非常关键 在此 就为各位传授
  • GO语言实现二叉树基本功能

    用GO语言和用C语言写的思路没有区别 都是利用递归来解决遍历难的问题 这里值得注意的是 在GO中用switch case是完全可以代替if else的 个人觉得在做多项判断时用switch case来写不仅效率更高 思路也更清晰 也使得代码
  • 【目录】从0到1玩转分布式锁底层原理

    一 课程目录 分布式锁是什么 为什么需要分布式锁 如何用MySQL实现一把分布式锁 Redis实现分布式锁的核心原理以及利弊 分布式锁核心类库Redisson初识 Redisson加锁的核心底层源码 Redisson锁是如何做到可重入和互斥
  • 离散行业和流程行业的区别

    所谓离散型生产企业主要是指一大类机械加工企业 它们的基本生产特征是机器 机床 对工件外形的加工 再将不同的工件组装成具有某种功能的产品 由于机器和工件都是分立的 故称之为离散型生产方式 离散行业是指制造企业中的一类企业 他们的最主要特征为
  • 八、C语言进阶:内存

    8 内存 8 1 内存四区 8 1 1 栈区 stack 由编译器自动分配和释放 主要是存放函数参数的值 局部变量的值 8 1 2 堆区 heap 由程序员自己申请分配和释放 需要malloc calloc realloc 函数来申请 用f