C++ 指针函数和函数指针有什么区别

来源:互联网 发布:产品展示动画制作软件 编辑:程序博客网 时间:2024/05/18 00:15

C++ 指针函数和函数指针有什么区别

这两个概念都是简称,指针函数是指带指针的函数,即本质是一个函数。我们知道函数都有返回类型(如果没有返回值,则为无值型),只不过指针函数返回类型是某一类型的指针(返回的是地址)。

 

返回类型标识符 *返回名称(形式参数表)

{ 函数体 }

 

返回类型可以是任何基本类型和复合类型。 事实上每一个函数,即使它不带有返回某种类型的指针,它本身都有一个入口地址,该地址相当于一个指针。比如函数返回一个整型值,实际上也相当于返回一个指针变量的值,不过这时的变量是函数本身而已,而整个函数相当于一个“变量”。例如下面一个返回指针函数的例子(VC++ 编译通过):

 

#include <iostream>

using namespace std;

 

int main()

{

float *find(float(*pionter)[4],int n);

static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};

float *p;

int i,m;

printf("Enter the number to be found:");

scanf("%d",&m);

printf("the score of NO.%d are:\n",m);

p=find(score,m);

for(i=0;i<4;i++)

printf("%5.2f\t",*(p+i));

return 0;

}

 

float *find(float(*pionter)[4],int n)/*定义指针函数*/

{

float *pt;

pt=*(pionter+n);

return(pt);

}

学生学号从0号算起,函数find()被定义为指针函数,形参pointer是指针指向包含4个元素的一维数组的指针变量。pointer+1指向score的第一行。*(pointer+1)指向第一行的第0个元素。pt是一个指针变量,它指向浮点型变量。main()函数中调用find()函数,将score数组的首地址传给pointer.

 

2,“函数指针”是指向函数的指针变量,因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上一致的。函数指针有两个用途:调用函数和做函数的参数

 

数据类型标志符 (*指针变量名)(参数)  。

下面的程序说明了函数指针调用函数的方法(VC++ 编译通过):

int max(int x,int y){ return(x>y?x:y); }

void main()

{

int (*ptr)(int,int);

int a,b,c;

ptr=max;

cin>>a>>b;

c=(*ptr)(a,b);

cout<<"a="<<a<<" b="<<b<<" c="<<c<<endl;

} }ptr是指向函数的指针变量,所以可把函数max()赋给ptr作为ptr的值,即把max()的入口地址赋给ptr,以后就可以用ptr来调用该函数,实际上ptr和max都指向同一个入口地址,不同就是ptr是一个指针变量,不像函数名称那样是死的,它可以指向任何函数 。在程序中把哪个函数的地址赋给它,它就指向哪个函数。而后用指针变量调用它,因此可以先后指向不同的函数,不过注意,指向函数的指针变量没有++和--运算,用时要小心。

 

指针函数应用举例:建立链表,插入,删除接点

 

#include <iostream>

using namespace std;

#define NULL 0    

struct student

{long num;

 float score;

 student *next;

};   

int n;

 

int main()

{ student *creat(void);

  student *del(student *,long); 

  student *insert(student *,student *);

  void print(student *);

  student *head,*stu;

  long del_num;

  cout<<"input records:"<<endl;

  head=creat();                        //返回头指针

  print(head);                          //输出全部结点

  cout<<endl<<"input the deleted number:";

  cin>>del_num;                        //输入要删除的学号

  while(del_num!=0)

  {head=del(head,del_num);              //删除后链表的头地址

   print(head);                         //输出全部结点

   cout<<"input the deleted number:";

   cin>>del_num;

  }

  cout<<endl<<"input the inserted record:";  //输入要插入的结点

  stu=new student;                      //开辟一个新结点

  cin>>stu->num>>stu->score;

  while(stu->num!=0)

  {head=insert(head,stu);              //返回地址

   print(head);                         //输出全部结点

   cout<<endl<<"input the inserted record:";  //输入要插入的结点

   stu=new student;

   cin>>stu->num>>stu->score;

  }

  return 0;

}

 

student *creat(void)       //建立链表的函数

{student *head;

 student *p1,*p2;

 n=0;

 p1=p2=new student;       //开辟一个新单元,并使p1,p2指向它

 cin>>p1->num>>p1->score;

 head=NULL;

 while(p1->num!=0)

{n=n+1;

 if(n==1) head=p1;

 else p2->next=p1;

 p2=p1;

 p1=new student;

 cin>>p1->num>>p1->score;

}

p2->next=NULL;

return(head);

}   

 

student *del(student *head,long num)   //删除结点的函数

{student *p1,*p2;

 if (head==NULL)                    //是空表

 {cout<<"list null!"<<endl; return(head);}

 p1=head;                          //使p1指向第一个结点

 while(num!=p1->num && p1->next!=NULL) //p1指向的不是所要找的结点且后面还有结点

 {p2=p1; p1=p1->next;}                 //p1后移一个结点

 if(num==p1->num)                        //找到了

 {if(p1==head) head=p1->next;   //若p1指向的是首结点,把第二个结点地址赋予head

  else p2->next=p1->next;    //否则将下一结点地址赋给前一结点地址

  cout<<"delete:"<<num<<endl;

  n=n-1;

 }

 else cout<<"cannot find "<<num;     //找不到该结点

 return(head);

}

   

student *insert(student *head,student *stud)  //插入结点的函数

{student *p0,*p1,*p2;

 p1=head;                          //使p1指向第一个结点

 p0=stud;                          //指向要插入的结点

 if(head==NULL)                    //原来的链表是空表

 {head=p0;p0->next=NULL;}          //使p0指向的结点作为头结点

 else

 {while((p0->num>p1->num) && (p1->next!=NULL))

 {p2=p1;                       //使p2指向刚才p1指向的结点

  p1=p1->next;}                //p1后移一个结点

  if(p0->num<=p1->num)

  {if(head==p1) head=p0;        //插到原来第一个结点之前

   else p2->next=p0;            //插到p2指向的结点之后

   p0->next=p1;}

  else

  {p1->next=p0; p0->next=NULL;}}  //插到最后的结点之后

   n=n+1;                         //结点数加1

   return (head);

}

              

void print(student *head)         //输出链表的函数

 {student *p;

  cout<<"Now,These "<<n<<" records are:"<<endl;

  p=head;

  if(head!=NULL)

  do

    {cout<<p->num<<"  "<<p->score<<endl;

     p=p->next;

    }while(p!=NULL);

}

 

int *p[n] 与int(*p)[n]区别

int*p[n]------p是一个指针数组,它由n个指向整型数据的指针元素组成 (含有n个指针元素)

int (*p)[n]----- p是一个指针(数组指针),指向int[n]的数组(它指向一个由nint元素构成的数组)

 

#include <iostream>

using namespace std;

 

int main()

{

    int *p[4];

    int a=1,b=2,c=3,d=4;

    p[0]=&a;

    p[1]=&b;

    p[2]=&c;

    p[3]=&d;

    int (*pp)[4];

    //pp[0]=&a;//error

    int aa[4]={5,6,7,8};

    pp=&aa; // 换成aa 是错误的,定义的pp元素个数要与aa相同才可以赋值

 

    cout<<*(p[0])<<" "<<*(pp[0])<<endl;

    return 0;

}

 

 

#include <iostream>

#include <typeinfo>

using namespace std;

int main()

{

 int vInt=10;

 int arr[2]={10,20};

 

 int *p=&vInt;

 int **p2p=&p;

 

 int *parr[2]={&vInt,&vInt};

 int (*p2arr)[2]=&arr;

 

 cout<<"Declaration [int vInt=10] type=="<<typeid(vInt).name()<<endl;

 cout<<"Declaration [arr[2]={10,20}] type=="<<typeid(arr).name()<<endl;

 cout<<"Declaration [int *p=&vInt] type=="<<typeid(p).name()<<endl;

 cout<<"Declaration [int **p2p=&p] type=="<<typeid(p2p).name()<<endl;

 cout<<"Declaration [int *parr[2]={&vInt,&vInt}] type=="<<typeid(parr).name()<<endl;

 cout<<"Declaration [int (*p2arr)[2]=&arr] type=="<<typeid(p2arr).name()<<endl;

 

 return 0;

}

 

运行的结果如下:(前面加了行号#XX)

#01 Declaration [int vInt=10] type==int

#02 Declaration [arr[2]={10,20}] type==int *

#03 Declaration [int *p=&vInt] type==int *

#04 Declaration [int **p2p=&p] type==int * *

#05 Declaration [int *parr[2]={&vInt,&vInt}] type==int **

#06 Declaration [int (*p2arr)[2]=&arr] type==int (*)[2]

 

#02, 在编译器看来数组只是相对应类型的指针类型。

当把数组传递给函数作为参数的时候,传递的是指针,所以可以利用参数来修改数组元素。这个转化是编译器自动完成的。也就是说这里编译器自动完成了int[]类型到int *的转化,

 

void f(int[]);

int a[2]={10,20};

f(a);//这行等价于编译器完成的函数转化f(int *p)

 

#05:指针数组的编译器内部表示也是对应类型的指针。

 

#06数组指针的编译器内部表示就是有一点特别了。

编译器(或者说是语言本身)有数组指针这个内部表示。

由于c++语言的类型严格检查的语言(当然还有一些是存在隐式类型转化的)

 

所以我们下面的写法是不能编译通过的。

{

int arr[3]={10,20};//注意是3个元素数组

int (*p2arr)[2]=&arr;//注意是指向2个元素数组的指针

}

 

小结

关于数组和指针的转化,以及我们使用指针(++,--)等来操作数组,是基于数组在内存中是连续分布的。

 

看到这里就会明白下面的程序为什么会运行的了。

我这里也把下面的程序作为今天内容的总结:

 

#include <iostream>

using namespace std;

int main()

{

 int a[2]={10,20};

 int *p=a;//根据上面说明,由于编译器的参与,两者类型转化后一致

 

 int vInt=10,vInt1=11;

 int *parr[2]={&vInt,&vInt1};

 int **p2p=parr;//上面分析,类型一致

 cout<<*parr[0]<<" "<<*parr[1]<<endl;

 cout<<*(*p2p)<<" "<<*(*(p2p+1)) <<endl;

 return 0;

}

 

输出结果 cout<<*parr[0]<<" "<<*parr[1]<<endl; ----------10 11

         cout<<*(*p2p)<<" "<<*(*(p2p+1)) <<endl;------10 11

原创粉丝点击