继续上篇指针未完成的学习任务。
- 指向函数的指针
- 指向指针的指针
- 指向指针数组的指针
- 指向const 变量的指针
- const 指针变量
- void 指针
1.指向函数的指针
指向函数的指针包含函数的地址,可以通过指针调用该函数。下面这种格式声明了一个函数指针:
int (*fpt)();
指针的名字是fpt。这个特殊的指针指向一个返回整数值并且不接受实参的函数。指针声明必须与指针所指函数的声明相匹配。
下面的DEMO表明,一个函数指针在不同时段可以具有不同的函数地址:
#include
"
stdafx.h
"
#include
<
iostream
>
void
FileFunc(),EditFunc();
int
main(
int
argc,
char
*
argv[])
{
void
(
*
fileTmp)();
//
声明一个指针函数
fileTmp
=
FileFunc;
//
指向函数的地址
(
*
fileTmp)();
//
通过指针调用函数
fileTmp
=
EditFunc;
(
*
fileTmp)();
return
0
;
}
void
FileFunc(){
std::cout
<<
"
File Function\n
"
;
}
void
EditFunc(){
std::cout
<<
"
Edit Function\n
"
;
}
运行效果如下:
通过使用函数指针的数组,可以创建一个有限状态机,程序行为取决于变量的值,根据变量值确定程序接下来执行哪个函数。表格驱动的菜单管理程序就是一个有限状态机的例子。
如下DEMO演示了如何通过4个原型菜单分别显示一条消息:
#include
"
stdafx.h
"
#include
<
iostream
>
struct
Menu{
char
*
name;
void
(
*
fn)();
};
void
FileFunc();
void
EditFunc();
void
ViewFunc();
void
ExitFunc();
Menu menu[]
=
{
{
"
File
"
,FileFunc},
{
"
Edit
"
,ExitFunc
},
{
"
View
"
,ViewFunc
},
{
"
Exit
"
,ExitFunc
}
};
const
int
sels
=
sizeof
menu
/
sizeof
(Menu);
int
main(
int
argc,
char
*
argv[])
{
unsigned sel
=
0
;
while
(sel
!=
sels){
for
(
int
i
=
0
;i
<
sels;i
++
)
{
std::cout
<<
i
+
1
<<
"
:
"
<<
menu[i].name
<<
"
\n
"
;
}
std::cout
<<
"
select:
"
;
std::cin
>>
sel;
if
(sel
<
sels
+
1
&&
sels
>
0
)
{
(
*
menu[sel
-
1
].fn)();
}
}
return
0
;
}
void
FileFunc(){
std::cout
<<
"
File Function \n
"
;
}
void
EditFunc(){
std::cout
<<
"
Edit Function \n
"
;
}
void
ViewFunc(){
std::cout
<<
"
View Function \n
"
;
}
void
ExitFunc(){
std::cout
<<
"
Exit Function \n
"
;
}
运行效果:
2.指向指针的指针
指向指针的指针可能不太容易处理。需要两个星号声明指针。如下所示:
char** opp;
可以由此类推,三个四个等多个星星,对应指向几个指针的指针。
下面有一个DEMO演示如何使用一个被调用函数修改调用函数的局部指针,并处理指针数组:
#include
"
stdafx.h
"
#include
<
iostream
>
void
FindCredit(
float
**
fpp);
int
main(
int
argc,
char
*
argv[])
{
float
values[]
=
{
34.23
,
87.33
,
46.33
,
-
23.44
,
85.34
,
0
};
float
*
fp
=
values;
FindCredit(
&
fp);
std::cout
<<*
fp
<<
"
\n
"
;
return
0
;
}
void
FindCredit(
float
**
fpp){
while
(
**
fpp
!=
0
){
if
(
**
fpp
<
0
)
{
break
;
}
else
{
(
*
fpp)
++
;
}
}
}
运行效果如下:
上面程序用数组地址初始化fp 指针,并把fp 指针的地址传递给FindCredit函数,该函数将指向指针的指针作为其唯一形参的实参。FindCredit用**fpp表达式间接地提取数组元素值。FindCredit函数递增调用函数指针向数组的指针,而不是递增自己指向调用函数指针的局部指针,以便在数组的循环访问中查找负值。(*fpp)++;语句的含义是递增指针形参所指定的内容,。而当遇到负值则跳出循环体。程序结束。
3.指向指针数组的指针
指向指针的指针的另一种用法是处理指针数组。
下面的DEMO演示了如何通过指向指针数组的指针打印出数组内容:
#include
"
stdafx.h
"
#include
<
iostream
>
char
*
Names[]
=
{
"
Bill
"
,
"
Sam
"
,
"
Jim
"
,
"
Charles
"
,
"
Donald
"
,
0
};
int
main(
int
argc,
char
*
argv[])
{
char
**
nm
=
Names;
while
(
*
nm
!=
0
){
std::cout
<<*
nm
++<<
"
\n
"
;
}
return
0
;
}
运行效果如下:
如上代码,把nm 指针初始化为字符指针数组Names的地址。每个std::count调用都传递nm指针所指的字符指针,然后递增指针,指向数组的下一个元素(指针)。
4.指向const变量的指针
当我们声明一个指向const 变量的指针时,意味着程序不能通过指针修改变量。声明形式如下:
const char* str;
任何对str指针所指字符数据的引用必须为只读的。这种用法有几层含义。首先,不能将一个const 变量的地址赋予指针,除非指针按上面的方式声明。此外,如果函数的某个形参被声明为指向一个非const 的变量指针,就不能把const 变量的地址对应该形参的实参传递给函数。看如下DEMO:
#include
"
stdafx.h
"
#include
<
iostream
>
void
cpytoupper(
char
*
s1,
const
char
*
s2)
{
char
*
s
=
s1;
std::cout
<<
"
const :
"
<<
s2
<<
"
\n
"
;
}
int
main(
int
argc,
char
*
argv[])
{
char
*
rcv
=
"
terry
"
;
const
char
snd[]
=
"
Hello, terry
"
;
cpytoupper(rcv,snd);
std::cout
<<
rcv
<<
"
\n
"
;
return
0
;
}
运行效果如下:
5.const指针变量
我们可以定义在初始化后就不能改变自身内容的指针,这种做法可以增加代码的安全性。如果指针永远不用于迭代,换言之,如果这个指针永远保持其初始值,就按下面的方式将其声明为const指针变量:
char* const ptr=buf;
这里就不细究了。
6.void 指针
void 指针可以指向任何类型的变量,其声明方式如下:
void* vptr;
任何地址都可以赋给void 指针,除非使用了类型强型转换,否则就不能用void 指针来取出一个变量值。
关于指针的学习,暂时到这里,以后再回头来加深下理解。