对char * const *(*next)(); char * (*c[10])(int **p)的理解从而引发的对函数指针的理解以及const修饰符的用法理解

首先来看下这两句代码:

char * cosnt *(*next) ();

char * (*c[10])(int **p);

如果不是对函数指针有一定了解的人就不清楚这两句代码是什么意思,其实这两句分别声明了两个函数指针。但如果对函数指针的理解不深刻,或者对const修饰符的用法不是很了解,理解这两句代码也是有困难的。因此我基于对这两句代码的理解整理了一下对函数指针的理解以及对const修饰符的理解,并在文章最后对这两句代码进行解释。

————————————————————我是华丽的分割线——————————————————

函数指针

首先来看一下正常调用函数的方法:
void fun1();

int main() {
fun1();
return 0;
}

void fun1() {
printf("Function fun1 is called!\n");
}

输出结果为:
Funcstion fun1 is called!

但实际上每个函数在内存中都是有一个地址的,存在地址也就意味着可以利用指针来进行调用,指向函数的指针就被成为函数指针,以下就是使用函数指针的代码:
void fun1();

int main() {
void (*pFun)();
pFun = fun1;
(*pFun)();
return 0;
}

void fun1() {
printf("Function fun1 is called!\n");
}

输出结果为:
Function fun1 is called!

可以发现两种方法的结果是一样的,都成功调用了函数fun。

现在来介绍一下函数指针的用法:
1.声明函数指针
声明函数指针需要三个部分,分别是函数指针的返回类型,函数指针变量名以及参数。如声明了一个函数指针为
int (*pFun)(int)
则声明了一个函数指针名为pFun,该指针指向一个返回类型为int,参数列表为(int)的函数,需要注意的是,函数指针的声明与其他指针的声明一样,需要在 指针前面加上一个*。

2.给函数指针赋值,令函数指针指向函数
通过第一步我们声明了一个函数指针,但还没给这个指针赋值,该指针不指向任何一个函数,也就无从调用。因此需要对指针赋值,令它指向某一个函数。
给函数指针赋值的方式有两种,拿上面的代码举例:
1.pFun = fun;
2.pFun = &fun;
需要注意的是,只要是返回类型和参数列表和该函数指针声明的返回类型和参数列表相同的函数都可以给该函数指针赋值。如下:
void fun1();
void fun2();

int main() {
void (*pFun)();
pFun = fun1;
(*pFun)();

pFun = fun2;
(*pFun)();
return 0;
}

void fun1() {
printf("Function fun1 is called!\n");
}

void fun2() {
printf("Function fun2 is called!\n");
}

输出结果为:
Function fun1 is called!
Function fun2 is called!

这也是函数指针的灵活性所在,通过这种特性,我们可以实现对函数的动态调用,类似于JAVA的多态。

3.通过函数指针调用函数
完成了函数指针的声明以及赋值后,我们就可以通过函数指针来对函数进行调用了。
函数指针的调用也有两种方式,拿上图代码示例:
1.(*pFun)();
2.pFun():
一般推荐使用第一种方式,因为第一种方式明确表示了是使用函数指针来调用函数。

另外,我们可以像声明其他类型的数组一样来声明函数指针数组,如下:
void fun1();
void fun2();

int main() {
void(*pFun[2])();
pFun[0] = fun1;
pFun[1] = fun2;
(*pFun[0])();
(*pFun[1])();

return 0;
}

void fun1() {
printf("Function fun1 is called!\n");
}

void fun2() {
printf("Function fun2 is called!\n");
}

输出结果为:
Function fun1 is called!
Function fun2 is called!

const修饰符

const修饰符表示常类型,即只读。被const修饰符修饰的变量无法写入修改,只可以读取。
但相当一部分人并不能很好地理解以下三句代码的区别:
1.char * const p;
2.const char * p;
3.char const *p;
第一句代码的意思为声明一个只读的指向一个char字符的指针p;第二句代码的意思为声明一个指向只读char字符的指针p;第三局代码的意思与第二句的相同
这里有一篇 博客是讲述如何理解这三句代码区别的,讲的很好,但是这种方法不利于平时理解代码。因此在这里我讲述一下我自己的一种理解方法。

首先介绍一下我理解指针声明的一种思维:
例如,我们声明了一个指针为:int ** p;
我会将这句声明分为三个部分,用三个括号分开,(int *) (*) (p),第一个部分(int *)表示指针p指向的数据的类型为int指针,第二个部分(*)表示该变量是一个指针, 第三个部分(p)表示该指针变量的变量名。为了更好地理解多重指针以及const修饰符修饰的对象,我一般会给指针指向的数据加个临时变量名,便于理解。例如之前那个 指针,我会理解为{  [ int (temp2) ] (*)(temp1)  }(*)(p),即p是一个指针,它指向temp1,而temp1也是一个指针,它指向int型数据temp2。
乍看之下,这种对于指针的理解十分麻烦,但一旦熟练了之后,对于指针的理解是十分迅速的,并且无论多么复杂的指针都可以很清楚地理解。另外,这种理解方式 对于const修饰符修饰的对象也能够很好地确定。

其次需要确定const修饰符修饰的对象:
const修饰符只能向后修饰,不能向前修饰,即const的作用范围是const后面的对象,且const后面只能是变量,或者是非指针类型名,在第二种情况下,const修饰的是 非指针类型名后面的变量。如int const p等同于const int p,但int *const p 不等同与const int * p。
接着结合上面讲述的对于理解指针声明的思维,我们可以很好地对含有const修饰符的指针变量进行理解。但有读者可能会问,如果一个指针含有const修饰符,那么加 入的临时变量名应该放在哪里?答案是放在const后面。我们举几个例子就能明白了。
1.char *const p => (char) (*) (const p) =>(char temp1) (*) (const p) => p是一个const指针,它指向一个char型数据temp1.
2.const char * p => (const char temp1) (*) (p) => (char const temp1) (*) (p) => p是一个指针,它指向一个const修饰的char型数据temp1
3.char const *p => (char const temp1) (*) (p)  => p是一个指针,它指向一个const修饰的char型数据temp1
4.const char * char * p => (const char * const) (*) (p) => ( (const char temp2) (*) (const temp1) ) (*) (p) => p是一个指针,它指向一个const指针temp1,而temp1指向 const修饰的char型数据temp2
5.const char * const * const p => (const char * const) (*) (const p) => ( (const char temp2) (*) (const temp1) ) (*) (const p) => p是一个const指针,它指向const指针 temp1,temp1指向const修饰的char型数据temp2.
6.const char ** const * const p => (const char ** const) (*) (const p) => ( (const char *) (*) (const temp1) ) (*) (const p) => ( ( (const char temp3) (*) (temp2) ) (*) (const temp1) ) (*) (const p) => p是一个const指针,它指向const指针temp1,temp1指向指针temp2,temp2指向const修饰的char型数据temp3.
从以上6个例子可以看出,应用我所讲述的方法可能很清楚地理解含有const的多重指针。

回归正题

现在可以运用上面的理解来解释文章开头的两句代码的含义了:
首先第一句的含义是声明了一个函数指针next,它指向参数列表为空,返回类型为char * const *的函数,该函数的返回类型具体含义为(char (*) (const temp1) ) (*) (p) =>返回一个指针p,p指向const指针temp1,temp1指向char型数据。
第二句的含义是声明了一个函数指针数组c[10],其中的每个函数指针都指向参数列表为(int **p),返回类型为char *的函数。
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值