指针
指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。 要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的 类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区。让我们分别说明。
先声明几个指针放着做例子:
例一:
(1)int*ptr;
(2)char*ptr;
(3)int**ptr;
(4)int(*ptr)[3];
(5)int*(*ptr)[4];
指针的类型
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:
(1)int*ptr;//指针的类型是int*
(2)char*ptr;//指针的类型是char*
(3)int**ptr;//指针的类型是int**
(4)int(*ptr)[3];//指针的类型是int(*)[3]
(5)int*(*ptr)[4];//指针的类型是int*(*)[4]
指针所指向的类型
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
(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为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?
指针本身所占据的内存区
指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。
指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。
1 nt 2 main() 3 { 4 int a =12; 5 int b; 6 int *p; 7 int **ptr; 8 9 // &a 的结果是一个指针,类型是int*,指向类型int,指向a的地址 10 p = &a; 11 12 printf("&a = 0x%d\n",&a); //0x1606416840 13 printf("*p = %d\n",*p); //12 14 printf("p =0x%d\n",p); //0x1606416840 15 printf("&p = 0x%d\n",&p); //0x1606416824 16 17 //*p的结果,在这里它的类型是int,它所占用的地址是p所指向的地址,显然*p就是变量a 18 *p = 24; 19 20 printf("*p = %d\n",*p); //24 21 printf("a = %d\n",a); //24 22 printf("p = 0x%d\n",p); //0x1606416840 23 printf("&p = 0x%d\n",&p); //0x1606416824 24 25 26 //&p 的结果是个指针,该指针的类型是p的类型加个*,在这里是int**,该指针的指向类型是p的类型,即int *, 27 //该指针的地址是p指针的地址 28 ptr = &p; 29 30 printf("ptr = 0x%d\n",ptr); //0x1606416824 31 printf("**ptr = %d\n",**ptr);//24 32 printf("*ptr = 0x%d\n",*ptr); //0x1606416840 33 34 //*ptr是个指针,&b也是一个指针且这两个指针的类型和所指向的类型是一样的,所以用&b来给*ptr赋值就是毫无问题的了。 35 *ptr = &b; 36 37 printf("ptr =0x%d\n",*ptr); //0x1606416836 38 printf("&b = 0x%d\n",&b); //0x1606416836 39 //*ptr的结果是ptr所指向的东西,在这里是一个指针,对这个指针再做一次*运算,结果就是一个int类型的变量。 40 **ptr = 36; 41 42 printf("**ptr = %d\n",**ptr); //36 43 printf("b= %d\n",b);//36 44 45 }
1 void MyFun(int x); //这个申明也可写成:void MyFun( int ); 2 void (*FunP)(int ); //也可申明成void(*FunP)(int x),但习惯上一般不这样。 3 4 int main(int argc, char* argv[]) 5 { 6 MyFun(10); //这是直接调用MyFun函数 7 FunP=&MyFun; //将MyFun函数的地址赋给FunP变量 8 (*FunP)(20); //这是通过函数指针变量FunP来调用MyFun函数的。 9 } 10 11 void MyFun(int x) //这里定义一个MyFun函数 12 { 13 printf("%d\n",x); 14 }
void myFun1(int x); void myFun2(int x); void myFun3(int x); typedef void (*FunType)(int ); void CallMyFun( FunType fp, int x); int main() { CallMyFun(myFun1,10); CallMyFun(myFun2,20); CallMyFun(myFun3,30); } void CallMyFun( FunType, int x) { fp(x); } void myFun1(int x ) { printf("myFun1函数输出:%d\n",x); } void myFun2( int x) { printf("myFun2函数输出:%d\n",x); }