C语言学习之内存理解

一、程序运行为什么要内存

1.1 计算机的运行目的

就像你打工是为了赚钱一样,所以计算机运行的目的也是为了得到一定的结果。再出及结果之前还有一个很重要的东西就是过程,有的人注重结果,有的人注重过程,有的人注重结果和过程。就类似于函数:

//我只注重结果
int main(int aa,int b)
{
	return a+b;
}
//我只注重过程
int main()
{
	int c;
	c = a+b;
	printf("结果 = %d",c);
}
//注重结果和过程
int main()
{
	int c;
	c = a+b;
	printf("结果 = %d",c);
	return c;
}

程序的本质就是很多函数相继运行的过程,如果程序不运行,那么就只是相当于一个一个字模和数字组合起来的占用内存的渣滓。只有程序运行起来,我们才能得到结果。

1.2冯洛伊曼结构和哈弗结构

冯诺依曼结构:数据和代码放在一起;
哈佛结构:数据和代码分开存放。
代码就是函数,单片机代码放在flash中。数据就是全局变量,和局部变量单片机放在RAM中。

1.3动态内存DRAM,静态内存SRAM

动态内存:就是程序员而分配的内存,malloc,需要程序员自己去释放,free。
静态内存:内存自己分配的,不需要我们自己去释放,比如定义的一个数组啊什么的。

1.4为啥需要内存

因为越大的程序越需要很多的数据来支撑,而数据是存放在内存的,所以需要内存。
同时管理内存也是一个很重要的过程,因为内存不是无限大的,循环利用才是一个优秀程序员应该必备的。

二、位、字节、半字、字的概念和内存位宽

2.1什么是内存

硬件角度:就是电脑的一个配件,需要他才能组成一个完整的计算机。
软件角度:就是一个一个随机访问的东西,只要你给地址,就可以访问这个地址的内存。就相当于你在超市,你付钱就可以买到东西,你付什么东西的钱,就可以买到什么东西。

2.2内存的大小

内存的大小在理论上是无穷大的,因为我们可以不停的加加,类似于数数,我可以从一不听的往后数,当然我们不可乱数,必须按照规矩来(也就是每个内存的地址都是唯一的不能改变)。
在实际上,我们的内存是有限的,就向你不可能修一座无线高的大楼,所以用操作系统来说,32位操作系统我们的的可以操作大小就是2的32次方(当然可能有部分偏差,很实际的例子就是我们8G的优盘,空间只有7个多G,没有8G)

2.3内存存放的模型

32位的内存存放方式:
在这里插入图片描述

16位内存:

在这里插入图片描述

8位内存
在这里插入图片描述

现在基本都是用的32位的芯片的。

2.4内存位宽

从上面几张图看来,内存位宽都是2的偶数倍,1,2,4,8…
从软件上来讲,我们的位宽可以是非0的任意整数,1,2,3,4.5…都可以,但是硬件做不出来的啊,所以我们再市场上看到不到这种奇数型的内存。

2.5位,字节,半字、字的关系

位:1 bit
字节:8位(8 bit)
半字:16位(16bit)
字:32位(32 bit)
双字:64位 (64 bit)
这个不是唯一性,因为有很多操作系统,window,Linux等等、但是他们的关系是不变的。

三、内存的编址,寻址、对齐

3.1 内存的编址方式

在理论上来说,内存的就是一个个的格子,这个格子有编号,这个格子有大小,可以装东西。这个格子的编号(唯一)和大小都是永久绑定的,这就是编址。
在程序运行的的时候,CPU不关心你的格子在哪里,有没有按照顺序来,CPU只关心你的地址在哪里(编号是多少
)。
这句话很重要:
内存的编址是以字节为单位的。
就是这格子占用了多大的空间?这个空间是固定的,都是1个字节。(可以看下面那张图,0123这个所有的格子都是1个字节的)

3.2内存和数据类型的关系

C语言的基本类型:int、char、short、long、float…等等
int 之所叫整形的数据,是因为他和CPU的位宽是一样的,比如32位的CPU,他的整形数据占用4个字节就是32位。
数据类型必须和内存相匹配才能获得最好的性能,否则可能效率低下甚至不工作。

在32位系统中,定义变量对好用int型,因为效率高,原因就是在32位系统中本身的内存也是32位的,与之相匹配。
当然char类型和short类型也可以执行,但是效率没有int类型高。

3.3内存对齐

在这里插入图片描述

以这张图为例子:
我们定义一个int类型的变量,我们给他分配内存的方式:
对齐:0123 这几个内存给他
非对齐:1234、2345、3456这几个内存都给他。

有什么区别呢,我们把这个内存编址看成一层一层的楼,如果0123这四个人住在一起,他们及交流不需要上下楼,是不是比起1234,2345、3456这几种方式来说快捷很多啊。
再举个极端的例子,假设我们定义了2个变量,一个char类型,一个int类型。char类型先入住,把0号房间占用了,那么接下来的int类型住那几个房间呢,答案是4567,那么是不是123这三个房间就空了呢,是的没错。但是我们不在乎,我们有钱,空着就空着。因为现在内存不像原来那么贵重,所以我们可以适当的浪费内存,保证效率。就像我们去卖电脑,你不会去买运行慢的但是拥有一个1T内存的电脑来打游戏,而是会选择一个运行起飞的256G的电脑。

四、如何操作内存

4.1C 语言对内存地址的封装

int a;
a = 5;
a += 4;

举个例子:上面程序来说,int a的实质就是编译器帮我们申请了1个int类型的内存格子,并且把这个符号a与这个内存绑定,以后我们用a的时候,编译器就会直接找到对应的内存。但是我们不知道这个内存的地址,也不需要知道。

C语言数据类型的本质含义:表示一个内存的长度和解析方法。
如何理解:


(int) 0;
(char) 0;
(int *) 0; 
(char *) 0;

在这里插入图片描述
还是用这张图,首先地址里面有个地方存放的是0,我们就认为这个0从表格上的0号格子开始存储。
(int ) 0;首先int占用4个字节,从0开始存放0这个整形数,编译器看到这个0是一个整形数,需要占用4个格子,然后就把0123这四个格子一起给他,才能装下。
(char) 0;char占用一个字节,从0开始存放0这个整形数,编译器看到这个0是一个字符型,只要一个格子,所以就把0这个格子给他就好了。
(int *)0;这是一个整形指针,占用4个字节,从0开始存放0这个整形数,编译器看到这个0是一个指针,需要占用4个格子,然后就把0123这四个格子一起给他,才能装下。
(char *) 0;这是一个字符指针,占用4个字节,从0开始存放0这个整形数,编译器看到这个0是一个指针,需要占用4个格子,然后就把0123这四个格子一起给他,才能装下。

可以看到的是,0还是0他没变,只是他穿了不同马甲,但是他代表的是他对应的内存,让编译器认为他是那种类型。编译器不去刨根问底。看到他是什么类型,就给他分配对应类型需要占用的地址。
换个说法就是 int a;和char b;这两个定义a和b其实没有啥区别,你换成 int b和char a也是一样的,他的本质差距就是代表的地址不一样和编译器看待他的类型不一样(解析方法)。

4.2 用数组访问内存

int a;
int b[10];

区别在哪里:
int a:内存给a这个家伙分配4个字节大小的地址,并把为首的地址和a绑定起来.
int b[10]:内存给b这个家伙分配40个字节大小的地址,并把为首元素的的首地址和b绑定起来.

4.3用指针访问地址

记住一句话,指针就是地址。
int a;
int *p;
a和p都代表一个地址(假设为0x12345678);
int a代表的是以0x12345678这个地址开头的四个格子里面存放的一个整形数。
int *p代表的是以0x12345678这个地址开头的四个格子里面存放的一个地址,这个地址代表的内存单元里面存放的是一个整形数。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

永不秃头的程序员

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

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

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

打赏作者

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

抵扣说明:

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

余额充值