C语言中的函数指针与指针函数 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语言中,形参值的改变并不能改变实参的值,但形参所指向内容值的改变却能改变实参,这一点非常的重要,是指针传递的精华所在。
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;
int b=20;
p=&a;//整形指针变量的初始化
q=&b;
printf("%dn",*p);
printf("%dn",*q);
pfun1=fun1;//把函数fun的地址赋值给函数指针pfun
pfun2=fun2;
(*pfun1)(p,q);//用函数指针去调用函数,pfun是fun的地址,那么*pfun当然就是函数本身了
printf("%dn",*p);
printf("%dn",*q);
//当交换两个指针时,发现值并没有发生改变
//在C语言中,形参的改变并不能改变实参,实参中p指向a的地址,q指向b的地址,在形参中,把两个地址互换,即形参的p指向b的地址,q指向a的地址,但并不能改变实参的值,除非改变地址中的内容值
(*pfun2)(p,q);
printf("%dn",*p);
printf("%dn",*q);
//此时p与q指向的值发生了变化,由于把地址中的内容交换了,所以交换了p,q
pfun=fun;
char* x="ab";
char* y="bc";
char* s=(*pfun)(x,y);
printf("%sn",s);
//free(s);//s指向这个堆内存,所以malloc之后要释放
s=NULL;
if(s!=NULL){//释放掉这个内存后,指针仍然不为空,此时的指针称为野指针,所以要把s=NULL
printf("%sn",s);
}
//对于野指针,有两种情况
//第一种情况: char* p;只声明了字符型指针,但没明确指向的地址,此时,用这个指针是很危险的,因为这个指针是野指针
//第二种情况: malloc()之后,没有free()之后,没有把指针设置为空,因为此时指针仍然存有地址,但是这个地址已经是无效的,所以对这个指针的使用是很危险的
return 0;
}
void fun1(int*p,int*q){
int* temp=p;
p=q;
q=temp;
}
void fun2(int*p,int*q){
int temp;
temp=*p;
*p=*q;
*q=temp;
}
char* fun(char*p,char* q){
//char a[]="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;
}
1. fun1函数
fun1函数中交换地址,并不能交换两个指针指向的值,因为形参的改变不能引起实参的改变。
2. fun2函数
fun2函数交换的是地址里面的内容,所以能交换两个指针指向的值。
3. fun函数
(1)fun函数里面定义的a是个局部变量,在函数返回之后这块内存会被释放掉。因此,为了得到返回值,可以声明为 static char a[]=""abc";
(2)malloc申请的是堆内存,因此,可以得到返回值,但必须free掉这块内存,同时将p=NULL,避免野指针。
(3)可以定义char* s=字符串,在C语言中,字符串是存放是静态常量区,因此,函数结束后,那块内存不会被释放掉。可以得到返回值。
因此,不能返回局部指针变量。
C语言中,形参只有在传递时才分配内存单元,实参到形参的传递是单向传递,因此,形参的改变并不能引起实参的改变,另外,实参与形参占据着不同的内存单元。
更多阅读
转载 《鸿门宴》中的“樊哙”与《樊哙传》中的“樊哙”比 樊哙传
原文地址:《鸿门宴》中的“樊哙”与《樊哙传》中的“樊哙”比较阅读作者: 一笑天下《鸿门宴》中的“樊哙”与《樊哙传》中的“樊哙”比较阅读(一)比较阅读下面两篇短文,回答文后问题。(22分)其一《鸿门宴》(节选)于是张良至军门见樊哙。樊
超漂亮的鼠标指针,让你的电脑炫起来!一 漂亮的鼠标指针下载
漂亮的鼠标指针,让你的电脑炫起来!使用方法:文件下载后解压,复制文件夹,粘贴到C:WINDOWSCursors文件夹中然后电脑开始→控制面板→鼠标,在指针选项卡中选择你安装的方案即可……性感红色口红鼠标指针下载地址http://115.com/file/dnglzio
ExternalInterface.addCallback注册的函数在浏览器中的兼容性问题 浏览器兼容性测试
ExternalInterface.addCallback注册的函数在浏览器中的兼容性问题现在做一个小应用,要求使用js调用flash中的函数,就使用了ExternalInterface.addCallback函数。之前用过一次,按照官方API上的方法做了以后,发现只有IE是能正常调用的,其
图像处理中的卷积与模板 图像处理 卷积
图像处理中的卷积与模板2011-04-25 11:16转载自 deepthink_2010最终编辑 shuting_guo1.使用模板处理图像相关概念:模板:矩阵方块,其数学含义是一种卷积运算。卷积运算:可看作是加权求和的过程,使用到的图像区域中的每个像素分别与卷积核(
《鸿门宴》中的“樊哙”与《樊哙传》中的“樊哙”比较阅读 鸿门宴樊哙
《鸿门宴》中的“樊哙”与《樊哙传》中的“樊哙”比较阅读(一) 比较阅读下面两篇短文,回答文后问题。(22分)