指针详解
【1】指针包括哪些内容?
指针是一个特殊的变量,它所存储的数值被解释为内存的一个地址。
要了解一个指针需要搞清其四方面的内容:
(1)指针的类型
(2)指针所指向的类型
(3)指针的值 或者 指针所指向的内存区
(4)指针本身所占据的内存区
先声明几个指针作为例子:代码如下:
1 int *ptr;
2 char *ptr;
3 int **ptr;
4 int (*ptr) [3];
5 int * (*ptr) [4];
【2】指针的类型怎么分析?
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。
这是指针本身所具有的类型。让我们看看例一中各个指针的类型:
1 int *ptr; //指针的类型为int*
2 char *ptr; //指针的类型为char*
3 int **ptr; //指针的类型为int**
4 int (*ptr) [3]; //指针的类型为int(*)[3]
5 int * (*ptr) [4]; //指针的类型为int*(*)[4]
【3】指针所指向的类型怎么分析?
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
这句话很关键,多读几遍........
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。
下面我们看看各个指针所指向的类型:
1 int *ptr; //指针的类型为int
2 char *ptr; //指针的类型为char
3 int **ptr; //指针的类型为int*
4 int (*ptr) [3]; //指针的类型为int()[3]
5 int * (*ptr) [4]; //指针的类型为int*()[4]
在指针的算术运算中,指针所指向的类型有很大的作用。
指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。
当你对C 越来越熟悉时,你会发现,把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念,
是精通指针的关键点之一。
不少书就把指针的这两个概念搅在一起了。所以越看越糊涂。
【4】指针的值----或者叫指针所指向的内存区或地址怎么分析?
指针的值即就是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。
在32 位程序里,所有类型的指针的值都是一个32 位整数,因为32 位程序里内存地址全都是32 位长。
指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。
以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX 为首地址的一片内存区域;
我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。
在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:
这个指针的类型是什么?
指针指向的类型是什么?
该指针指向了哪里?(重点注意)
【5】指针本身所占据的内存区如何分析?
指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。
在32 位平台里,指针本身占据了4 个字节的长度。
指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。
【6】与指针相关的运算符有哪两个?
& 取地址运算符
* 间接运算符
&a 的运算结果也就是取变量a的地址,即就是获取变量a的指针。
指针的类型是a 的类型再加个*。
指针所指向的数据类型是变量a的类型。
指针的值 即就是指针所指向的地址,也就是变量a的地址。
*p 的运算结果就依情况而定了。总之*p的结果是p 所指向的那个玩意。
这个东西具备这些特点:它的类型是p 指向的类型,它所占用的地址是p所指向的地址。
【7】指针类型转换如何实现?
当我们初始化一个指针或给一个指针赋值时,赋值号的左边是一个指针,赋值号的右边是一个指针表达式。
在我们前面所举的例子中,绝大多数情况下,指针的类型和指针表达式的类型是一样的,指针所指向的类型和指针表达式所指向的类型是一样的。
示例如下:
1 float f = 12.3;
2 float *fptr = &f;
3 int *p;
在上面的例子中,假如我们想让指针p 指向实数f,应该怎么办?是用下面的语句吗?示例如下:
1 int *p;
2 p = &f;
不对。
因为指针p 的类型是int *,它指向的类型是int。表达式&f 的结果是一个指针,指针的类型是float *,它指向的类型是float。两者不一致。
直接赋值的方法是不行的。至少在我的MSVC++6.0上,对指针的赋值语句要求赋值号两边的类型一致,所指向的类型也一致。
其它的编译器上我没试过,大家可以试试。为了实现我们的目的,需要进行"强制类型转换":示例如下:
1 p =(int *) &f;
如果有一个指针p,我们需要把它的类型和所指向的类型改为TYEP * 和 TYPE,那么语法格式是: (TYPE *)p。
这样强制类型转换的结果是一个新指针,该新指针的类型是TYPE *,它指向的类型是TYPE,它指向的地址就是原指针指向的地址。
切记一点:而原来的指针p的一切属性都没有被修改。
一个函数如果使用了指针作为形参,那么在函数调用语句的实参和形参的结合过程中,必须保证类型一致,否则需要强制转换。
我们已经知道,指针的值就是指针指向的地址,在32 位程序中,指针的值其实是一个32 位整数。
那可不可以把一个整数当作指针的值直接赋给指针呢?就象下面的语句:
1 unsigned int a;
2 TYPE *ptr; //TYPE 是int,char 或结构类型等等类型。
3 a = 20345686;
4 ptr = 20345686; //我们的目的是要使指针ptr 指向地址20345686
5 ptr=a; //我们的目的是要使指针ptr 指向地址20345686
6 //编译一下吧。结果发现后面两条语句全是错的。那么我们的目的就不能
7 //达到了吗?不,还有办法:
8 unsigned int a;
9 TYPE *ptr; //TYPE 是int,char 或结构类型等等类型。
10 a = N; //N 必须代表一个合法的地址;
11 ptr=(TYPE*)a; //呵呵,这就可以了。
严格说来这里的(TYPE *)和指针类型转换中的(TYPE *)还不一样。这里的(TYPE*)的意思是把无符号整数a 的值当作一个地址来看待。
上面强调了a 的值必须代表一个合法的地址,否则的话,在你使用ptr 的时候,就会出现非法操作错误。
试想能不能反过来,把指针指向的地址即指针的值当作一个整数取出来。完全可以。
下面的例子演示了把一个指针的值当作一个整数取出来,然后再把这个整数当作一个地址赋给一个指针:
1 int a = 123,b;
2 int *ptr = &a;
3 char *str;
4 b = (int)ptr; //把指针ptr的值当作一个整数取出来。
5 str = (char*)b; //把这个整数的值当作一个地址赋给指针str。
现在我们已经知道了,可以把指针的值当作一个整数取出来,也可以把一个整数值当作地址赋给一个指针。
Good Good Study, Day Day Up.
顺序 选择 循环 总结