二、指针与函数
1. 参数传递指针
函数的参数,除了传递普通的变量,引用之外,还可以把指针当成参数来传递
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #include <iostream>
using namespace std;
//函数原型
void double_data(int *int_ptr);
int main(){
int value{10};
//修改前,输出为10
cout << value << endl;
//在函数内部修改value的值
double_data(value);
//修改后,输出为20
cout << value << endl;
}
void double_data(int *int_ptr){
*int_ptr *=2;
}
|
在某些情况下,传递指针比其他方式的传递要合适得多,比如下面有一个函数负责交换传递进来的两个参数的值, 此时如果不使用指针或者引用,则无法实现该功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | #include <iostream>
using namespace std;
void swap(int *a , int *b);
int main (){
int x{100},y{200};
//交换前打印 x : 100 , y : 200
cout << x <<" = " << y <<endl;
swap(&x , &y)
//交换前打印 x : 200 , y : 100
cout << x <<" = " << y <<endl;
}
void swap(int *a , int *b){
int temp = *a ;
*a = *b ;
*b = temp;
}
|
2. 函数返回指针
函数平常除了返回标准的数值之外,其实也可以返回指针。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | #include <iostream>
using namespace std;
//返回两个参数中的最大者
int *calc_largest(int *ptr1 , int *ptr2);
int main(){
int a = 100;
int b = 200;
//使用指针指向最大数值
int *largest_ptr = calc_largest(&a , &b);
//输出:200
cout << *largest_ptr << endl ;
return 0 ;
}
int *calc_largest(int *ptr1 , int *ptr2){
//解引用获取到数据后比较 :
if(*ptr1 > *ptr2){
return ptr1;
}else{
return ptr2;
}
}
|
注意: 不要返回一个函数内部的一个局部变量指针 , 因为本地变量的声明周期应该只位于函数内部。一旦函数执行完毕则被释放。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | #include <iostream>
using namespace std;
int *do_this(){
int size = 10;
return &size;
}
int main(){
int *result = do_this();
std::cout <<"result = " <<result << std::endl;
return 0 ;
}
|
3. 二级指针
指向指针的指针,即可称之为二级指针。有点类似二维数组,数组里面装的是数组,即可称之为二维数组。
1. 二级指针介绍
2. 二级指针的应用
二级指针不如一级指针使用的那么频繁,通常出现的地方是作为函数参数传递。如果在函数的内部想要修改外部一级指针指向的数据值,那么则需要二级指针了。
如下示例所示, 如果传递的是一个一级指针,那么在外部的p依然没有被分配空间,传递进去的依然是一份值的拷贝而已 , 导致后面的指针赋值 为 42 也无法执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | //函数原型
void createPointer(int** p);
int main(){
//空指针
int* p = nullptr;
//在函数内部对该指针初始化
createPointer(&p);
//初始化完毕后,修改指向空间的数据
*p = 42;
//释放指针
delete p ;
return 0 ;
}
void createPointer(int** p){
// 解引用,得到的是一级指针,其实就是得到了外面的 p 那么整段话连起来就是 int *P = new int();
*p = new int();
}
|
4. 函数指针
1. 基本使用
函数指针的意思是指向函数的指针 。 通常来说,指针是变量,有自己的类型,那么函数指针也有类型。只不过它的类型稍微不一样而已。函数指针的类型由函数的返回值、函数的参数列表决定。 要想声明一个函数指针,只需要使用指针
来替换函数名
即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #include <iostream>
//函数原型
int add(int a , int b);
int main(){
int result = add(3,4);
std::cout << "result = " << result << std::endl;
return 0 ;
}
int add(int a , int b){
return a + b;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | #include <iostream>
using namespace std;
//函数原型
int add(int a , int b);
int main(){
//前半段表示声明一个函数指针add_ptr 该函数指针指向的函数返回值是int,并且有两个int类型的参数。
//指针的小括号不能省略。
int (*add_ptr) (int,int) =add;
//普通方式调用函数
int result =add(3,4);
cout << "result = " << result << endl;
//使用函数指针方式调用add函数
int result2 = add_ptr(3,4) ;
cout << "result2 = " << result2 << endl;
return 0 ;
}
int add(int a , int b){
return a + b;
}
|
2. 函数指针作为参数
有时候,也可以把某个函数A通过参数的方式传递给另一个函数B,随后在函数B里面执行传递进来的函数A。函数虽然不能直接作为参数来进行传递,但是函数指针可以。实际上在传递的时候,传递的是指针而已。
比如下面的示例: 有一个计算的函数calc
, 允许在第三个参数传递进来具体的计算函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #include<iostream>
using namespace std;
int add (int a , int b);
int calc(int a , int b ,int (*fun)(int, int));
int main() {
//函数指针p,指向add函数
//int(*p)(int ,int) = add;
//cout << calc(3,5 , p) << endl;
//函数名称可以直接使用,它实际上就是一个函数指针。
cout << calc(3,5 , add) << endl;
return 0 ;
}
int add (int a , int b){
return a + b;
}
//计算的函数,最后的参数要求的是一个函数指针。
int calc(int a , int b ,int (*fun)(int, int)){
return fun(a,b);
}
|
3. 函数指针的作用
如果一个通用的函数,需要使用到 另一个函数,但是这个函数并没有确定名称,是由其他组织或者个人开发的,那么这时候可以预留一个位置,做成函数指针 虚位以待。比如:现在有一个vector或者数组,需要交给其他个人或组织来遍历,但是这些组织或者个人的遍历手法不一样,那么这时候可以使用函数指针占位。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | //函数原型
void listScore(vector<int> scores , void (*ps)(vector<int>));
void printScore1(vector<int> scores);
void printScore2(vector<int> scores);
int main() {
vector<int> scores {50,60,70,80,90};
listScore(scores , printScore1);
listScore(scores , printScore2);
return 0 ;
}
//接收函数指针的函数
void listScore(vector<int> scores , void (*ps)(vector<int>)){
ps(scores);
}
//打印函数1
void printScore1(vector<int> scores){
cout << "****采用基于范围for循环遍历******" << endl;
for(int i : scores){
cout << i << endl;
}
}
//打印函数2
void printScore2(vector<int> scores){
cout << "****采用for i循环遍历******" << endl;
for (int i = 0; i < scores.size(); ++i) {
cout <<scores[i] << endl;
}
}
|
4. typedef使用
typedef 的作用是自己习惯的名字,来替已有的类型名称。 语法: typedef 已知类型名称 自定义名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | #include<vector>
using namespace std;
//使用myint 来替代 int。
typedef int myint ;
//使用vi 来替代 vector<int>
typedef vector<int> vi;
int main(){
int a = 3 ;
//此时的myint 等价于 int
myint b = 3 ;
vector<int> scores1{60,70,80,90}
//此时的vi 等价于 vector<int>
vi scores2{60,70,80,90};
return 0 ;
}
|
1. 未使用 typedef 简化
下面示例代码,没有使用typedef
简化函数指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | #include<vector>
using namespace std;
void listScores(vector<int> s , void(*pfs)(vector<int>)){
pfs(s);
}
void pirntScores(vector<int> scores){
//遍历打印
for(int s: scores){
cout << s<< endl;
}
}
int main(){
vector<int> scores {60,70,80,90};
//把printScores函数传递给listScores , 函数名称单独使用,它实际上是一个函数指针
listScores( scores ,pirntScores);
return 0 ;
}
|
2. 使用 typedef 简化
下面示例代码,使用typedef
简化函数指针 , 实现的功能都是一样的,只是代码简化了些
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | #include<vector>
using namespace std;
// 声明一种类型,这种类型的名称叫做 pfs ,它是一种函数指针,该函数没有返回值,有两个分别是int的参数
typedef void(*pfs)(vector<int>);
//此处使用简化好的函数指针类型
void listScores(vector<int> s , pfs p){
p(s);
}
void pirntScores(vector<int> scores){
//遍历打印
for(int s: scores){
cout << s<< endl;
}
}
int main(){
vector<int> scores {60,70,80,90};
//也可以选择使用变量来接收printScores
pfs pfs1 = pirntScores;
//把pfs1 传递给listScores ,实际上传递的是printScores
listScores( scores ,pfs1);
return 0 ;
}
|