计算机现在功能虽然强大,但究其实质是0与1的变换,循环往复,以至无穷,故能成其大。正如老子所说“一生二,二生三,三生万物”、“世界万物生于有,有生于无”。所以在学习计算机课程的过程中,要劳劳掌握基础知识,掌握根本,然后再去求变,才能以不变应万变,方为上策。
内存与地址
在介绍指针之前,先让我来讲一讲计算机内存与地址。计算机内存可以看作是一辆火车,我们知道火车有很多节车厢,每一节车厢都有车厢编号(坐过火车的人都知道),每一节车厢就可比喻为计算机的一块内存,车厢里面有座位号,通过座位号就可以唯一的确定一个座位,座位号就好在这一个内存块的偏移量,通过它可以唯一确定的数据存储的位置。
注意,内存中的每个位置由一个独一无二的地址标识,内存中的每个位置都包含一个值。
现在举例说明内存中数据存储,如下表,表中加粗边框部分表示内存中实际存储的数据,无边框部分表示内存单元的地址。
10000 | 10004 | 10006 | 10008 | 10012 | 10016 |
110 | -1 | 16 | 1234567890 | 10000 | 10008 |
仔细的人也许会看到,对-1或16只占了两个字节,可粗略看作为short int类型数据,110在内存中占了4个字节,可粗略看作是int类型,而1234567890则可粗略看作是浮点型数据,所以应该了解虽然是同样一块地址,也可能存放不同类型的数据。
如果你能记住一个值的存储地址,你就可能根据这个地址取得这个值。但是要记住所有这些地址实在是太笨拙了(因为内存的地址并不像上表中表示的那么简单),所以高级语言所提供的特性之一就是通过名字而不是地址来访问内存的位置。下面这张表与上表相同,但这次使用名字来代替地址。
a | b | c | d | e | f |
110 | -1 | 16 | 1234567 | 10000 | 10008 |
从上表中可以看出,当地址抽象成我们比较容易接受的名字时,对编程来说就变得简单,这些名字就是传说中的变量。不过有一点非常重要,你必须记住,名字与内存位置之间关联并不是硬件所提供的,它是由编译器为我们实现的。所有的这些变量给了我们一种更方便的方法记住地址——硬件仍然通过地址访问内存位置。
好了,我们再来看看上面的两张表,我有一个问题,对于变量e中存储的内容到底代表一个值还是一个地址呢?
问题很简单,不能确定。
例1:
inta = 110;
int*e = &a;
例1中e代表一个地址,这个地址指向了整型变量a。
例2
int e = 10000;
例2中e则代表一个值。
我们已经知道定义变量时需要类型,编译器实现了变量与内存位置之间关联,那变量的类型又是干什么呢?变量名相当于帮我们找到了那个内存,而变量类型则告诉编译器从变量所指向的那个内存位置起取几个字节。如int a =110; 则是从10000(a对应内存地址)起取4个字节,所以从10000到10003这段地址就是变量a存储的空间,从而变量a共有232个取值。
而short int b = -1;代表从10004开始取sizeof(short int)个字节,也就是10004、10005这2个字节。其他的可以以此类推。
针对类型我们可以这样理解,还是拿坐火车为例,当一个出行的时候,买一张票就可以,这种情况相当于(char类型);某一天刚好和女朋友出去旅游,买一张票显然不够了,就得买2张票(short int类型);如果一个宿舍4个人准备去旅游显示就得4张票(int,float类型);以此类推。火车相对不同的人不同需求分配座位,内存同样根据不同的变量分配不同的内存空间。理解了这些,对于复杂的类型如数组、结构体、联合体变量的定义内存分配就明白了。
以上这些是通过参考《C和指针》这本书,经过自己的一些编程体会所总结的,比如以火车来比喻内存之类。我写文章的目的,一方面是对自己所学的一种总结,另一方面是或许那些对指针感兴趣的朋友,而又迷惑的朋友有一点小小的帮助。在书写过程中如果有什么错误或者误解大家,还望大家不要吝啬自己的建议,在文章下留言,我会努力做好的!
欲知后事如何,请听下回分解!