一.指针到底是什么
指针 VS 变量 --------指针 VS 地址
指针(pointer)到底是什么,弄清楚这个问题很重要,这是我们所讨论的话题的源头,而在阐述指针是什么之前,我们需要先来看一下变量的概念。
我们知道,计算机的内存(primary storage)被划分为多个存储单元,这些存储单元可以以单个或者顺序相连组成一个更大单元的方式被使用。每一个单独的存储单元都是一个字节(byte),它通常由8个位(bit)组成,每一个位可以表示的值只有0或1。每一个存储单元都被一个及其分配的标识唯一地表示,而这个标识就是地址。
下图表示了存储单元单独被操作时的情形,矩形表示存储单元,矩形内的内容是存储在这个内存单元的具体的值。矩形上方的数就是每个内存单元的地址。因为每个单元为一个字节,而每个字符型常量(character constant)所占据的正是一个字节,如下所示:
再来看下面的图:
这次的情况是顺序连成组进行操作,对于整型常量(integer constant),在32位计算机中需要四个字节来存储(有一点要声明,208位置的那个矩形里的1078345超出了int类型的范围,是long int类型,但ANSI C只规定了long型数据长度不小于int型,int型数据长度不小于short型,并规定int型为16位,long型为32位,然而很多编译器采取的策略是使long和int型数据占据相同的内存字节数,即全为32位),所以地址以4个单位增长(也就是说现在的一个矩形表示4个内存单元),这次矩形下面多了几个小写字母,存储在矩形里面的值不是固定唯一的,而是可变的。我们可以把矩形认为是一个变量(variable),每次我们要引用矩形里的值时,机器都是通过地址来定位(那个矩形)并取得其中的值的,而对于我们来说要记住这些地址几乎是不可能的,所以高级语言提供了用名字来访问内存位置的特性,它们就是变量名,即上图的a,b,c,d。
现在用变量名替换掉上图中的地址:
大家要注意,变量名与地址的关联是由编译器为我们实现的,具体的实现方式我们无需关心,但要清楚硬件仍然是通过地址访问内存位置的。接下来,继续看图:
来看新增的Ptr,同样是个变量,它也有地址,它的值是变量a的地址。至此可以给出指针的定义了:指针是一种用于存放另一个变量的地址的变量。上图中的Ptr就是一个指针,并且我们说它指向了变量a(因为Ptr的值是变量a的地址),要注意指针中只能存放地址,不能将一个整型量或者其他非地址类型(整型数0及具有0值的整形常量表达式除外,后面的文章会细致讲解)的数据赋给一个指针!
还有,指针这个词,由于是对pointer这个词翻译得来,完整的叫法应该是指针变量,由于指针变量中存的地址,而在很多英文资料中,指针(pointer)的涵义不完全都是指针变量,有时也指地址,请大家在阅读或参考资料时注意区分!
(注:本章及后续章节中用以表示内存的矩形中的值及其地址只是为了简洁易读从而采用十进制数表示。)
===================================================================================
1、硬件(机器)是通过地址访问内存位置的。
2、对于程序员来说要记住这些地址几乎是不可能的,所以我们让编译器将地址与一个名字关联起来,这样我们就可以不用地址,而是用与之关联的名字来代替,高级语言就用名字来访问内存位置的特性,这些与地址关联的名字就是变量名。
3、指针是一种用于存放另一个变量的地址的变量。
4、指针中只能存放地址,不能将一个整型量或者其他非地址类型(整型数0及具有0值的整形常量表达式除外,后面的文章会细致讲解)的数据赋给一个指针。
如:
char *p = 236; 错!因为它不是一个0值
char *p = (void *)236; 对!因为虽然它不是0值,但它是
char *p = 0; 对! 因为是整数0值
char *p = 0.0; 错!因为是非整数0值
char *p = 3-3; 对!
#define three 3
#define two 2
#define one 1
char *p = three - two - one ; 对!因为是零值常量表达式
char *p = three -two; 错! 因为是非零值,尽管他是常量表达式
char *p = NULL; 对! 因为NULL 就是一个地址零的宏 #define NULL (void*)0
1.采用NULL或空指针常量,如:int *p = NULL;或 char *p = 2-2; 或float*p = 0;都是OK的 !
2.取一个对象的地址然后赋给一个指针,如:int i = 3; int *ip = &i;
3.将一个指针常量赋给一个指针,如:long *p = (long *)0xfffffff0;OK的 !
4.将一个T类型数组的名字赋给一个相同类型的指针,如:char ary[100]; char *cp = ary;
5.将一个指针的地址赋给一个指针,如:int i = 3; int *ip = &i;int **pp = &ip;
6.将一个字符串常量赋给一个字符指针,如:char *cp = “abcdefg”;OK的 !