浙江大学刘加海C语言课件5.docx

上传人:b****7 文档编号:9364757 上传时间:2023-02-04 格式:DOCX 页数:19 大小:26.89KB
下载 相关 举报
浙江大学刘加海C语言课件5.docx_第1页
第1页 / 共19页
浙江大学刘加海C语言课件5.docx_第2页
第2页 / 共19页
浙江大学刘加海C语言课件5.docx_第3页
第3页 / 共19页
浙江大学刘加海C语言课件5.docx_第4页
第4页 / 共19页
浙江大学刘加海C语言课件5.docx_第5页
第5页 / 共19页
点击查看更多>>
下载资源
资源描述

浙江大学刘加海C语言课件5.docx

《浙江大学刘加海C语言课件5.docx》由会员分享,可在线阅读,更多相关《浙江大学刘加海C语言课件5.docx(19页珍藏版)》请在冰豆网上搜索。

浙江大学刘加海C语言课件5.docx

浙江大学刘加海C语言课件5

第5章指针与函数

◆本章重点

1.函数指针的概念、定义及赋值。

2.函数指针的应用。

3.指针函数的定义。

4.命令行参数的应用。

◆本章难点

1.函数指针的概念,函数指针的赋值及调用方法。

尤其是定义及调用中的形式参数及实际参数的使用。

2.指针函数的概念以及与函数指针的区别。

3.命令行参数编程中的文件名与命令的关系。

4.命令行参数的赋值方法。

指针和函数的关系主要包括三个方面的内容:

一是指针可以指向某个函数,即函数指针;二是函数的返回值可以是指针类型的变量,即指针函数;三是指针可以作为函数的参数。

5.1指向函数的指针

大家知道,变量a被分配到某个存储区域,若指针变量p的值为该存储区域的首地址,则称p为指向变量a的指针,通过对指针p的间接引用可以访问它所指向的变量a。

函数虽然不是变量,但是它经过编译后,其目标代码在内存中是连续存放的,该代码的首地址就是函数执行时的入口地址,它可以赋给指针变量,使得指针变量指向函数。

利用指向函数的指针变量,可以代替函数名,也可以作为函数的参数传递给其他函数。

也就是说可以用指针变量指向基本类型变量、字符串、数组等,也可指向一个函数。

一个函数在编译时被分配给一个入口地址。

这个入口地址就称为函数的指针。

可以用一个指针变量指向某函数,然后通过该指针变量调用此函数。

5.1.1用函数指针变量调用函数

1.函数指针的声明

格式:

数据类型(*指针变量名)(函数形参类型标识符列表);

其中的“数据类型”是指函数返回值的类型。

例如:

char(*f1)(char*,char);

int(*f2)(int*,int);

上述语句声明两个指向函数的指针:

f1指向形参类型依次为char*、char,返回值类型为char的函数;f2指向形参类型依次为int*、int,返回值类型为int的函数。

注意

f1、f2是不同类型的指针,因为它们各自所指向的函数的返回值类型,形参个数及各形参的类型不尽相同。

2.为指向函数的指针赋值

函数名是指针常量,其值为该函数在内存中存储区域的首地址。

只能将函数的首地址赋值到指向同类型函数的指针。

函数指针赋值格式为:

函数指针=函数名;

3.函数指针的调用方式为:

(*指针名)(实在参数列表);

5.1.2用函数指针变量调用函数举例

例5.1用函数指针调用求最大值函数,求出a和b中的大者。

函数占有一段内存单元,可用函数指针变量指向其首地址,通过指针变量来访问它所指向的函数。

程序设计如下:

#include

intmax(intx,inty)

{

returnx>y?

x:

y;

}

voidmain()

{

inta,b,c;

int(*p)(int,int);/*声明函数指针*/

p=max;/*函数名代表了函数入口地址*/

scanf("%d,%d",&a,&b);

c=(*p)(a,b);/*调用方式*/

printf("a=%d,b=%d,max=%d\n",a,b,c);

}

注意

(1)int(*p)(int,int);定义p是一个指向函数的指针变量,即所指向的函数返回值为int型,形参依次为int、int类型的函数。

(2)在int(*p)(int,int);(*p)两侧的括弧不可省略,表示p先与*结合,是指针变量,然后再与后面的()结合,表示此函数指针变量所指向的函数返回值是整型。

如果写成“int*p(int,int)”,则由于()优先级高于*,它表示声明了一个函数,只不过这个函数的返回值是指向整型变量的指针。

(3)给函数指针变量赋值时只赋函数名,不准带参数。

如:

p=max;

赋值语句“p=max;”的作用是将函数max的入口地址赋给指针变量p。

和数组名代表数组的起始地址一样,函数名代表函数的入口地址。

函数调用可以通过函数名,也可通过函数指针,本例中的调用形式为c=(*p)(a,b);用函数指针调用的参数与函数调用的参数完全一致,用函数指针变量调用函数时,只需将(*p)代替函数名即可。

(4)对指向函数的指针变量不准作加减运算,如:

p++,p--,p+n都是错误的。

例5.2指向函数的指针简单应用示例。

#include

floatf1(floatx)

{

returnx*x;

}

floatf2(floatx)

{

returnx*x*x;

}

voidmain()

{

float(*p)(float),y;

p=f1;

y=(*p)

(2);

printf("%f\n",y);

p=f2;

y=(*p)

(2);

printf("%f\n",y);

}

其中,语句“p=f1;”将函数f1的首地址赋给p,表达式“(*p)

(2)”的作用是以2为实参调用函数f1,返回值为4。

同样,语句“p=f2;”将改写p的值为函数f2的首地址,表达式“(*p)

(2)”的作用是以2为实参调用函数f2,返回值为8。

思考:

有二个函数定义:

intadd(intx,inty)

{

returnx+y;

}

intsub(intx,inty)

{

returnx+y;

}

在main函数中定义一个函数指针,分别调用函数add、sub,并在main函数中输出结果。

例5.3已知契比雪夫多项式的定义如下:

x (n=1)

2x2-1(n=2)

4x3-3x(n=3)

8x4-8x+1(n=4)

试编写程序,从键盘输入整数n和实数x,并计算多项式的值。

#include

voidmain()

{

floatfn1(float),fn2(float),fn3(float),fn4(float);

float(*fp)(float);

floatx;

intn;

printf("inputx:

");

scanf("%f",&x);

printf("inputn:

");

scanf("%d",&n);

switch(n)

{

case1:

fp=fn1;break;

case2:

fp=fn2;break;

case3:

fp=fn3;break;

case4:

fp=fn4;break;

default:

printf("dataerror!

");

}

printf("result=%f",(*fp)(x));

}

floatfn1(floatx)

{

returnx;

}

floatfn2(floatx)

{

return2*x*x-1;

}

floatfn3(floatx)

{

return4*x*x*x-3*x;

}

floatfn4(floatx)

{

return4*x*x*x*x-8*x*x+1;

}

例5.4设一个函数pp,在调用它的时候,每次实现不同的功能。

输入a和b两个数,第一次调用pp时找出a和b中大者,第二次找出a和b中小者。

#include

intmax(int,int);//函数原型声明

intmin(int,int);//函数原型声明

voidpp(int,int,int(*p)(int,int));//函数原型声明

voidmain()

{

inta,b;

scanf("%d,%d",&a,&b);

printf("max=");

pp(a,b,max);

printf("min=");

pp(a,b,min);

}

intmax(intx,inty)//求x,y中的大者

{

returnx>y?

x:

y;

}

intmin(intx,inty)//求x,y中的小者

{

returnx

x:

y;

}

voidpp(intx,inty,int(*p)(int,int))

{

intresult;

result=(*p)(x,y);

printf("%d\n",result);

}

运行情况如下:

enteraandb:

2,6

max=6

min=2

注意:

程序中使用的函数指针fp,将随着输入条件n的不同而指向不同的函数,从而达到在不同条件下调用不同函数的目的。

5.2返回值为指针的函数

函数被调用后,可以由函数中的return语句返回一个值到主调函数中。

函数的返回值可以是整型值、字符值、实型值等,也可以是返回指针型的数据,即地址。

返回值为指针的函数,与以前的函数概念类似,只是返回的值的类型是指针类型而已,此类函数通常称为指针函数。

指针函数定义形式:

类型名*函数名(形参表定义)

{

函数体

}

如:

int*func(intx,inty);

其中,func是函数名,其返回值类型是“指向整型的指针”,也即函数值是一个指针,指向一个整型变量,函数的形参为intx和inty。

5.2.1指针函数应用举例

例5.5由键盘输入1~12自然数,再调用指针函数输出英文名被调用程序中应定义指针函数。

#include

char*month_name(intn)

{staticchar*name[13]={

"ILLEGAL",

"JANUARY",

"FEBRUARY",

"MARCH",

"APRIL",

"MAY",

"JUNE",

"JULY",

"AUGUST",

"SEPTEMBER",

"OCTOBET",

"NOVEMBER",

"DECEMBER"};

return((n<1||n>12)?

name[0]:

name[n]);

}

voidmain()

{char*month_name(int);/*说明一个指针函数,由于函数定义在先,此语句可省略*/

intn;

scanf("%d",&n);

printf("%s",month_name(n));

}

例5.6编一函数,在一组字符串中找出按字典序最大的字符串。

#include

#include

char*find_max(char*str[],intn)//声明函数返回值为指向字符的指针

{

inti;

char*p;

p=str[0];//假设str[0]及p所指向的字符串按字典序最大

for(i=1;i

if(strcmp(str[i],p)>0)

p=str[i];//使p指向按字典序最大的字符串

returnp;//返回指针值

}

voidmain()

{

char*a[5]={"ABc","abc","Abc","abcd","abca"};

printf("%s\n",find_max(a,5));

}

运行结果:

abcd

分析:

char*find_max(char*str[],intn)声明函数返回值为一个指向字符或字符串的指针。

形式参数char*str[]表示它是一个指针数组,指针数组中的每个元素相当于一个指针变量,分别指向不同字符串的首地址。

strcmp(str[i],p)表示str[i]和p指向的两个字符串从左至右逐个字符相比较(按ASCII码值大小比较),直到出现不同的字符或遇到‘\0’为止。

如果全部字符相同,则认为相等(返回0值);若出现不同的字符,则以第一个不相同的字符比较结果为准(返回其ASCII码的差值)。

例5.7有若干学生的成绩(每个学生四门课程),要求用户在输入学生序号(假设从0号开始)后,能输出该学生的全部成绩。

#include

float*search(float(*pointer)[4],intn);/*函数原型声明*/

voidmain()

{

 staticfloatscore[][4]={{65,70,80,90},{76,89,67,88},{84,78,90,76}};

 float*p;

 inti,num;

 printf("Enterthenumberofstudent:

");

 scanf("%d",&num);

 printf("ThescoresofNo.%dare:

\n",num);

 p=search(score,m);/*在score数组中查询m号学生的成绩*/

/*p指向m号学生第0门课程*/

 for(i=0;i<4;i++)

   printf("%5.2f\t",*(p+i));

}

float*search(float(*pointer)[4],intn)

{

 float*pp;/*pp是指向实数的指针,pointer是指向数组的指针*/

 pp=*(pointer+n);/*pp=(float*)(pointer+n)*/

 returnpp;

}

运行结果如下:

Enterthenumberofstudent:

2

ThescoresofNo.2are:

84.0078.0090.0076.00

注意

float(*pointer)[4],其中的pointer是一个指向一维数组的指针变量,数组元素个数为4(四门课程),即pointer指向一个学生的四门成绩。

main()函数调用search函数,将score数组的首地址传给pointer(注意score是一个二维数组名,所以score也是一个指向行的指针,而不是指向列元素的指针)。

输入学生序号后,使pp指向该学生第0门课程,赋值给p。

*(p+i)表示此学生第i门课程的成绩。

例5.8编一函数,在字符串中找出一个子串的首地址。

#include

#include

char*find_str(char*s1,char*s2)

{

inti,j,ls2;

ls2=strlen(s2);//求子串s2的长度ls2

for(i=0;i

{

for(j=0;j

if(s1[j+i]!

=s2[j])

break;

if(j==ls2)

returns1+i;

}/*查找s1+i是否为所求的地址值。

具体思想为:

从地址s1+i起的ls2个

字符与从地址s2起的ls2个字符均对应相同,则s1+i是所求地址。

*/

returnNULL;//NULL为空指针

}

voidmain()

{

char*src="Windows98Office97Microsoft",*dest="Office97",*pp;

pp=find_str(src,dest);//返回的地址值送给指针变量pp

if(pp!

=NULL)

printf("%s\n",pp);

else

printf("notfind:

%s\n",dest);

}

运行结果为:

Office97Microsoft

注意函数*find_str返回字符串s2在s1中第一次出现的首地址,当查找不到时返回空指针值NULL。

5.2.2指针函数和函数指针比较

指针函数和函数指针这两个概念都是简称。

它们的区别如表5.1所示。

表5.1函数指针和指针函数的区别

函数指针

指针函数

含义:

指向函数的入口地址的指针

含义:

调用函数后返回值为指针

定义形式:

类型(*p)(形式参数表)

定义形式:

类型*p(形式参数表)

本质:

指针

本质:

函数

5.3命令行参数

5.3.1命令行参数的概念

所谓“命令行参数”,一般是在DOS环境下所输入的命令及其参数。

执行文件的形式为:

命令名参数1参数2...参数n(回车)。

命令名和各参数之间用空格分隔。

例如,若有一命令文件名为disp,现要将两个字符串“Zhejiang”,“Hangzhou”作为参数传送给main函数。

可以写成以下形式:

dispZhejiangHangzhou

带参数的命令行文件的编辑步骤:

首先编辑一个名为disp.c(或disp.cpp)的文件,然后将之经过编译、连接后产生disp.exe文件,最后在Dos命令提示符下输入带参数的命令然后回车即可。

5.3.2命令行参数的表示方法

在编辑C语言源程序时,main()函数应带有两个参数,形式为:

voidmain(intargc,char*argv[])

{

……

}

注意

(1)形参argc是命令行中参数的个数,可执行文件名本身也算一个,以空格分隔。

(2)形参argv是一个字符指针数组,argv是一个数组名,元素个数为形参argc的值,其元素为指向命令行字符串的指针,指针数组argv[argc-1]分别指向命令行各参数的首地址。

5.3.3命令行参数使用举例

例5.9编一程序,显示命令行上的所有参数(不包括命令名),源程序名为echo.c。

#include

voidmain(intargc,char*argv[])

{

inti;

i=0;

while(argc>1)

{

++i;

printf("%s\n",argv[i]);

--argc;

}

}

编译连接后生成应用程序文件echo.exe,进入DOS环境,在命令行输入:

disp Zhejiang Hangzhou

运行结果为:

Zhejiang

Hangzhou

程序运行时,系统自动作如下赋值:

命令行参数的个数(含命令)3赋给argc,因为输入的参数为3个,分别为:

dispzhejianghangzhou。

argv[0]指向字符串"disp"的首地址;argv[1]指向字符串"Zhejiang"的首地址;argv[2]指向字符串"Hangzhou"的首地址。

思考:

如文件名前有路径,它们都保存在argv[0]中,请调试当把++i放在printf语句后,程序的运行情况如何?

例5.10用一程序实现文件的加密和解密。

约定:

c程序取名为lock.c,程序的可执行文件名为lock.exe,其用法为:

lock+|-<被处理的文件名>,其中“+”为加密,“-”为解密。

#include

voidmain(intargc,char*argv[])

{

charc;

if(argc!

=3)printf("参数个数不对!

\n");

else

{c=*argv[1];/*截取第二个实参字符串的第一个字符*/

switch(c)

{case'+':

/*执行加密*/

{/*加密程序段*/

printf("执行加密程序段。

\n");

}

break;

case'-':

/*执行解密*/

{/*解密程序段*/

printf("执行解密程序段。

\n");

}

break;

default:

printf("第二个参数错误!

\n");

}

}

}

注意

(1)形参argc的值为3,因为有三个参数”lock”、”+|-“、被处理的文件名。

(2)元素argv[0]指向第1个实参字符串“lock”,元素argv[1]指向第2个实参字符串“+|-”,元素argv[2]指向第3个实参字符串“被处理的文件名”。

(3)main函数中的形参不一定命名为argc和argv,可以是任意的名字,只是人们习惯用argc,argv而已。

习题

1.输入3个整数,按从小到大的顺序输出(用函数指针调用实现)。

2.输入3个字符串,按从小到大的顺序输出(用函数指针调用实现)。

3.用函数指针来实现:

 

写一个程序,输入x的值,输出相应的结果。

4.从键盘输入10名学生的成绩,显示其中的最高分、最低分及平均成绩(要求用指针来编写程序)。

5.编制函数,在字符串数组中查找与另一个字符串相等的字符串,函数的返回值为字符串的地址或NULL值(当找不到时)。

6.以下程序输出的结果是()。

#include

intfuna(inta,intb)

{

returna+b;

}

intfunb(inta,intb)

{

returna-b;

}

intsub(int(*t)(int,int),intx,inty)

{

return((*t)(x,y));

}

voidmain()

{

intx,(*p)(int,int);

p=funa;

x=sub(p,9,3);

x+=sub(funb,8,3);

printf("%d\n",x);

}

7.阅读下面程序。

#include

voidmain(inta,char**ar)

{

a--;

printf("%d",a);

if(a==0)exit(0);

main(a,ar);

}

如文件名为pro.c编译后在命令行输入C:

\>proaaaaaabbbbbccccddd,写出程序运行的结果。

8.编一程序,输入星期的序号0~6,输出中文的星期名。

9.编写一个带命令行参数的程序prog.c。

当运行progfilename时将文本文件filename按原样在标准输出(终端)上输出;当运行prog-nfilename时将文本文件按原样在标准输出(终端)上输出,并在各行开头显示当前行行号(从1:

开始,如1:

XXXXXXXX);其他运行方式均显示出错信息。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 教学研究 > 教学计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1