函数是任何一门语言中必不可少的部分,正是由这些函数组成了程序。首先谈一下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,而是指向垃圾内存的指针。
有两种情况可以导致野指针:
(1)char* p;
(2)malloc,free
第一种情况是定义指针,但没有给指针赋地址,此时,对指针的使用是很危险的,因为你不知道它指向哪里,是个野指针。
第二种情况,malloc是在堆上分配内存,必须由用户手动释放,当释放之后,指针指向的内存已经释放掉了,但指针本身的地址还存在,即指向了一个无效的内存,所以这时的指针为野指针,必须把这个指针p=NULL.
5. 下面举个例子说明上述几种情况
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
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=&a;//整形指针变量的初始化
q=&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>
fun1函数中交换地址,并不能交换两个指针指向的值,因为形参的改变不能引起实参的改变。
2.fun2函数
fun2函数交换的是地址里面的内容,所以能交换两个指针指向的值。
3.fun函数
(1)fun函数里面定义的a是个局部变量,在函数返回之后这块内存会被释放掉。因此,为了得到返回值,可以声明为 static char a[]=""abc";
(2)malloc申请的是堆内存,因此,可以得到返回值,但必须free掉这块内存,同时将p=NULL,避免野指针。
(3)可以定义char* s=字符串,在C语言中,字符串是存放是静态常量区,因此,函数结束后,那块内存不会被释放掉。可以得到返回值。
因此,不能返回局部指针变量。
C语言中,形参只有在传递时才分配内存单元,实参到形参的传递是单向传递,因此,形参的改变并不能引起实参的改变,另外,实参与形参占据着不同的内存单元。