指针与函数

来源:互联网 发布:电气控制柜设计软件 编辑:程序博客网 时间:2024/06/01 09:45

一、指针作为函数参数

指针可以作为函数的参数。在函数章节中,我们把数字作为参数传入函数中,实际上就是利用了传递指针(即传递数组的首地址)的方法。通过首地址,我们可以访问数组中的任何一个元素。

对于指向其他类型变量的指针,我们可以用同样的方式处理。

#include<iostream>using namespace std;void swap(int *x,int *y){int t=*x;*x=*y;*y=t;}int main(){int a,b;a=5;b=3;swap(&a,&b);printf("a=%d,b=%d\n",a,b);return 0;} 

输出:a=3,b=5

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

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

void swap(int x,int y){int t;t=x;x=y;y=t;}
我们调用了 swap(a,b);然而这个函数没有起作用,没有将 a 和 b 的值互换。

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

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

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

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

#include<cstdio>using namespace std;void swap(int *x,int *y){int t=*x;*x=*y;*y=t;}void sort(int *x,int *y,int *z){if(*x>*y) swap(x,y);if(*x>*z) swap(x,z);if(*y>*z) swap(y,z);}int main(){int a,b,c;scanf("%d%d%d",&a,&b,&c);sort(&a,&b,&c);printf("%d %d %d\n",a,b,c);return 0;}

输入:2 3 1

输出:1 2 3

二、函数返回指针

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

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

例如:int *a(int a,int b)

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

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

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

#include<cstdio>  #include<cmath>  using namespace std;  int n,a[10001];  bool isprime(int n)//只能被1和他本身整除   {      if(n<2) return false;      if(n==2) return true;      for(int i=2;i<=sqrt(n);i++)      {          if(n%i==0) return false;      }      return true; }  int *find()//返回地址   {      for(int i=1;i<=n;i++)      {          if(isprime(a[i]))              return &a[i];//或return a+i;       }      return NULL;//如果找不到返回空指针   }   int main()  {      scanf("%d",&n);      for(int i=1;i<=n;i++)      {          scanf("%d",&a[i]);      }      int *p=find();      if(p!=NULL)          printf("%d\n%d\n",p,*p);//输出素数的地址和它本身      else          printf("can't find!\n");      return 0;   }  


三、函数指针和函数指针数组

一个指针变量通过指向不同的整数变量的地址,就可以对其他的变量操作。程序中不仅数据是存放在内存空间中,代码也同样存放在内存空间里。

具体讲,C++的函数也保存在内存中,函数的入口地址也同样可以用指针访问。

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

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

#include<iostream>using namespace std;int t(int a){return a;}int main(){cout<<t<<endl;//显示函数地址 int (*p)(int a);//定义函数指针变量p p=t;//将函数t的地址赋值给 函数指针p cout<<p(5)<<','<<(*p)(10)<<endl;//输出p(5)是C++的写法,(*p)(10)是兼容 C,这是使用 p 来调用函数的两种方法  return 0;} 


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

⑴声明函数指针。

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

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

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

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

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

⑵获取函数的地址。

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

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

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

类似普通变量指针,可以用(*fp)来间接调用指向的函数。

但 C++也允许像使用函数名一样使用 fp,虽然有争议,但 C++确实是支持了。函数指针还有另一种结合 typedef 的声明方式,如例 X 所示。

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

#include<iostream>using namespace std;int sum(int a,int b){return a+b;} typedef int (*LP)(int,int);//定义了一个函数指针变量类型LPint main(){LP p=sum;//定义了一个LP类型的函数指针LP,并赋值为sumcout<<p(2,5);//使用p来调用函数,实参为2和5,调用sum函数,输出返回值7return 0;}
输出:7

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

#include<iostream>using namespace std;void t1(){cout<<"test1";}void t2(){cout<<"test2";}void t3(){cout<<"test3";}void t4(){cout<<"test4";}void t5(){cout<<"test5";}typedef void(*LP)();//定义了一个函数指针变量类型LPint main(){LP a[]={t1,t2,t3,t4,t5};//定义了一个LP类型的函数指针数组a,并初始化int x;cin>>x;a[x]() ;//使用a[x]()来调用选择的函数return 0;  


 
原创粉丝点击