先了解存储单元,内存(一般是2G)里的存储单元是以字节为单位的,每一个字节有一个编号,如下图:
以上表示的是某一段内存(H表示地址是以16进制表示的)。
存储单元从零开始编号,这些编号可以看作存储单元在内存中的地址。就像一条街,每个房子都有门牌号码。
CPU从内存中读数据,首先要指定存储单元的地址,也就是说它要先确定它要读取哪一个存储单元中的数据。就像在一条街上找人,先要确定他住在哪个房子里
现在,我们只需要知道,我们的数据就是存在上面的内存单元中。
定义一个整型数据:int n;
内存单元的地址是以16进制表示的,做个小实验
#include<stdio.h>
main() {
int n;
printf("%d\n", &n);
printf("%x\n", &n);
printf("%d\n", n);
printf("%x\n", n);
};
我假设,int n;n申请的内存为:
注意:编译器给n分配内存是随机的,只要一段内存内有四个没有被占用的连续内存单元,这段内存就有可能分配给n。此处我们认为编译器把104H到107H的内存单元分配给了n。
那么n和104H的区别是什么呢,它们都是这段的内存的名字,只是因为,16进制形式的名字不好记,所以换个名字叫n,n就代表这段四个字节的内存。那如何怎么表明这种代表性?,printf(“%x”,&n);它输出的结果为104(H是16进制的标志,就像十进制的d,你输出十进制的数没有输出d吧),也就是说&n是n这段内存的首地址(一段内存的地址就是这段内存的首地址)。再看printf(“%x”, n);
它输出的是这段内存中存的数据,你没有赋值,那么输出的东西就是随机的十六进制数(它有可能是不用的数据也有可能是CPU执行过的指令,记住,不管是数据还是指令,在内存中都是以01形式表示的)。
对上面的有了了解后,现在来看指针。
int *a;
float *b;
char *c;
上面定义了三个指针变量a、b、c。这里我还是用上图来假设他们的内存关系(这里的假设是有可能存在的)
指针变量是a,b,c,其实它和上面的n有相同之处,上面的n是整型变量,a是指针变量,n里面存的是整型数据,a里面存的是地址,什么地址呢?注意,很关键:这个地址是一段存放整型数据的内存的首地址,看上面图就明白了。这就是指针。
这里还有一个很重要的概念:上面a、b、c存102H、107H、10CH的空间多大,这个内存空间和你定义是什么样类型的指针木有关系
在编译器里定义一个指针变量,编译器会给这个指针变量分配一个空间,这个空间里存放的是一段内存的首地址,先解释一段内存,一段内存的大小是与你所定义的指针类型相关的,比如int,这段内存占四个字节(当然要看你的机器是多少位的了),则这段内存的首地址是第一个字节的地址,如char类型,占一个字节,这段内存的首地址就是这个字节的地址,还如结构体类型,此时内存大小要看该结构体的所有属性所占内存之和。现在解释这个空间,编译器给指针分配的空间大小是和CPU的寻址长度相关的,比如32位的CPU,它的寻址长度为32位,那么这个空间也就占四个字节,其实不管你定义什么样的指针类型,这个空间只是用来存地址,只占四个字节,而真正该空间所存的地址是哪一段内存的首地址才和所定义的指针类型相关。
再来看看结构体指针
#include<stdio.h>
struct node {
char b;
int *n;
struct node *next;
};
main() {
}
你们比较困惑的估计就是上面的东西了,最近学的东西都有结构体,结构体指针,好,现在来一点点解释。
还是假设出这个结构体在内存中的样子:
姑且认为(其实深层次的很纠结的,想弄明白的可以去Google)结构体node所占的内存是里面元素所占内存之和,注意这里的内存是连续的。
struct node *p;
p = (struct node *)malloc(sizeof(struct node));
上面是动态分配一段结构体内存,sizeof(struct node)的值为9,也就是9个字节,p是一个结构体指针,它和其它类型的指针没有什么两样,只不过这个指针里面的地址是一段结构体内存的首地址,也就是“102H”
一个小问题:p+1是什么意思?
int *n; n+1就是向后移动4个字节,因为sizeof(int)=4,p+1,就是向后移动9个字节,
那么《数据结构》P46,
int stacksize;//当前已分配的存储空间,以元素为单位
这个元素应该知道是什么意思了,就是stacksize的1代表9个字节。