33
第第第 第第第第第 第第第 第第第第第 5.1 5.1 第第第第第 第第第第第第第第第第 第第第第第 第第第第第第第第第第 5.2 5.2 第第第第第第第第第第 第第第第第第第第第第 5.3 5.3 第第第第第第第第第第 5.4 5.4 第第第第第第第第第第第第第第 第第第第第第第第第第第第第第 5.5 5.5 第第第第第第第第 第第第第第第第第

第五章 指针和函数

  • Upload
    lucia

  • View
    136

  • Download
    2

Embed Size (px)

DESCRIPTION

第五章 指针和函数. 5.1 指针的概念、指针变量的定义和引用 5.2 指针变量作函数的参数 5.3 函数的指针与函数调用 5.4 指向函数的指针变量作函数参数 5.5 返回指针值的函数. 5.1 指针的概念、指针变量的定义和引用. 变量和地址 指针变量的概念 指针变量的定义 指针变量的初始化 指针变量的引用. …………. 2000. i. 5. 2001. 2002. j. 3. 2003. ‘H’. 2004. ch. 2005. 2006. f. 3.14. 2007. 2008. 2009. …………. - PowerPoint PPT Presentation

Citation preview

Page 1: 第五章  指针和函数

第五章 指针和函数第五章 指针和函数 5.15.1 指针的概念、指针变量的定义和引用 指针的概念、指针变量的定义和引用 5.2 5.2 指针变量作函数的参数指针变量作函数的参数 5.3 5.3 函数的指针与函数调用 5.45.4 指向函数的指针变量作函数参数 指向函数的指针变量作函数参数 5.55.5 返回指针值的函数返回指针值的函数

Page 2: 第五章  指针和函数

5.15.1 指针的概念、指针变量的定义和引用 指针的概念、指针变量的定义和引用 变量和地址变量和地址 指针变量的概念指针变量的概念 指针变量的定义指针变量的定义 指针变量的初始化指针变量的初始化 指针变量的引用指针变量的引用

Page 3: 第五章  指针和函数

变量和地址变量和地址 地址地址::一个变量名代表内存中的一个存储单元,每个存储单元都有一个一个变量名代表内存中的一个存储单元,每个存储单元都有一个编号,这就是“地址”。编号,这就是“地址”。

房间—变量名 房客—变量值 房间号—地址 int i,j; char ch; float f;

i=5; j=3; ch=’H’; f=3.14; 5

3‘H’3.14

i

jch

f

…………

…………

2000

2002

20042005

2009

2001

2003

200620072008

编译或函数调用时为变量分配内存单元

内存中每个字节有一个编号——地址 变量是对程序中数据存储空间的抽象

Page 4: 第五章  指针和函数

指针变量的概念指针变量的概念

…...

…...

2000

2004

20062005

整型变量 i20

变量 ptr

200120022003

指针:一个变量的地址。 指针变量:专门存放另一变量地址的变量。

2000

指针

指针变量

变量的内容 变量的地址

指针变量变量变量地址 ( 指针 )

变量值指向 地址存入指针变量

Page 5: 第五章  指针和函数

指针变量的定义指针变量的定义 [ 存储类型 ] 数据类型 * 指针变量名;

int i,j,*pi, *pj; float f; float *pf;合法标识符指针变量本身的存储类型表示定义指针变量不是‘ *’ 运算符注:(1) int *p1, *p2; 指针变量名是 p1,p2 , 不是 *p1,*p2 。(2) 指针变量只能指向定义时所规定类型的变量。(3) 指针变量定义后,变量值不确定,应用前必须先赋值。

指针的目标变量的数据类型

Page 6: 第五章  指针和函数

指针变量的初始化指针变量的初始化

赋给指针变量,不是赋给目标变量例 int i; int *p=&i; 变量必须已说明过类型应一致例 int *p=&i;

int i; ()例 int i; int *p=&i; int *q=p; 用已初始化指针变量作初值

例 main( ) { int x; static int *p=&x; .............. } ()不能用 auto 变量的地址去初始化 static 型指针

一般形式: [ 存储类型 ] 数据类型 * 指针名 = 初始地址值;

Page 7: 第五章  指针和函数

指针变量的引用指针变量的引用 & : 取变量的地址。单目运算符、优先级为取变量的地址。单目运算符、优先级为 22 、右、右结合性。结合性。 设有程序段代码:

int i,*ptr; i=20; ptr=&i; ptr 和 i 的关系如图

Page 8: 第五章  指针和函数

指针变量的引用指针变量的引用 * :取指针变量所指地址中的内容,与取指针变量所指地址中的内容,与 && 为互逆运算。单目为互逆运算。单目运算符、优先级为 运算符、优先级为 22 、右结合性。、右结合性。 有程序段:有程序段:int x=20,y,*ptr;int x=20,y,*ptr;ptr=&x;ptr=&x;y=*ptr;y=*ptr;

该段程序的意思是:定义整型变量该段程序的意思是:定义整型变量 xx (初值为(初值为 2020 )和)和 yy 以以及指向整型的指针变量及指向整型的指针变量 ptrptr 。将变量。将变量 xx 的地址赋给指针变量的地址赋给指针变量ptrptr ,然后以指针变量,然后以指针变量 ptrptr 的值为内存单元地址,将该单元的值为内存单元地址,将该单元的数据取出赋给变量的数据取出赋给变量 yy 。即相当于执行语句。即相当于执行语句 y=x; y=x;

Page 9: 第五章  指针和函数

注意:注意: 乘法运算符号和指针操作符号乘法运算符号和指针操作符号 ** 形式上相同,位运形式上相同,位运算符号与(算符号与( && )与指针运算符号)与指针运算符号 && 也相同。但是这也相同。但是这些运算符号之间没有任何关系些运算符号之间没有任何关系 ,, 编译器根据他们在编译器根据他们在程序中所处的位置来解释他们,在使用的时候要注程序中所处的位置来解释他们,在使用的时候要注意它们使用的场合。 意它们使用的场合。

Page 10: 第五章  指针和函数

例例 5-15-1 #include "stdio.h"#include "stdio.h" main()main() {{ int num_int=12, *p_int;/*int num_int=12, *p_int;/* 定义一个指向定义一个指向 intint 型数据的指针变量型数据的指针变量 p_int */p_int */ float num_f=3.14, *p_f;float num_f=3.14, *p_f; /*/* 定义一个指向定义一个指向 floatfloat 型数据的指针变量型数据的指针变量 p_f *p_f *// char num_ch='p', *p_ch;char num_ch='p', *p_ch; /*/* 定义一个指向定义一个指向 charchar 型数据的指针变量型数据的指针变量 ph *ph *// p_int=&num_int; p_int=&num_int; /*/* 取变量取变量 num_intnum_int 的地址,赋值给的地址,赋值给 p_int */p_int */ p_f=&num_f; p_f=&num_f; /*/* 取变量取变量 num_fnum_f 的地址,赋值给的地址,赋值给 p_f */p_f */ p_ch=&num_ch; p_ch=&num_ch; /*/* 取变量取变量 num_chnum_ch 的地址,赋值给的地址,赋值给 p_ch */p_ch */ printf("num_int=%d, *p_int=%d", num_int, *p_int);printf("num_int=%d, *p_int=%d", num_int, *p_int); printf("num_f=%4.2f, *p_f=%4.2f\n", num_f, *p_f);printf("num_f=%4.2f, *p_f=%4.2f\n", num_f, *p_f); printf("num_ch=%c, *p_ch=%c\n", num_ch, *p_ch);printf("num_ch=%c, *p_ch=%c\n", num_ch, *p_ch); }} [[ 程序演示程序演示 ]]

Page 11: 第五章  指针和函数

程序运行结果:程序运行结果:num_int=12, *p_int=12num_int=12, *p_int=12num_f=3.14, *p_f=3.14num_f=3.14, *p_f=3.14num_ch=p, *p_ch=pnum_ch=p, *p_ch=p 程序说明程序说明::(( 11 )头三行的变量定义语句──指针变量的定义)头三行的变量定义语句──指针变量的定义 注意注意:此时的指针变量:此时的指针变量 p_intp_int 、、 p_fp_f 、、 p_chp_ch ,并,并未指向某个具体的变量(称指针是悬空的)。使用未指向某个具体的变量(称指针是悬空的)。使用悬空指针很容易破坏系统,导致系统瘫痪。悬空指针很容易破坏系统,导致系统瘫痪。

Page 12: 第五章  指针和函数

(2)(2) 中间三行的赋值语句──取地址运算中间三行的赋值语句──取地址运算 (( && ))取地址运算的格式: 取地址运算的格式: &变量&变量例如,例如, &num_int&num_int 、、 &num_f&num_f 、、 &num_ch&num_ch 的结果,分别为的结果,分别为变量变量 num_intnum_int 、、 num_fnum_f 、、 num_chnum_ch 的地址。的地址。注意注意:指针变量只能存放指针(地址),且只能是相同类型变:指针变量只能存放指针(地址),且只能是相同类型变量的地址。量的地址。例如,指针变量例如,指针变量 p_intp_int 、、 p_fp_f 、、 p_chp_ch ,只能分别接收,只能分别接收 intint 型、型、floatfloat 型、型、 charchar 型变量的地址,否则出错。型变量的地址,否则出错。(( 33 )后三行的输出语句──指针运算()后三行的输出语句──指针运算( ** ))使用直接访问和间接访问两种方式,分别输出变量使用直接访问和间接访问两种方式,分别输出变量 num_intnum_int 、、num_fnum_f 、、 num_chnum_ch 的值。的值。注意注意:这三行出现在指针变量前的星号“:这三行出现在指针变量前的星号“ *”*” 是指针运算符,是指针运算符,访问指针变量所指向的变量的值,而非指针运算符。访问指针变量所指向的变量的值,而非指针运算符。

Page 13: 第五章  指针和函数

指针的算术运算:指针的算术运算: 若 p=&i; 有 pn &i sizeof(i)n p++, p--, p+n, p-n, p+=n, p-=n 的含义例例 5-25-2 #include <stdio.h>#include <stdio.h> void main()void main() {{ int a=1,b=2,c=3,*ptr;int a=1,b=2,c=3,*ptr; ptr=&b;ptr=&b; printf("b:Address %x,Value %d\n",ptr,b);printf("b:Address %x,Value %d\n",ptr,b); ptr++;ptr++; printf("c:Address %x,Value %d\n",ptr,c);printf("c:Address %x,Value %d\n",ptr,c); ptr-=2;ptr-=2; printf("a:Address %x,Value %d\n",ptr,a);printf("a:Address %x,Value %d\n",ptr,a); }}

Page 14: 第五章  指针和函数

在程序的一次执行中,输出结果可能是在程序的一次执行中,输出结果可能是 (( 不同的计不同的计算机变量存储的位置可能不同算机变量存储的位置可能不同 )) :: b:Address fff2,Value 2b:Address fff2,Value 2 c:Address fff4,Value 3c:Address fff4,Value 3 a:Address fff0,Value 1a:Address fff0,Value 1 从程序的执行结果中可以看出,程序中定义的三个从程序的执行结果中可以看出,程序中定义的三个整型变量整型变量 aa 、、 bb 、、 cc 在内存中依次存放,首先我们在内存中依次存放,首先我们让指针变量让指针变量 ptrptr 指向变量指向变量 bb ,输出变量,输出变量 bb 的存放地的存放地址为址为 fff2fff2 ;之后将指针变量作增一运算,指针变量;之后将指针变量作增一运算,指针变量的值实际增加的值实际增加 1*2=21*2=2 ,此时,此时 ptrptr 指向变量指向变量 cc ,输出,输出其地址值为其地址值为 fff4fff4 ;最后对指针变量作;最后对指针变量作 ptr-2ptr-2 操作,操作,让让 ptrptr 指向变量指向变量 aa ,输出其地址值,输出其地址值 fff0fff0 。。

Page 15: 第五章  指针和函数

指针变量的逻辑运算 :指针变量的逻辑运算 : 例例 5-35-3 :: #include <stdio.h>#include <stdio.h> void main()void main() {{ int a=1,b=2,*aptr,*bptr;int a=1,b=2,*aptr,*bptr; aptr=&a;aptr=&a; bptr=&b;bptr=&b; printf("a:Address %x;b:Address %x\n",aptr,bptr);printf("a:Address %x;b:Address %x\n",aptr,bptr); printf("aptr>bptr=%d\n",aptr>bptr);printf("aptr>bptr=%d\n",aptr>bptr); printf("aptr<=bptr=%d\n",aptr<=bptr);printf("aptr<=bptr=%d\n",aptr<=bptr); printf("aptr&&bptr=%d\n",aptr&&bptr);printf("aptr&&bptr=%d\n",aptr&&bptr); }} 在程序的一次执行中,输出结果可能是:在程序的一次执行中,输出结果可能是: a:Address fff4,b:Address fff2a:Address fff4,b:Address fff2 aptr>bptr=1aptr>bptr=1 aptr<=bptr=0aptr<=bptr=0 aptr&&bptr=1aptr&&bptr=1

Page 16: 第五章  指针和函数

对于指针变量,下列运算是没有意义的或者是不允许的:对于指针变量,下列运算是没有意义的或者是不允许的:(( 11 )除加减某一整数运算以外的其他算术运算,如:乘、除、)除加减某一整数运算以外的其他算术运算,如:乘、除、求模等;求模等;(( 22 )两个指针变量的加法运算是没有意义的,无论它们指向)两个指针变量的加法运算是没有意义的,无论它们指向的是同一种数据类型还是不同的数据类型;例如有两个指针的是同一种数据类型还是不同的数据类型;例如有两个指针变量变量 ptraptra 和和 ptrbptrb ,那么,那么 ptra+ptrbptra+ptrb 没有任何意义。没有任何意义。(( 33 )空指针变量是无意义的而且是危险的。定义一个指针后)空指针变量是无意义的而且是危险的。定义一个指针后没有使其指向一个确定的地址,这个指针变量称为空指针,没有使其指向一个确定的地址,这个指针变量称为空指针,其错误信息是:其错误信息是: Null point assigmentNull point assigment 。当使用空指针时,。当使用空指针时,其结果是不可预料的,严重时可能造成系统瘫痪。其结果是不可预料的,严重时可能造成系统瘫痪。

Page 17: 第五章  指针和函数

例例 5-45-4 输入输入 xx 、、 yy ,, zz三个整数,输出最大值和最小值(使用指针方式实现)。 三个整数,输出最大值和最小值(使用指针方式实现)。 分析:找出三个数的最大值和最小值可以先找两个数中的最大值和最小值,然后再和第三分析:找出三个数的最大值和最小值可以先找两个数中的最大值和最小值,然后再和第三个数比较就可以找出三个数的最大和最小值。个数比较就可以找出三个数的最大和最小值。 算法描述:算法描述: 算法开始算法开始 定义数据对象:定义数据对象: x,y,zx,y,z为整型变量为整型变量 pmax,pminpmax,pmin 为整型指针变量。为整型指针变量。 输入 输入 x,y,zx,y,z if if (( x>yx>y )) thenthen 指针变量赋值:指针变量赋值: pmax=xpmax=x ;; 指针变量赋值: 指针变量赋值: pmin=ypmin=y ;; ElseElse 指针变量赋值:指针变量赋值: pmax=ypmax=y ;; 指针变量赋值: 指针变量赋值: pmin=xpmin=x ;; if( z>pmax) then if( z>pmax) then pmax=zpmax=z;; if(z<pmin) then if(z<pmin) then pmin=zpmin=z;; 输出结果输出结果 pmax,pminpmax,pmin 。。 算法结束算法结束

Page 18: 第五章  指针和函数

根据算法描述编写程序代码如下:根据算法描述编写程序代码如下: #include <stdio.h>#include <stdio.h> void main()void main() {{ int x,y,z,*pmax,*pmin;int x,y,z,*pmax,*pmin;printf("Input three numbers:\n");printf("Input three numbers:\n"); scanf("%d%d%d",&x,&y,&z);scanf("%d%d%d",&x,&y,&z); if(x>y)if(x>y) {{ pmax=&x;pmax=&x; pmin=&y;pmin=&y; }} elseelse {{ pmax=&y;pmax=&y; pmin=&x;pmin=&x; }} if(z>*pmax) if(z>*pmax) pmax=&z;pmax=&z; if(z<*pmin) if(z<*pmin) pmin=&z;pmin=&z; printf("max=%d\nmin=%d\n",*pmax,*pmin);printf("max=%d\nmin=%d\n",*pmax,*pmin); }}

Page 19: 第五章  指针和函数

5.2 5.2 指针变量作函数的参数指针变量作函数的参数1.1. 指针变量,既可以作为函数的形参,也可以作函数指针变量,既可以作为函数的形参,也可以作函数的实参。的实参。2.2. 指针变量作实参时,与普通变量一样,也是“值传指针变量作实参时,与普通变量一样,也是“值传递”,即将指针变量的值(一个地址)传递给被调递”,即将指针变量的值(一个地址)传递给被调用函数的形参(必须是一个指针变量)。用函数的形参(必须是一个指针变量)。注意注意:被调用函数不能改变实参指针变量的值,但可:被调用函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值。以改变实参指针变量所指向的变量的值。

Page 20: 第五章  指针和函数

例例 5-45-4 输入两个整数,将数从大到小排列 输入两个整数,将数从大到小排列 #include <stdio.h>#include <stdio.h> void main()void main() {{ void swap(int *ptr1,int *ptr2);void swap(int *ptr1,int *ptr2); int a,b,*p1,*p2;int a,b,*p1,*p2; printf("Input a,b:");printf("Input a,b:"); scanf("%d%d",&a,&b);scanf("%d%d",&a,&b); printf("a=%d,\tb=%d\n",a,b);printf("a=%d,\tb=%d\n",a,b); p1=&a;p1=&a; p2=&b;p2=&b; if(a<b)if(a<b) swap(p1,p2);swap(p1,p2); printf(“after swap:\n”);printf(“after swap:\n”); printf("a=%d,\tb=%d\n",a,b);printf("a=%d,\tb=%d\n",a,b); }}

Page 21: 第五章  指针和函数

void swap(int *x,int *y)void swap(int *x,int *y) {{ int temp;int temp; temp=*x;temp=*x; *x=*y;*x=*y; *y=temp;*y=temp; }} input a,binput a,b :: 7 10(7 10( 用户从键盘输入数据用户从键盘输入数据 )) a=7,b=10a=7,b=10 after swap:after swap: a=10,b=7a=10,b=7

Page 22: 第五章  指针和函数

例子中调用函数例子中调用函数 swap(p1,p2),swap(p1,p2), 在函数在函数 swapswap 中中对对 *ptr1*ptr1 和和 *ptr2*ptr2 操作其实就是访问操作其实就是访问 mainmain 函数中函数中变量变量 aa 和和 bb 。通过函数体中的局部变量。通过函数体中的局部变量 temptemp ,使,使变量变量 aa 和和 bb 的值被修改。调用时,给予了的值被修改。调用时,给予了 aa 和和 bb 的的地址作为参数,函数地址作为参数,函数 swapswap 运行后间接修改了运行后间接修改了 aa 和和bb 的值。变量在内存中的存储结构如图所示。 的值。变量在内存中的存储结构如图所示。

Page 23: 第五章  指针和函数

5.3 函数指针与函数调用1.1. 函数指针的概念函数指针的概念 一个函数在编译时,被分配了一个入口地址,这个地址就称为该函数的指针。 一个函数在编译时,被分配了一个入口地址,这个地址就称为该函数的指针。可以用一个指针变量指向一个函数,然后通过该指针变量调用此函数。可以用一个指针变量指向一个函数,然后通过该指针变量调用此函数。2.2. 指向函数的指针变量指向函数的指针变量 ( ( 11 )定义格式)定义格式 函数类型 函数类型 (*(* 指针变量指针变量 )( ))( ) ;; 注意注意:“:“ ** 指针变量”外的括号不能缺,否则成了返回指针值的函数。指针变量”外的括号不能缺,否则成了返回指针值的函数。 例如, 例如, int (*fp)(); int (*fp)(); /* fp/* fp 为指向为指向 intint 函数的指针变量函数的指针变量 */*/ (( 22 )赋值)赋值 函数名代表该函数的入口地址。因此,可用函数名给指向函数的指针变量赋 函数名代表该函数的入口地址。因此,可用函数名给指向函数的指针变量赋值。值。 指向函数的指针变量=指向函数的指针变量= [&][&] 函数名函数名 ;; 注意注意:函数名后不能带括号和参数;函数名前的“:函数名后不能带括号和参数;函数名前的“ &”&” 符号是可选的。符号是可选的。 (3)(3) 调用格式调用格式 (*(* 函数指针变量函数指针变量 )([)([ 实参表实参表 ])])

Page 24: 第五章  指针和函数

例如有如下定义:例如有如下定义:int (*function)();int (*function)();定义了一个指向返回值为整型的无参函数的指针(简称为指向整型函数的指定义了一个指向返回值为整型的无参函数的指针(简称为指向整型函数的指针)针) functionfunction 。。 (( 33 )用指向函数的指针变量来调用函数 )用指向函数的指针变量来调用函数 定义指向函数的指针后,就可以将一个函数的名字赋给该指针变量。在给定义指向函数的指针后,就可以将一个函数的名字赋给该指针变量。在给函数指针变量赋值时,只需要给出函数名而不必给出参数。例如:函数指针变量赋值时,只需要给出函数名而不必给出参数。例如: 函数说明为:函数说明为: void swap(int *ptr1,int *ptr2)void swap(int *ptr1,int *ptr2) ;; 指向函数的指针变量定义为:指向函数的指针变量定义为: void (*fptr)(int *ptr1,int *ptr2);void (*fptr)(int *ptr1,int *ptr2); 则将函数则将函数 swapswap 的地址赋给指针变量的地址赋给指针变量 fptrfptr 的表达式为:的表达式为: fptr=swap;fptr=swap; 对于有了确定的指向的指向函数的指针变量施以指针运算(星号运算)时,对于有了确定的指向的指向函数的指针变量施以指针运算(星号运算)时,就是使程序控制转移到指针指向的地址去执行该函数的函数体。就是使程序控制转移到指针指向的地址去执行该函数的函数体。

Page 25: 第五章  指针和函数

例例 5-5 5-5 从键盘输入一个大于从键盘输入一个大于 11 的正整数的正整数 n,n, 当当 nn 为偶数时,计算为偶数时,计算 1+1/221/421+1/221/42۰۰۰۰++1/n2++1/n2 ,, 当当 nn 为奇数时,计算为奇数时,计算 1+1/32+1/521+1/32+1/52۰۰۰۰۰۰++1/n2++1/n2 要求使用指向函数的指针变量来实现该程序。要求使用指向函数的指针变量来实现该程序。 算法描述:算法描述: 算法开始算法开始 定义定义 ptr ptr /* ptr/* ptr 是指向函数的指针变量是指向函数的指针变量 */*/ 输入输入 nn IfIf (( n>1n>1 ) ) then then If(nIf(n 是偶数是偶数 ) then ) then ptr<- ptr<- 函数函数 fun1fun1 的起始地址的起始地址 elseelse ptr<- ptr<- 函数函数 fun2fun2 的起始地址的起始地址 输出计算结果输出计算结果 ElseElse 系统提示输入错误系统提示输入错误 算法结束算法结束

Page 26: 第五章  指针和函数

根据以上算法描述写出程序代码如下:根据以上算法描述写出程序代码如下: #include <stdio.h>#include <stdio.h> double func1(int x),func2(int y);double func1(int x),func2(int y); void main()void main() {{ double (*fptr)(int); /*double (*fptr)(int); /* 定义指向函数的指针变量定义指向函数的指针变量 fptr*/fptr*/ int n;int n; printf(“input a numberprintf(“input a number :”:” );); scanf(“%d”,&n);scanf(“%d”,&n); if(n>1)if(n>1) {{ if(n%2==0)if(n%2==0) fptr=func1;/*nfptr=func1;/*n 为偶数,指针变量为偶数,指针变量 ptrptr 指向函数指向函数 func1()*/func1()*/ elseelse fptr=func2; /*nfptr=func2; /*n 为奇数,指针变量为奇数,指针变量 ptrptr 指向函数指向函数 func2()*/func2()*/ printf(“value=%9.4f\n”,(*fptr)(n));printf(“value=%9.4f\n”,(*fptr)(n)); }} else else printf(“error!\n”);printf(“error!\n”); }}

Page 27: 第五章  指针和函数

double func1(int x)double func1(int x) {{ int k;int k; double value;double value; value=1.0;value=1.0; for(k=2;k<=x;k=k+2)for(k=2;k<=x;k=k+2) value=value+(1/(double)k)*(1/(double)k);value=value+(1/(double)k)*(1/(double)k); return value;return value; }} double func2(int y)double func2(int y) {{ int k;int k; double value;double value; value=1.0;value=1.0; for(k=3;k<=y;k=k+2)for(k=3;k<=y;k=k+2) value=value+(1/(double)k)* (1/(double)k);value=value+(1/(double)k)* (1/(double)k); return value;return value; }} [[ 程序演示程序演示 ]]

Page 28: 第五章  指针和函数

使用指向函数的指针可以很方便的调用函数,但是在使用的使用指向函数的指针可以很方便的调用函数,但是在使用的过程中要注意以下事项:过程中要注意以下事项: (( 11 )在给函数指针变量赋值时,只需要给出函数名,不必)在给函数指针变量赋值时,只需要给出函数名,不必要给出参数。如例子中“要给出参数。如例子中“ fptr=func1;”fptr=func1;” 。。 (( 22 )调用前必须给函数指针变量赋值。如例子中运行语句)调用前必须给函数指针变量赋值。如例子中运行语句(( *p*p )) (n)(n) 前,要对函数指针变量进行赋值语句操作:“前,要对函数指针变量进行赋值语句操作:“ ffptr=func1;”ptr=func1;” 或者“或者“ fptr=func2;”fptr=func2;” 。。 (( 33 )函数指针)函数指针 fptrfptr 可以先后指向同类型的不同的函数,如:可以先后指向同类型的不同的函数,如:fptr=func1; fptr=func2;fptr=func1; fptr=func2; (( 44 )前面学过对于指针变量可以进行加减运算,但是对于)前面学过对于指针变量可以进行加减运算,但是对于函数指针来说它的运算是没有意义的。比如说函数指针来说它的运算是没有意义的。比如说 fptrfptr 为函数指为函数指针变量,则针变量,则 fptr=fptr+1fptr=fptr+1或或 fptr=fptr-1fptr=fptr-1 是没有意义的。是没有意义的。

Page 29: 第五章  指针和函数

5.45.4 指向函数的指针变量作函数参数指向函数的指针变量作函数参数指向函数的指针变量的常用用途之一,就是将函数指指向函数的指针变量的常用用途之一,就是将函数指针作参数,传递到其它函数。针作参数,传递到其它函数。函数名作实参时,因为要缺省括号和参数,造成编译函数名作实参时,因为要缺省括号和参数,造成编译器无法判断它是一个变量还是一个函数,所以必须器无法判断它是一个变量还是一个函数,所以必须加以说明。函数说明的格式,与第加以说明。函数说明的格式,与第 77 章中介绍的一章中介绍的一样。样。注意注意:对指向函数的指针变量,诸如:对指向函数的指针变量,诸如 p+ip+i 、、 p++/p--p++/p--等运算是没有意义的。等运算是没有意义的。

Page 30: 第五章  指针和函数

例例 5-6 5-6 求函数求函数 f1(x)=1+x2f1(x)=1+x2 在区间在区间 [0[0 ,, 1]1] 和函数和函数 f2(x)=1/f2(x)=1/(( 1+16x21+16x2 )在区间)在区间 [0[0 ,, 2.0]2.0] 的定积分。的定积分。 算法描述:算法描述: (( 11 )对两个被积函数,各定义一个函数,类型为)对两个被积函数,各定义一个函数,类型为 double,double,形参形参 xx ,类型为,类型为 double.double. (( 22 )定义定积分通用函数:)定义定积分通用函数: double collect(double (*p)double collect(double (*p)(float x),float a,float b,int n)(float x),float a,float b,int n) 。它有四个形参,。它有四个形参, pp 为函数为函数指针名,类型为指针名,类型为 doubledouble 与被积函数类型相同。形参与被积函数类型相同。形参 aa 为积为积分下限,分下限, bb 为积分上限,为积分上限, nn 为区间等份数。为区间等份数。 (( 33 )主函数中分别用被积分的函数名字做实参数,两次调)主函数中分别用被积分的函数名字做实参数,两次调用定积分通用函数用定积分通用函数 collectcollect 。积分上下限和等份数。积分上下限和等份数 nn 直接做直接做实参。实参。

Page 31: 第五章  指针和函数

根据算法描述写出程序代码如下:根据算法描述写出程序代码如下: #include <stdio.h>#include <stdio.h> void main()void main() {{ int n;int n; double y1,y2;double y1,y2; double fun1(float x);double fun1(float x); double fun2(float x);double fun2(float x); double collect(double (*p)(float x),float a,float b,int n);double collect(double (*p)(float x),float a,float b,int n); y1=collect(fun1,0.0,1.0,200);y1=collect(fun1,0.0,1.0,200); y2=collect(fun2,0.0,2.0,200);y2=collect(fun2,0.0,2.0,200); printf("y1=%f\ny2=%f\n",y1,y2);printf("y1=%f\ny2=%f\n",y1,y2); }} double collect(double (*p)(float x),float a,float b,int n)double collect(double (*p)(float x),float a,float b,int n) {{ int i;int i; float f,h,area;float f,h,area; h=(b-a)/n;h=(b-a)/n; area=((*p)(a)+(*p)(b))/2.0;area=((*p)(a)+(*p)(b))/2.0; for(i=1;i<n;i++)for(i=1;i<n;i++) area+=(*p)(a+i*h);area+=(*p)(a+i*h); return(area*h);return(area*h); }}

Page 32: 第五章  指针和函数

double fun1(float x)double fun1(float x) /*/* 定义定义 1+x21+x2 的的 CC函数形函数形式式 */*/ {{ float f;float f; f=1+x*x;f=1+x*x; return(f);return(f); }} double fun2(float x)double fun2(float x) /*/* 定义定义 1/1/ (( 1+16x21+16x2 ))的的 CC函数形式函数形式 */*/ {{ float f;float f; f=1/(1+16*x*x);f=1/(1+16*x*x); return(f);return(f); }} [[ 程序演示程序演示 ]]

Page 33: 第五章  指针和函数

5.55.5 返回指针值的函数返回指针值的函数 任何一个函数都要返回一个值,这个返回值的数据类型可以是整型、实任何一个函数都要返回一个值,这个返回值的数据类型可以是整型、实型(、字符型等基本数据类型,也可以是空类型(型(、字符型等基本数据类型,也可以是空类型( voidvoid )。除此之外,)。除此之外,CC 语言中还有一种函数在调用后可以返回一个指针型数据(地址),这语言中还有一种函数在调用后可以返回一个指针型数据(地址),这种函数称为返回指针值的函数。返回指针值的函数的定义形式如下:种函数称为返回指针值的函数。返回指针值的函数的定义形式如下: 存储类型 数据类型 存储类型 数据类型 ** 函数名(形式参数表);函数名(形式参数表); 例如有函数定义的头部为:例如有函数定义的头部为: float *funcname(float x,float y)float *funcname(float x,float y) 说明:(说明:( 11 )) floatfloat表示函数返回的指针用于指向实型对象。表示函数返回的指针用于指向实型对象。 (( 22 )) funcnamefuncname 是函数名,函数名前面的星号表示函数是函数名,函数名前面的星号表示函数 funcnamefuncname是一个返回指针值的函数,其返回的值是指向实型数据的指针值。是一个返回指针值的函数,其返回的值是指向实型数据的指针值。 可以将可以将 float *funcname(float x,float y)float *funcname(float x,float y) 与与 float *ptrfloat *ptr 对照来理解。对照来理解。定义定义 ptrptr 时不加时不加 ** 是普通的实型变量,加了是普通的实型变量,加了 ** 后后 ptrptr 就是实型指针变量就是实型指针变量 ,,存储的是实型变量的地址。同样,存储的是实型变量的地址。同样, funcnamefuncname 前面不加前面不加 ** 是普通的函数,是普通的函数,返回值是实型,加了返回值是实型,加了 ** 后就是返回指针值的函数。后就是返回指针值的函数。 (( 33 )实型变量)实型变量 xx 和和 yy 是函数的形式参数。是函数的形式参数。 (( 44 )主调函数体中要对返回指针值的函数作声明。)主调函数体中要对返回指针值的函数作声明。