传值和传址,指针函数,函数指针,函数指针作为参数,函数指针作为返回值。

有时候,我们定义的函数需要接收用户传入的数据,那么就需要使用到函数的参数。

函数参数的数量可以有多个,

返回值一般表示函数计算后的数值,也可以表示执行结果。

主函数传入的参数称为实参,传递到函数体的参数叫做形参。

传递到形参后就可以直接在函数体当中使用已经定义过的形参的数据。

函数的设计应该遵从一个函数实现一个功能的原则,

传入的参数让函数实现更为丰富的功能。

类型名就是指定函数的返回值,一个函数实现一个功能通常是要反馈结果的,若函数确实不需要返回值,可以使用void来定义。

函数定义时写的参数就是形参,形式参数,定义时仅仅是一个占位符,没有实际数值,在主函数执行函数时传递的具体的数值就是实际参数。

实参和形参的功能就是用于数据传输。当函数发生调用的时候,实参的值会传递给形参。并且传递是具有单向性的。当函数执行党的时候形参才会生成具体的空间,才会分配内存,当函数结束之后就会立即释放内存。所以形参的变量只有在函数的内部有效,出了函数他什么也不是。

传值和传址

指针也是一个变量,所以可以通过参数(将指针的存值)传递给函数。引进指针的参数有什么意义呢?

因为作用域的存在,不同的函数是无法直接去访问对方的变量的,所以形参和实参重名也并不冲突。

当通过传递变量实现对一个变量的更改并打印的话,在函数中更改的仅仅是形参,对在main函数的数据没有影响。

而函数中指针的使用呢就是拿到实参变量的地址,直接对所在的地址的数据进行修改。

这是传值和传址的根本区别。

传递数组

在主函数中定义的数组,进行实参与形参的传值时,函数调用处的实参直接书写数组名就可以了。实际上不是传输的整个数组的每个值,并不存在将整个数组作为参数传递的形式,而是将数组的第一个元素的地址进行了传递,所以,在函数中对数组元素进行的修改会将主函数中定义的数组的元素一并修改。

指针函数与函数指针

指针函数:

函数的类型实际指的就是函数的返回值。可以返回为整形、浮点型、等、当然也可以返回指针类型的数据,定义时只需要在函数名前面加一个*就可以了。这就称为指针函数。

指针函数产生并返回的是一个带指针的,比如返回一个字符串,那就是用char类型进行定义的。

譬如我们使用%s进行输出时需要一个字符串,我们使用函数来进行提供字符串,但是对于字符串没有可以定义字符串的类型,我们是用char类型的指针来定义的字符串,字符串的约定俗成就是给指针读到空字符就可以结束,所以我们知道第一个字符地址就可以知道整个字符串,所以我们定义函数返回值类型时候,对于返回字符串类型都是定义的char类型。

用指针变量做返回值我们就称之为指针函数。

注意:不要返回局部变量(在函数中定义的变量)的指针!!

函数指针:

是一个指针,指向函数的指针。与数组一样,定义时我们使用小括号将函数的名字与前面的*号括起来。

函数表示法就是我们平时用的函数,像printf函数,这个函数的名字经过求值之后,就会变成函数的地址。所以呢,在定义了函数指针后,再给他传递一个已经被定义的函数名就可以通过该指针进行调用函数了。

比如我们定义一个函数指针,希望通过函数指针来对已经定义的函数进行调用,那么就是使指针指向函数,此指针的返回值为函数的返回值,参数为函数的参数。

譬如定义函数指针fp同过fp调用函数int squre(int ):int (*fp)(int ); 直接让fp = squre ;就可以。

为什么呢?因为我们定义的指针就规定了此指针只能指向一个参数为int 返回值为int的函数。所指函数各方面就是与squre符合,所以就可以直接相等。这个squre经过运算之后就是函数的地址,这个地址被指针存储了。

函数指针作为参数:

函数指针也可以被作为参数进行传递。这就实现了在一个函数里调用另一个函数。

当我们定义了一个函数,函数的参数的类型可以为指针类型,如果我们为此指针添加了参数类型与返回值类型,那么这个指针我们要求它必须指向符合给他定义的参数与返回值的函数,这就是一个函数指针,它必须指向函数。指针的本质就是存储一个所指的地址,所以传参时传递的就是一个地址,函数的本质也是一个地址,所以传参时我们就可以将函数名作为实参传递出去,这个指针收到地址后存储,就是指向了地址对应的函数,那么我们就成功在一个函数里通过指针调用了另外一个函数。既然调用的函数是有参数与返回值的,所以我们定义的函数的返回值必须与所调函数一致,还需增加参数值,个数与类型都要与所掉函数的参数一致。

举个例子,我们定义一个calc函数,希望通过这个函数实现对其他函数如sub,add函数自由的调用。

首先我们定义add函数与sub函数:int add(int ,int );      int sub(int ,int );

这两个函数的返回值与参数类型都是int,参数都具有两个。

接下来就是定义calc函数并实现对sub或add的调用了:

刚刚说过,要实现对其他函数的调用,需要定义一个函数指针,来接收不同的函数的地址,接收谁的地址,就调用谁。然后执行函数的返回值类型与参数个数,类型还必须与所调函数的返回值与参数完全一样。

所以我们这么定义calc:int calc(int (*fp)(int ,int ),int ,int );

calc函数有三个参数,第一个参数为函数指针类型的参数,它可以调用其他的函数,第二个、三个为整形参数,为调用成功后函数的参数,所调函数进行运算完毕后,必然返回一个值,所以calc的返回值必须与所调函数的返回值一样,接受了所调函数的返回值再返出calc函数。

当我们在主函数里调用calc时就是这样:calc(add,5,8); 实参分别为add函数的地址,参数5,和参数8。

反正就是函数指针他必须接收函数!!,接收了就能实现指针调用函数。可以是函数指针与函数直接相等,也可以通过传参进行传递。当然成功调用的前提是函数指针的定义(即返回值,参数)都要正确,都要符合所指函数的类型。

当函数指针作为参数时,就表示它要开始调用函数了!

将函数指针作为返回值:

什么意思呢?

比如这个函数的名字叫select,它本身有两个参数,返回的返回值是一个函数指针,这个函数指针也具有两个参数,并且其返回值为整型。那么这个返回函数指针的select函数就是一个返回函数指针(地址)的函数,既然函数指针(地址)作为返回值,那么我们需要再定义一个与返回函数同类型的函数指针来接收它。

这个函数怎么写?

int (*select(int ,int ))(int ,int );

这个式子从第一次出现的变量select看起,向右读,与参数结合形成带两个整形参数的函数,碰到括号想向左看,只有一个*,那么*就是select函数的返回值,select返回一个地址。这个地址可以是一个函数的地址,而最希望得到函数地址的是函数指针,所以我们就定一个函数指针来接收select函数返回的地址,完成函数指针对select返回的函数的调用。

如果我们想把此函数指针放到其他函数里进行调用,即用其他函数调用这个函数指针作为返回值形成的函数指针,我们最好新建一个函数指针来接收此函数指针 ,int (*fp)(int ,int ) = int (*select(int,int ))(int ,int)  这样调用时就不需要使用函数名select而是使用函数指针fp,这样调用就直观多了。

说不清楚也容易说错,下面是使用函数指针作为返回值完成的计算器代码:

#include <stdio.h>

int add(int ,int);
int sub(int ,int); 
int (*select(char))(int ,int );  // 定义一个函数指针,指向函数返回的地址 
 
int add(int num1 ,int num2)
{
	return num1 + num2; 
}  
int sub(int num1 ,int num2)
{
	return num1 - num2;
}
//calc方法  调用函数的函数 
int calc(int (*fp)(int ,int),int num1,int num2) 
{
	return (*fp)(num1,num2);
}
//select方法  select的返回值是地址
int (*select(char op))(int ,int)  									 
{
	switch(op)
	{
		case '+' : return add;
		case '-' : return sub;
	}
}

int main()
{
	int num1 ,num2;
	char op;
        int (*fp)(int ,int);  //定义一个函数指针fp来接受select函数返回的地址形成的函数指针

	printf("请输入一个式子:");
	scanf("%d%c%d",&num1,&op,&num2);

	fp = select(op);
	//根据op决定调用的函数
	printf("%d %c %d = %d",num1,op,num2,calc(fp,num1,num2)); 
	
	return 0;
}

main函数中,在calc调用那里也可以不用fp接收,直接这么写:

int main()
{
	int num1 ,num2;
	char op;
	printf("请输入一个式子:");
	scanf("%d%c%d",&num1,&op,&num2);
	int (*fp)(int ,int ) = int (*select(char op))(int ,int ); 
	
	//根据op决定调用的函数
	printf("%d %c %d = %d",num1,op,num2,calc(select(op),num1,num2)); 
	
	return 0;
}

简而言之,以上实现输入字符就能调用对应方法的原理就是:

函数select根据输入的字符返回对应方法的函数地址,仅仅返回函数地址不可取,我们需要定义一个函数指针来接收这个地址,由此形成可以指向方法函数的函数指针。而这个函数指针又可以在别的函数中作为参数被调用,执行调用的函数需要定义相同的参数与返回值供此函数指针使用。

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章