指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区。让我们分别说明。
先声明几个指针放着做例子:
例一:
(1)int*ptr;
(2)char*ptr;
(3)int**ptr;
(4)int(*ptr)[3];
(5)int*(*ptr)[4];
#include <stdio.h>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
//指针在定义的时候要说清楚指针的类型
//(1)int*ptr;
int a=10;
int *ptra=&a;
cout<<"对象a的地址: "<<hex<<(int)&a<<endl;
cout<<"指针ptra的地址 : "<<hex<<(int)&ptra<<endl;
cout<<"指针ptra中存的地址 : "<<hex<<*((int*)(&ptra))<<endl;
//如何求一个指针ptra中存放的变量地址:*((int*)((int)&ptra))
//先取指针的地址:(&ptra)
//强制将地址转换为int*:(int*)((int)&ptra)。这一步完全是为了下一步指针解引用解引用。
//将指针解引用即可得到指针中存放的变量地址:*((int*)(&ptra))
//(3)int**ptr;这个申明应该写成(int*) *ptr ----- ptr是一个指针,指向的数据类型是int*.
int* *ptr=&ptra;
cout<<"ptra中存的地址 : "<<hex<<(int)(*ptr)<<endl;
cout<<"ptr的地址 : "<<hex<<(int)(&ptr)<<endl;
//(4)int(*ptr)[3];这个也是一个指针,但是指针的类型貌似不太容易看出来
typedef int (*PTR)[3];
int array[3]={1,2,3};
PTR ptr_array=&array;
//这样是不是很清楚了,ptr其实是这样一个指针,它指向的是一个int类型的数组,并且这个数组的大小是3.
cout<<"数组元素array[0]: "<<(*ptr_array)[0]<<endl;
cout<<"数组元素array[1]: "<<(*ptr_array)[1]<<endl;
cout<<"数组元素array[2]: "<<(*ptr_array)[2]<<endl;
//对ptr_array解引用就是数组首地址
//当然不使用typedef也是可以的,过于但是看起来复杂
int (*ptr_array1)[3]=&array;
cout<<"数组元素array[0]: "<<(*ptr_array1)[0]<<endl;
cout<<"数组元素array[1]: "<<(*ptr_array1)[1]<<endl;
cout<<"数组元素array[2]: "<<(*ptr_array1)[2]<<endl;
//(5)int*(*ptr)[4];这个又复杂了一些。实际上应该是(int*) (*ptr)[4];这个数组中
//那么这里ptr也是一个指针,指针指向一个大小为4的数组,数组中的数据类型为int*。说明ptr指向的数组中是四个指针。
//按照上面的再来一遍
int cell1=100;
int cell2=12;
int cell3=13;
typedef int* (*PTRP)[3];
int* point_array[3];
point_array[0]=&cell1;
point_array[1]=&cell2;
point_array[2]=&cell3;
PTRP pointptr_array=&point_array;
cout<<"cell1的地址:"<<hex<<(int)(&cell1)<<endl;
cout<<"cell1的地址:"<<hex<<(int)((*pointptr_array)[0])<<endl;
cout<<"cell1的值:"<<dec<<cell1<<endl;//这句话很重要的是那个dec。将输出流十六进制换成十进制。
cout<<"cell1的值:"<<*(*pointptr_array)[0]<<endl;
cout<<"cell2的地址:"<<hex<<(int)(&cell2)<<endl;
cout<<"cell2的地址:"<<hex<<(int)((*pointptr_array)[1])<<endl;
cout<<"cell2的值:"<<dec<<cell2<<endl;//这句话很重要的是那个dec。将输出流十六进制换成十进制。
cout<<"cell2的值:"<<*(*pointptr_array)[1]<<endl;
return 0;
}
指针的类型
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:
(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语言指针所指向的类型
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
(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越来越熟悉时,你会发现,把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念,是精通指针的关键点之一。
指针的值,或者叫指针所指向的内存区或地址
指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。 指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为si zeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?
C语言指针本身所占据的内存区
指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。
指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。