数组与指针:
先看下面一段代码:
#include <stdio.h>
int main()
{
int a[5]={5,4,3,2,1};
printf("%x\n", a);
printf("%x\n", a+1);
printf("%d\n", *a);
printf("%x\n", &a);
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(&a));
printf("%x\n", &a+1);
return 0;
}
输出结果:
22cc84
5
22cc80
20
4
22cc94
我们知道,数组名的值是一个指针常量,它的值为数组第1个元素的地址,并不表示整个数组,所以int a[5]; int *p = a 这两条语句就很容易理解了。二维和多维数组的数组名也是同样的意义,n维数组可以看做1维数组,该数组的元素是n-1维数组。例如,二维数组int matrix[3][3],可以看做一个1维数组,包含3个元素,每个元素是一个包含3个整型元素的数组,数组名matrix是一个指向它第1个元素的指针,所以matrix是一个指向包含3个整型元素的数组的数组指针,关于数组指针下面将会讨论。上面代码的第1条输出语句输出的是a[0]的地址,第2条语句为a[1]的地址,第3条语句为a[0]的值。
但是,数组名在做为取地址操作符&和sizeof的操作数时,并不是指向数组第1个元素的指针常量。&操作返回的是一个数组指针,sizeof返回整个数组的长度。第4条输出语句输出数组指针的值,注意,它和数组第一个元素的地址值是一样的,第5条语句输出数组的长度。第6条语句表明&a返回一个指针,第7条语句的输出和第4条语句的地址差值为20,刚好是数组是a的长度,证明&a返回的是数组指针。
数组指针:
int *p[ ]:[ ]运算符的优先级高于*,所以p先和[ ]结合,表示数组,数组中的元素的类型为int *,表示指向int类型的指针。该声明表示指针数组。
int (*p)[ ]:*先和p结合,意味着p是指针,p指向的元素的数据类型为int [ ]。该声明表示数组指针。
指针数组比较好理解,下面的代码主要分析数组指针。
#include <stdio.h>
int main()
{
int matrix[3][3]={{3,3,3},{2,2,2},{1,1,1}};
int (*p)[3] = matrix;
printf("%x\n", matrix);
printf("%x\n", matrix+1);
printf("%x\n", p);
printf("%d\n", sizeof(p));
printf("%x\n", *p);
printf("%d\n", sizeof(*p));
printf("%x\n", **p);
printf("%x\n", *p+1);
printf("%d\n", sizeof(*p+1));
printf("%x\n", *(*p+1));
return 0;
}
输出结果:
22cc70
22cc7c
22cc70
4
22cc70
12
3
22cc74
4
3
int (*p)[3]定义了数组指针,matrix是一个指向包含3个整型元素的数组的数组指针,第1、2条输出语句表明数组名matrix的意义,第3、4条语句说明p是一个指针,它的值和matrix相等。随后6条输出语句表明,数组指针解引用得到的是一个数组,类似于数组名,它的类型是指向数组中元素的指针。
函数指针:
看下面一段代码:
#include <stdio.h>
int func(int m)
{
printf("%d\n", m);
return 0;
}
int main()
{
int (*pf)(int);
pf = func;
pf(0);
(*pf)(1);
pf = &func;
pf(2);
(*pf)(3);
pf = *func;
pf(4);
(*pf)(5);
(&func)(6);
(*func)(7);
(******pf)(8);
printf("%x\n", func);
printf("%x\n", pf);
printf("%x\n", &func);
printf("%x\n", &pf);
printf("%x\n", *func);
printf("%x\n", *pf);
printf("%x\n", ******func);
printf("%x\n", ******pf);
return 0;
}
输出结果:
0
1
2
3
4
5
6
7
8
401050
401050
401050
22cca4
401050
401050
401050
401050
函数名是函数的入口地址,函数名被使用时总是由编译器把它转换为函数指针。所以语句pf=func和pf=&func是等价的,后一种赋值方式把编译的工作显示的执行了,对于语句pf=*func,编译器首先将func转换为函数指针,然后解引用,相当于把函数指针又转换为函数名,所以编译器还要再一次将其转换为函数指针。其他输出语句的&运算和*运算都可以按上述方法来理解。
参考:
1、C程序设计语言(K&R),中文版第二版
2、C和指针