一,内存编址方式
1,内存在逻辑上就是一个一个的格子,这些格子可以用来装东西(里面装的内容就是内存中存储的数),每个格子都有一个编号,这个编号就是内存地址,这个内存地址(就是一个数字)和这个格子的空间(实质是一个空间)是一 一对应且永久绑定的。
2,程序运行时,CPU只认识内存地址,至于这个地址所代表的空间在哪里,怎么分布并不关心。因为硬件设计保证了按照这个地址就一定能找到这个格子,所以说内存单元的两个概念:地址和空间是内存单元的两个方面。
3,内存单元的单位有:位(1bit)、字节(8bit)、半字(一般16bit)、字(一般是32bit)。内存编址的单位是字节,这是一个关键。
4,内存编址可以用以下图形表征:
![](https://i-blog.csdnimg.cn/blog_migrate/2b15ba28cdee06e497642e2550a9f2ae.png)
二,内存和数据类型的关系
1,数据类型是用来定义变量的,而这些变量需要在内存中存储、运算。
2,内存编址的单位是字节,即一个逻辑上的内存格子是一个字节的长度,这是一个关键。
3,c语言中数据类型的本质含义是:表示一个内存格子的长度和解析方法。
数据类型决定长度的含义:一个内存地址(0x10000000),本来这个内存地址只代表了一个内存格子,即一个字节的长度,但实际上可以通过给它一个类型(int),让它有了长度(4),那么这个代表内存地址的数字(0x10000000)就能表示从这个数字(0x10000000)开头的连续的n(4)个字节的内存格子(0x10000000)+(0x10000001)+(0x10000002)+(0x10000003)。
数据类型决定解析方法的含义:一个内存地址(0x10000000)可以通过给这个内存地址不同的数据类型来指定这个内存单元格子中二进制数的解析方法。 例如:int(0x10000000),就表示(0x10000000)+(0x10000001)+(0x10000002)+(0x10000003)这四个字节连起来共同存储的是一个int型的数据,以int的方式解析二进制数。float(0x10000000),表示的是(0x10000000)+(0x10000001)+(0x10000002)+(0x10000003)这四个字节共同存储的是一个float数据,以float的方式解析二进制数。
所以说:不管是普通变量类型(int\short\float等)还是指针类型(int *\float *)只要记住,类型只是对后面的数字或符号(符号也就是和内存地址绑定的变量名,实际也是一个数字,都是内存地址)所表征的一种长度规定和解析方法而已。
4,C语言中的指针,全名叫指针变量,指针变量其实和普通变量没有任何区别。比如说,int a; int *p;其实没有任何区别,a和p都表示一个内存地址(0x20000000),但是这个内存地址(0x20000000)的长度和解析方法不同。a是int型,所以a的长度是4个字节,解析方法是按照int 的规定来的。p是int *类型,在32位系统中长度是4个字节,解析方法是以(0x20000000)开头的连续四个字节中存储了一个地址,这个地址所代表的内存单元中存放的是一个int型的数。
5,用数组来管理内存。数组管理内存和变量其实也没有本质区别,只是符号的解析方法不同。(普通变量、指针变量、数组其实都没有本质区别,都是对内存地址的解析,只是解析方法不一样)。但要注意的是:区分下数组的第一个元素(a[0])称为首元素;第一个字节的地址就称为首地址;首元素a[0]的首地址称为首元素的首地址。
#include<stdio.h>
int main(void)
{
int a[4] = {1,2,3,4};
int *p = NULL;
printf(" a = 0x%x \n",a); //首元素的首地址 0x8feae030
printf(" &a[0] = 0x%x \n",&a[0]); //首元素的首地址 0x8feae030
printf(" &a = 0x%x \n",&a); //首地址 0x8feae030
p = a+1;
printf("*p = %d \n",*(p-1)); // 1
p = &a[0] + 1;
printf("*p = %d \n",*(p-1)); // 1
p = &a + 1;
printf("*p = %d \n",*(p-1)); // 4
return 1;
}