C语言的指针是C语言这门语言的精华所在,当然也是让很多人诟病的地方。
指针是什么?有这么一句话:“对于锤子来说,一切都是钉子。”那么换句话讲指针,即“对于指针来说,一切都是地址”。
内存是由一个个内存单元构成的,每个内存单元都有自己的地址。而指针就是用来存放这些地址的。凡是可以用指针来存储的变量,在指针看来它(变量)都是地址。
比如:
二级指针:
存放一个整型变量地址用一级指针来存放,int a=10; int* pa=&a;
指针变量也是变量,所以可以取的指针变量地址,存放一级指针变量地址用二级指针来存储。int *ppa=&pa
.依次类推,存放二级指针变量地址用三级指针变量来存储。
对于指针来讲,重难点便是和其它知识的结合运用,如下:
指针数组:
指针数组,顾名思义,指针数组它是一个数组,数组元素类型是指针类型。
在main()函数的参数中便用了这种类型:
第一个是一个int型变量,表示参数的个数。
第二个是一个字符串指针数组,数组中的每一个指针都指向一个字符串,这些字符串就是用户传给程序的参数,这些参数用用空格分开。
第三个是环境变量。
数组指针:
数组指针不同于指针数组,两者强调的重点更是不同。前者强调此为指针,后者强调此为数组。数组指针是用来存放数组地址的指针变量。如:
int arr[10];
int (*parr)[10]=&arr;
那么在二维数组中,我们便可以用数组指针来接收二维数组,比如用在函数参数。
int a[3][3]={1,2,3,4,5,6,7,8,9};
int (*pa)[3]=a;
函数指针
函数指针是指向函数的指针变量。 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是大体一致的。函数指针有两个用途:调用函数和做函数的参数。
double Add(double num1, double num2)
{
return num1 + num2;
}
int main()
{
double ret = 0.0;
ret=Add(3.0, 5.0);
printf("%lf", ret);
system("pause");
return 0;
}
以上为用直接调用函数的方式来实现函数调用。
用函数指针方式来调用函数方法如下
double (*pAdd)(double num1, double num2)=&Add;
int main()
{
double ret = 0.0;
ret=(*pAdd)(3.0, 5.0);
printf("%lf", ret);
return 0;
}
对表达式 double (*pAdd)(double num1, double num2)
进行分析,依据运算符优先级顺序,这个声明有两个括号,第一个括号聚组作用,第二个括号函数调用作用,括号里面是它的参数。第一个括号迫使间接访问在函数调用之前进行,进行解引用后,是一个函数类型,所以pAdd是一个函数指针。
实际上,在函数调用时函数名首先被转换为一个函数指针,该指针指定函数在内存中的位置。然后,函数调用操作符调用该函数,执行开始于这个地址的代码。
所以调用函数可以用三种方法
//第一种
ret=Add(3,4);//直接用函数名称调用函数
//第二种
ret=(*pAdd)(3,4);//用函数指针来调用函数。这种方法并不是必须的,因为编译器在执行函数调用操作符之前又会把它转换回去。
//第三种
ret=pAdd(3,4);
函数指针数组
上面讲过指针数组的概念和意义,同样,函数指针数组可以理解为(函数指针 数组),有一个数组,数组的元素类型为函数地址。代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
double Add(double num1, double num2)
{
return num1 + num2;
}
double Sub(double num1, double num2)
{
return num1 - num2;
}
//double(*pAdd)(double num1, double num2) = &Add;//函数指针pAdd
//double(*pSub)(double num1, double num2) = ⋐//函数指针pSub
double(*p[3])(double num1, double num2) = { Add, Sub };//函数指针数组
int main()
{
double ret = 0.0;
double result = 0.0;
ret = p[0](3.0, 5.0);
result = p[1](8.0, 2.0);
printf("%lf\n", ret);
printf("%lf\n", result);
system("pause");
return 0;
}
变量p是一个数组,数组大小为3,数组元素类型为函数类型。double(*p[3])(double num1, double num2)
。
可以用来实现转移表。
指向函数指针数组的指针
如上述中double(*parr[3])(double num1, double num2)
是一个函数指针数组,而函数指针数组的指针是一个指针,指向上面的表达式。
1,写出一个指针(*pparr)
2, 这个指针指向一个有三个元素的数组(*(*pparr)[3])
3,写出返回值和函数调用即完整的表达式为
double(*(*pparr)[3])(double num1, double num2)=&parr;
可以看到pparr是一个指针类型,这个指针指向一个含有三个元素的数组,每个元素是函数指针类型。