函数指针与指针函数

来源:互联网 发布:江苏学信学院传销 知乎 编辑:程序博客网 时间:2024/06/02 16:59

 函数是任何一门语言中必不可少的部分,正是由这些函数组成了程序。首先谈一下C语言中的函数指针与指针函数,再了解一下函数参数传递的相关原理。

 1.函数指针与指针函数

 (1) 函数指针 即指向这个函数的指针,定义为数据类型 (*fun)(参数列表) ,()的优先级比*高,所以*fun加括号。如 void(*fun)(int*,int*);

 (2)指针函数 即返回值是指针的函数,定义为 数据类型 * fun(参数列表). 如 char*fun(int*,int*);即返回值为char*型。

 在C语言中,变量有它的地址,同理函数也是有地址的。那么把函数的地址赋给函数指针,再通过函数指针调用这个函数就可以了。

 第一步: 定义函数指针,如 int (*pfun)(int*,int*);

 第二步: 定义函数  如 int fun(int*,int*);

 第三步: 把函数的地址赋给函数指针,即 pfun=fun;

 第四步: 通过函数指针去调用这个函数 (*pfun)(p,q); //pfun是函数的地址,那么 *pfun当然就是函数本身了。

 2.函数参数传递问题

 在C语言中,有两种参数传递的方式,一种是值传递,另一种是指针传递。

 值传递很好理解,即把实参的值传递给形参。

 而指针传递传的是地址在C语言中,形参值的改变并不能改变实参的值,但形参所指向内容值的改变却能改变实参</span>,这一点非常的重要,是指针传递的精华所在。

 3. 指针函数

 当函数的返回值为指针类型时,应该尽量不要返回局部变量的指针,因为,局部变量是定义在函数内部,当这个函数调用结束了,局部变量的栈内存也被释放了,因此,不能够正确的得到返回值。实际上,内存已经被释放了,但这个指针的地址已经返回过去了,但是这个地址已经是无效的了,此时,对这个指针的使用是很危险的。

 4. 野指针

 野指针并不是NULL,而是指向垃圾内存的指针。&nbsp;

 有两种情况可以导致野指针:

 (1)char* p;

 (2)malloc,free

 第一种情况是定义指针,但没有给指针赋地址,此时,对指针的使用是很危险的,因为你不知道它指向哪里,是个野指针。

 第二种情况,malloc是在堆上分配内存,必须由用户手动释放,当释放之后,指针指向的内存已经释放掉了,但指针本身的地址还存在,即指向了一个无效的内存,所以这时的指针为野指针,必须把这个指针p=NULL.

 5. 下面举个例子说明上述几种情况 

 #include &lt;stdio.h&gt;            

#include &lt;string.h&gt;            

#include &lt;stdlib.h&gt;            

#include &lt;unistd.h&gt;            

void fun1(int*,int*);            

void fun2(int*,int*);            

char* fun(char*,char*);//指针函数,即返回值为指针的函数            

int main(){             //定义3个函数指针            

void (*pfun1)(int*,int*);            

void(*pfun2)(int*,int*);            

char*(*pfun)(char*,char*);//定义返回值为指针的函数指针            

 int*p;           

 int*q;            

int a=10;           

 intb=20;           

 p=&amp;a;//整形指针变量的初始化            

q=&amp;b;           

printf("%d\n",*p);            

printf("%d\n",*q);            

pfun1=fun1;//把函数fun的地址赋值给函数指针pfun             

pfun2=fun2;           

 (*pfun1)(p,q);//用函数指针去调用函数,pfun是fun的地址,那么*pfun当然就是函数本身了            

printf("%d\n",*p);            

printf("%d\n",*q);             //当交换两个指针时,发现值并没有发生改变             //在C语言中,形参的改变并不能改变实参,实参中p指向a的地址,q指向b的地址,在形参中,把两个地址互换,即形参的p指向b的地址,q指向a的地址,但并不能改变实参的值,除非改变地址中的内容值           

 (*pfun2)(p,q);           

 printf("%d\n",*p);            

printf("%d\n",*q);             //此时p与q指向的值发生了变化,由于把地址中的内容交换了,所以交换了p,q            

pfun=fun;            

char* x="ab";            

char* y="bc";             

char* s=(*pfun)(x,y);           

 printf("%s\n",s);             //free(s);//s指向这个堆内存,所以malloc之后要释放          

  s=NULL;           

 if(s!=NULL){//释放掉这个内存后,指针仍然不为空,此时的指针称为野指针,所以要把s=NULL            

printf("%s\n",s);             }             //对于野指针,有两种情况             //第一种情况: char* p;只声明了字符型指针,但没明确指向的地址,此时,用这个指针是很危险的,因为这个指针是野指针             //第二种情况: malloc()之后,没有free()之后,没有把指针设置为空,因为此时指针仍然存有地址,但是这个地址已经是无效的,所以对这个指针的使用是很危险的                        

 return0;             }                        

 voidfun1(int*p,int*q){           

 int*temp=p;             p=q;             q=temp;             }           


 voidfun2(int*p,int*q)

{             int temp;             temp=*p;             *p=*q;             *q=temp;                          }         


 char*fun(char*p,char* q)

{             //chara[]="abc";//定义一个内存空间,局部变量栈上内存             //char* s=a;             //return s;//在这函数结束之后,char型指针被释放掉,因此不能正确返回             //因此,最好别返回一个局部变量指针             //(1)解决方法:把数组变成静态,即 static char a[]="abc";静态内存在函数结束后不会被释放             //(2)申请堆内存             //(3)定义为常量区                          //char*s=(char*)malloc(sizeof(char*)*10);            // strcpy(s,"abc");            char* s1="ssss"; //定义一个指针变量指向字符串,在C中,字符串被存放在常量区,静态存储区域,因此,在这个函数结束之后,这个地址仍然是有效的,即常量区的内存没有被释放掉,因此能够返回值             return s1;             }

<address>1. fun1函数</address>

 &nbsp;fun1函数中交换地址,并不能交换两个指针指向的值,因为形参的改变不能引起实参的改变。

 2.fun2函数

 fun2函数交换的是地址里面的内容,所以能交换两个指针指向的值。

 3.fun函数

 (1)fun函数里面定义的a是个局部变量,在函数返回之后这块内存会被释放掉。因此,为了得到返回值,可以声明为 static char a[]=""abc";

 (2)malloc申请的是堆内存,因此,可以得到返回值,但必须free掉这块内存,同时将p=NULL,避免野指针。

 (3)可以定义char* s=字符串,在C语言中,字符串是存放是静态常量区,因此,函数结束后,那块内存不会被释放掉。可以得到返回值。

 &nbsp;因此,不能返回局部指针变量。

 C语言中,形参只有在传递时才分配内存单元,实参到形参的传递是单向传递,因此,形参的改变并不能引起实参的改变,另外,实参与形参占据着不同的内存单元。


原创粉丝点击