内存==c语言1

一、程序运行为什么需要内存
1、计算机程序运行的目的
  • 结果和过程:用函数来做类比,函数的形参就是待加工的数据,函数本体是代码,函数的返回值为结果,函数的执行过程就是过程。
  • 代码示例:
    int add(int a,int b){//此函数的执行为了得到结果
    	return a+b;
    }
    void add(int a,int b{//此函数的执行重在过程
    	int c ;
    	c=a+b;
    	printf("c=%d\n",c);
    	return c;
    }
    int add(int a,int b){//此函数的执行重在过程,重在结果
    	int c;
    	c=a+b;
    	printf("c=%d\n",c);
    	return c;
    }
    
2、计算机程序的运行过程
  • 计算机程序的运行过程就是程序中多个函数相继运行的过程,函数运行的过程就是数据加工的过程。
3、冯诺依曼结构和哈佛结构
  • 冯诺依曼结构:数据和代码放在一起,一起寻址。(x86)
    哈佛结构:数据和代码分开放置,独立寻址。(ARM)
  • 代码:即函数
    数据:即全局变量、局部变量
  • 示例:在S5PV210中运行的Linux系统上,运行应用程序时,所有的应用程序代码和数据都放在DRAM中,这就是冯诺依曼结构;在单片机中,我们把程序烧写到Flash中。然后程序在Flash中原地运行,程序中所涉及到的数据(全局变量、局部变量)不能放在Flash中,必须放在RAM(SRAM)中,这就是哈佛结构。
4、动态内存DRAM和静态内存SRAM
  • (1) DRAM的存储原理是电容存储电荷的方式,SRAM的存储原理是触发器的方式。
    在这里插入图片描述
  • (2)SDRAM:同步动态随机存储器。
5、程序运行为什么需要内存?
  • 内存用来存放数据(和代码),即全局变量、局部变量等,而数据是程序得组成部分和处理对象,因此内存是程序运行的本质需求。越简单得程序运行需要得内存越小,越复杂得程序运行需要得内存越大。
  • 内存管理是编程一个很重要的知识点,我们学习很多编程的关键点都是为了内存管理,比如说数据结构和算法。
6、深入思考:如何管理内存
  • 从操作系统得角度说:
    • 操作系统掌握着所有得硬件资源,因为内存很大,所以操作系统把内存分成一个个页面(即是块,一般是4KB),然后以页面为单位进行管理。页面内则以字节为单位进行管理。其实操作系统内存管理的原理非常复杂,但对于编程人员来说,只需要利用好操作系统提供的内存管理API即可。譬如在C语言中使用malloc、free来进行内存申请与释放
    • 不带操作系统时,程序需要直接操作内存,编程者需要自己进行内存的计算和安排。
  • 从编程语言的角度说:不同语言提供了不同的内存管理接口
    • ①汇编:没有任何内存管理,内存管理全靠程序员自己,操作内存时直接使用内存地址,非常麻烦
    • ②C语言:编译器帮我们直接管理内存地址,通过编译器提供的变量名来访问内存,操作系统下如果需要大块内存可以通过API(malloc、free)来访问系统内存,而裸机程序中需要大块内存需要自己定义数据等来解决。
    • ③c++:对内存的使用进一步封装,我们可以用new来创建对象(其实就是为对象分配内存),使用完之后用delete来删除对象(即释放内存)。所以c++的内存管理比c语言更高级点,但是内存管理还是要程序员自己实现,使用完不释放会造成内存泄漏。
    • ④java/c#等:这些语言不操作内存,而是通过虚拟机来操作内存。虚拟机作为我们程序员的代理,帮我们处理内存释放的工作。
  • 总结:java/c#看起来似乎比c/c++更高级一些,但虚拟机的内存回收是需要付出一定性能代价的,当我们开发程序的速度非常在乎的时候,就会用java/c#等语言;当我们对程序的性能非常在乎的时候,就会用c/c++。
二、位、字节、半字、字的概念和内存位宽
1、什么是内存?
  • ①硬件角度:内存实际上就是电脑的一个配件(内存条)。根据不同的实现原理,可以把内存分为SRAM和DRAM(SDRAM\DDR1SDRAM\DDR2SDRAM、LPDDR5SDRAM)
  • ②逻辑角度:可以随机读写(给一个地址就可以进行访问);内存在编程中天然是用来存放变量的,c语言的一个变量就对应着内存中的一小段。
2、内存的逻辑抽象图
  • 逻辑上内存是由无穷多的小格子组成,每一个小格子对应着一个地址
  • 现实中的内存大小是有限制的,譬如32位的操作系统(32位系统是指32位数据线,但是一般地址线也是32位,即内存地址只有32位二进制数,所以逻辑上大小为2^32)内存限制就为4GB。实际上32位系统中的内存是小于等于4GB的。
3、位和字节、字和半字
  • 内存单元的大小单位有4个:位(1bit) 字节(8bit) 半字(一般是16bit) 字(一般是32bit)
4、内存位宽
  • 从硬件角度讲:内存的硬件实现本身是有宽度的,有些内存条是8位的,有些是16位的。需要强调的是内存芯片之间是可以并联的,通过并联8位的内存芯片可以实现16位或者32位的内存。(数字电路有提到过此知识)
  • 从逻辑角度讲:内存位宽在逻辑上是任意的,但实际硬件的位宽不是任意的,所以我们需要按照不同位宽的硬件特性来编程
  • 内存位宽是在一个时钟周期内所能传送数据的位数,位数越大则瞬间所能传输的数据量越大,这是内存的重要参数之一
三、内存编址共和寻址、内存对齐
1、内存编址方法
  • 将内存单元与地址唯一地、永久地绑定起来。
  • 地址和空间是内存单元的两个方面。
2、关键:内存编址是以字节为单位的
3、内存和数据类型的关系
  • c语言中的数据类型有char、short、 int 、long、 float 、double。
  • 数据类型是用来当定义变量的,而变量需要存储在内存中,所以数据类型必须和内存相匹配才能获得最好的性能。
  • 在32位系统中定义变量最好用int,因为这样效率高。原因是系统本身就是32位的结构,一次处理32位数据。在32位系统中定义bool类型的变量时系统内部也是用int实现的。
  • 在实际编程中要根据实际情况进行内存和效率的取舍。
4、内存对齐
  • 对齐访问很配合硬件,所以效率很高;
  • 非对齐访问因为和硬件不搭,所以效率不高
四、C语言如何操作内存
1、C语言对内存地址的封装
  • 用变量名来访问内存
  • 数据类型的含义:表示一个内存格子的长度和解析方法
  • 函数是一段代码的封装,函数名的实质就是这一段代码的首地址,所以说函数名的本质也是一个内存地址。
2、用指针来间接访问内存
  • 关于类型,不管是普通变量类型还是指针变量类型,只要记住:类型只是对后面的数字或符号(代表的是内存地址)所表征的内存的一种长度和解析方法的规定而已
3、用数组来管理内存
  • 数组管理内存和变量没有本质区别,只是符号的解析方法不同。
  • 数组中的第一个元素称为首元素,首元素的第一个字节的地址就是首元素首地址。
五、内存管理之结构体
1、数据结构这门学问的意义
  • 数据结构就是研究数据如何在内存中组织、加工的学问。
2、最简单的数据结构:数组
  • 将同种类型的变量组织起来,方便管理。
  • 优势:在内存中顺序存储,可用下标随机访问。
    劣势:所有元素类型必须相同,定义时必须给出大小且不能再修改。
3、结构体隆重登场
  • 结构体发明出来就是为了解决数组的第一个缺陷:数组中所有元素类型必须相同。
  • 代码示例:
struct people{
	int age;
	char name[10];
	int height;
};
4、题外话:结构体内嵌指针实现面向对象(节点)
  • 面向过程与面向对象:面向过程指把问题的解决步骤一步一步地拆分,按要求执行,最终解决问题;而面向对象则是把问题事务分解成各个对象,分类来解决问题。
  • C语言是面向过程的,但C语言写出来的Linux系统是面向对象的。
  • 用非面向对象的语言,不一定不能实现面向对象的代码,只是说用面向对象的语言来实现面向对象更加简单一些,因为语言本身就做了很多工作。
  • 代码示例:
struct s{
	int age;//普通变量
	int(*pfunc)(void);//函数指针,指向int xxx(void)这类函数
}
//使用这样的结构体可以实现面向对象,这样包含了函数指针的结构体就类似于面向对象中的class
六、内存管理之栈(stack)
1、什么是栈?
  • 栈是一种数据结构,C语言内存管理中使用栈来保存函数参数和局部变量。
2、栈管理内存的特点(小内存、自动化)
  • 先进后出(FILO),而队列是先进先出(FIFO)。
  • 栈的特点是入口即出口,只有一个口,另一个口是堵死的,所以是先进后出。而队列的特点是入口和出口都有,必须从入口进去,从出口出来,所以是先进先出。
3、栈的应用举例:局部变量
  • c语言中的局部变量是用栈来实现的,定义局部变量,对应操作是入栈(自动化);
    函数退出局部变量注销的时候,对应的操作是出栈(自动化)。
  • 栈的优点:方便、分配和回收都不用程序员自己操作,c语言自动完成
  • 定义局部变量但未被初始化吗,值是随机的,为什么?
    因为栈式反复使用的,并且每次使用完之后没有清零
4、栈的优势和劣势
  • 优势:自动化,不用程序员手动操作内存
  • 劣势:首先,栈式有大小的,所以栈内存大小不好设置。所以太小怕溢出,太大怕浪费内存(与数组类似)。其次,栈溢出的危害很大,一定要避免。所以我们在C语言中定义局部变量时不能定义太多或者太大(譬如不能定义int a[10000];使用递归来解决问题时一定要注意递归收敛)。
七、内存管理之堆(heap)
1、什么是堆
  • 堆是一种内存管理方式,其特点就是自由(随时申请、释放、大小块随意)
  • 堆内存是操作系统划分给堆管理器(操作系统的一段代码,属于操作系统内存管理单元)来管理的,然后向使用者(用户进程)提供API(malloc和free)来使用堆内存。
  • 什么时候需要使用堆内存?
    需要内存容量比较大时、需要反复使用及释放时,很多数据结构(譬如链表)的使用都需要使用堆内存。
2、堆内存管理的特点
  • 容量不限(常规需求都能满足)。
  • 申请及释放都需要手动进行,若使用完后没有释放则会造成内存泄漏,内存泄漏的堆积会导致内存溢出甚至系统崩溃。
  • (内存泄漏:申请(new/malloc)了一块内存,但是没有去手动的释放(delete/free)内存,导致指针已经消失,而指针指向的东西还在,已经不能控制这块内存)
3、C语言操作堆内存的接口
  • (1)堆内存申请时有三个功能类似的函数:malloc、calloc、realloc。
    • void *malloc(size_t size); // 申请指定大小的内存
    • void *calloc(size_t nmemb, size_t size); // 申请nmemb个内存单元,每个size字节
    • void *realloc(void *ptr, size_t size); // 改变已经申请的空间的大小
  • (2)堆内存释放最简单,直接调用free函数即可
    void free(void *ptr);
  • (3) 代码示例:
// 譬如要申请10个int元素的内存
malloc(40);
calloc(10,4);
  • (4)C语言定义数组时必须给出数组元素个数,且无法再修改。而在Java等高级语言中,则可以修改数组大小,其原理是重新创建一个新的数组,然后释放掉原数组。realloc的实现原理也类似。
4、堆的优势和劣势
  • 优势:灵活使用
  • 劣势:需要程序员处理释放等细节,容易出错,严重依赖程序员水平。
八、复杂数据结构
1、链表、哈希表、二叉树、图等
  • 链表:链表是最重要的,Linux内核中经常使用链表,驱动和应用的编写很多时候也需要链表,所以必须掌握链表:结构体的定义,链表的创建,链表的增、删、查,链表的逆序
  • 哈希表:不是很常用,一般不需要自己实现,直接使用别人实现的哈希表比较多。我们需要了解哈希表的原理、特点、适用场景。
  • 二叉树、图等:用于处理特定问题,很少使用,不必过于纠结。
2、为什么需要更复杂的数据结构
  • 因为现实中的实际问题是多种多样的,特定的问题可能需要特定的数据结构和算法来解决。
3、数据结构和算法的关系
  • 数据结构的发明都是为了配合一定的算法,算法是为了处理具体问题,其实现依赖于特定的数据结构
4、如何学习数据结构与算法
  • 数据结构与算法是相符相成的,要一起研究。
  • 数据结构与算法对嵌入式来说不全是重点,不要盲目地深入研究。
5、举例
  • Linux内核在管理字符设备驱动时,使用了哈希表(hash table,散列表),所以字符设备驱动的很多特点都和哈希表的特点有关。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栋哥爱做饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值