指针及其应用3——指针与函数

简介: 指针及其应用3——指针与函数

指针作为函数参数     指针可以作为函数的参数。

在函数章节中,我们把数字作为参数传入函数中,实际上就 是利用了传递指针(即传递数组的首地址)的方法。通过首地址,我们可以访问数组中的任 何一个元素。 对于指向其他类型变量的指针,我们可以用同样的方式处理。

例如,我们编写如下一个函数,用于将两个整型变量的值交换。

1. void swap(int *x,int *y) 
2. {
3. int t=*x;*x=*y;*y=t; 
4. }

这时,我们在其他函数中可以使用这个函数:

1. int a=5,b=3;
2. swap(&a,&b);
3. printf(“a=%d,b=%d”,a,b); //输出:a=3,b=5

在这个过程中,我们先将 a 和 b 的地址传给函数,然后在函数中通过地址得到变量 a 和 b 的值,并且对它们进行修改。当退出函数时,a 和 b 的值就已经交换了。

这里有一点值得我们注意。看如下这个过程:

1. void swap(int x,int y) 
2. {
3. int t=x;x=y; y=t;
4.  }

我们调用了 swap(a,b);然而这个函数没有起作用,没有将 a 和 b 的值互换。 为什么呢?因为这里在传入变量 a 和 b 的时候,是将 a 的值赋值给函数中的形参 x,将 b 赋值给形参 y。这里接下来的操作就完全与 a 和 b 无关了,函数将变量 x 和 y 的值互换, 然后退出函数。这里没有像上面例子那样传入指针,所以无法对传进来的变量进行修改。

将指针传入函数与将变量传入函数的区别在于:前者是通过指针来使用或修改传入的变量;而后者是将传入的变量的值赋给新的变量,函数对新的变量进行操作。

同理,对 scanf()函数而言,读取变量的时候我们要在变量之前加&运算符,即将指针传入函数。这是由于 scanf()函数通过指针将读取的值返回给引用的变量,没有&,就无法 进行正常的读取操作。

 

【例 9】编写一个函数,将三个整型变量排序,并将三者中的最小值赋给第一个变量,次小值赋给第二个变量,最大值赋给第三个变量。

1. #include<cstdio>
2. using namespace std;
3. void swap(int *x,int *y)
4. {
5.  int t=*x;*x=*y;*y=t;
6. }
7. void sort(int *x,int *y,int *z)
8. {
9.  if(*x>*y) swap(x,y);
10.   if(*x>*z) swap(x,z);
11.   if(*y>*z) swap(y,z);
12. }
13. int main()
14. {
15.   int a,b,c;
16.   scanf("%d%d%d",&a,&b,&c);
17.   sort(&a,&b,&c);
18.   printf("%d %d %d",a,b,c);
19.   return 0;
20.  }

输入:2 3 1

输出:1 2 3

函数返回指针

一个函数可以返回整数值、字符值、实型值等,也可以返回指针联系的数据(即地址)。

返回指针值的函数的一般定义形式为:

类型名 * 函数名(参数列表);

例如:

int *a(int a,int b)

a 是函数名,调用它后得到一个指向整型数据的指针(地址)。x 和 y 是函数 a 的形参, 为整型。

注意:在*a 的两侧没有括号;在 a 的两侧分别为*运算符和()运算符,由于()的优 先级高于*,因此 a 先于()结合。在函数前面有一个*,表示此函数是返回指针类型的函数。 最前面的 int 表示返回的指针指向整型变量。对初学 C++语言的人来说,这种定义形式可能 不太习惯,容易弄错,用时要十分小心。

 

【例 10】编写一个函数,用于在一个包含 N 个整数的数组中找到第一个质数,若有则返回 函数的地址;否则返回 NULL(空指针)。

1. #include<cstdio>
2. #include<cmath>
3. using namespace std;
4. int n,a[10001];
5. bool isprime(int n)//判断素数 
6. {
7.  if(n<2) return false;
8.  if(n==2) return true;
9.  for(int i=2;i<=sqrt(n);++i){
10.     if(n%i==0) return false;
11.   }
12.   return true;
13. }
14. int* find()
15. {
16.   for(int i=1;i<=n;++i)
17.     if(isprime(a[i])) return &a[i];//或:return a+i; 
18.   return NULL;//找不到返回空指针 
19. }
20. int main()
21. {
22.   scanf("%d",&n);
23.   for(int i=1;i<=n;++i)
24.     scanf("%d",&a[i]);
25.   int *p=find();
26.   if(p!=NULL) printf("%d\n%d\n",p,*p);//输出素数的地址及其本身 
27.   else
28.     printf("Can't find!");
29.   return 0;
30.  }

输入:

7

1 6 9 2 3 4 5

输出:

(可能是)4214864

2

函数指针和函数指针数组

一个指针变量通过指向不同的整数变量的地址,就可以对其他的变量操作。

程序中不仅数据是存放在内存空间中,代码也同样存放在内存空间里。具体讲,C++的 函数也保存在内存中,函数的入口地址也同样可以用指针访问。

另一方面,有些函数在编写时对要调用的辅助函数尚未确定,在执行时才能根据情况为其传递辅助函数的地址。比如 sort 函数的调用:“sort(a,a+n,cmp);”其中的比较函数 cmp 是我们根据需要转给 sort 的(也可能是 cmp1,cmp2 等),其实就是传递了函数指针。 下面我们来看一个具体例子。

 

【例 11】使用函数指针调用函数示例。  

1. #include<iostream>
2. using namespace std;
3. int t(int a)
4. {
5.  return a;
6. }
7. int main()
8. {
9.  cout<<t<<endl; 
10.         cout<<(void*)t<<endl;//输出地址
11.   printf("%x\n",t);//输出地址
12.   int (*p)(int a);//定义函数指针变量p 
13.   p=t;//将函数t的地址赋给函数指针p 
14.   cout<<p(5)<<','<<(*p)(10)<<endl;
15.   //输出 p(5)是 C++的写法,(*p)(10)是兼容 C,这是使用 p 来调用函数的两种方法 
16.   return 0;
17.  }

输出:1

5,10

 

函数指针的基本操作有 3 个:

⑴声明函数指针

声明要指定函数的返回类型以及函数的参数列表,和函数原型差不多。

例如,函数的原型是:int test(int);

相应的指针声明就是:int (*fp)(int);

要注意的是,不能写成:int *fp(int);

这样计算机编译程序会处理成声明一个 fp(int)的函数,返回类型是 int* 。

⑵获取函数的地址

获取函数的地址很简单,只要使用函数名即可,例如,fp=test;

这表明函数名和数组名一样,可以看作是指针。

⑶使用函数指针来调用函数

类似普通变量指针,可以用(*fp)来间接调用指向的函数。但 C++也允许像使用函数名一样使用 fp,虽然有争议,但C++确实是支持了。

函数指针还有另一种结合 typedef 的声明方式,如例 X 所示。  

【例 12】使用 typedef 定义函数指针示例。

1. #include<iostream>
2. using namespace std;
3. int sum(int a,int b)
4. {
5.  return a+b;
6. }
7. typedef int (*LP)(int,int);//定义了一个函数指针变量类型LP 
8. int main()
9. {
10.   LP p=sum;//定义了一个LP类型的函数指针p,并赋值为sum 
11.   cout<<p(2,5);//使用p来调用函数,实参为2和5,调用sum函数,返回7 
12.   return 0;
13.  }

输出:7

在软件开发编程中,函数指针的一个广泛应用是菜单功能函数的调用。通常选择菜单的某个选项都会调用相应的功能函数,并且有些软件的菜单会根据情况发生变化。如果使用 swith/case 或 if 语句处理起来会比较复杂、冗长,不利于代码的维护,可以考虑使用函数指针数组方便灵活地实现。

【例 13】使用函数指针数组,模拟菜单功能实现方法示例

1. #include<iostream>
2. using namespace std;
3. void t1(){cout<<"test1";} 
4. void t2(){cout<<"test2";} 
5. void t3(){cout<<"test3";} 
6. void t4(){cout<<"test4";} 
7. void t5(){cout<<"test5";} 
8. typedef void(*LP)();//定义了一个函数指针变量 
9. int main()
10. {
11.   LP a[]={t1,t2,t3,t4,t5};//定义了一个LP类型的函数指针数组a,并初始化 
12.   int x;
13.   cin>>x;
14.   a[x]();//使用a[x]()来调用选择的函数 
15.   return 0;
16.  }

输入:2

输出:test3

相关文章
|
17天前
|
存储 C语言 C++
如何通过指针作为函数参数来实现函数的返回多个值
在C语言中,可以通过将指针作为函数参数来实现函数返回多个值。调用函数时,传递变量的地址,函数内部通过修改指针所指向的内存来改变原变量的值,从而实现多值返回。
|
17天前
|
存储 搜索推荐 C语言
如何理解指针作为函数参数的输入和输出特性
指针作为函数参数时,可以实现输入和输出的双重功能。通过指针传递变量的地址,函数可以修改外部变量的值,实现输出;同时,指针本身也可以作为输入,传递初始值或状态。这种方式提高了函数的灵活性和效率。
|
1月前
利用指针函数
【10月更文挑战第2天】利用指针函数。
17 1
|
1月前
|
算法 搜索推荐 C语言
【C语言篇】深入理解指针4(模拟实现qsort函数)
【C语言篇】深入理解指针4(模拟实现qsort函数)
21 2
|
2月前
|
传感器 物联网 大数据
C 指针在物联网的应用
在物联网(IoT)中,C 语言及其指针功能广泛应用于嵌入式系统。C 指针在内存管理、设备驱动、数据结构处理、传感器通信等方面发挥关键作用,如动态分配内存、直接访问硬件寄存器、传递复杂数据结构等,有效提升了资源受限环境下的性能和灵活性。通过函数指针和省电模式管理,还能实现事件驱动编程和节能目标,使 C 语言成为 IoT 开发的重要工具。
66 12
|
2月前
|
存储 安全 C语言
C语言 二级指针应用场景
本文介绍了二级指针在 C 语言中的应用,
|
2月前
|
Linux
在Linux内核中根据函数指针输出函数名称
在Linux内核中根据函数指针输出函数名称
|
3月前
|
程序员 C语言
指针在函数参数和返回值中的使用
指针在函数参数和返回值中的使用
47 9
|
3月前
|
算法 Java
双指针在数组遍历中的应用
文章深入探讨了双指针技术在数组遍历中的应用,通过实战例子详细解释了快慢指针和首尾指针的不同用法,并提供了解决LeetCode相关问题的Java代码实现。
|
3月前
|
存储 搜索推荐 C语言
C语言中的指针函数:深入探索与应用
C语言中的指针函数:深入探索与应用