讲授提纲第七章函数1.docx
《讲授提纲第七章函数1.docx》由会员分享,可在线阅读,更多相关《讲授提纲第七章函数1.docx(24页珍藏版)》请在冰豆网上搜索。
讲授提纲第七章函数1
第七章函数
§7.1函数
一、函数及其定义
1.函数定义的一般形式(p114)
返回值类型函数名(形式参数表)
形式参数类型描述;
{(函数内部的)变量定义与有关说明语句部分
函数的可执行语句序列
}
[函数头]、[函数体]
[例7-1]求两个整数的最大值的函数定义。
(或p115)
intmax(x,y)/*定义了有两个形式参数x,y且返回int值的函数max*/
intx,y;/*说明了形参x,y均为int型*/
{intz;/*定义了函数内部使用的变量z*/
z=x>y?
x:
y;/*将x,y中较大值送入z*/
return(z);/*将z做为函数返回值,并使函数返回到被调程序(父程序)*/
}
2.关于函数返回值类型
①允许C基本数据类型和任何有意义的用户自定义类型。
②如果省略返回值类型则隐含返回int类型。
③没有返回值的函数。
3.关于形式参数及形参说明
函数参数是为在函数和父程序间传递数据而设置的。
各参数在被父程序调用时才从父程序处获得真正的值,因而在定义函数时参数是“形式上”的值称形式参数,简称形参。
函数被调用时形参从父程序处获得的真实值称实际参数,简称实参。
实参传递给形参的过程称实形结合,加上函数处理结果返回到父程序的过程统称函数的参数传递,函数参数传递是函数技术中的重要内容。
①形参之间以“,”分隔。
②形参是局部性变量,只在函数内有效。
③两种形参说明效果相同。
④无参函数的()不能省略,以示位于()前面的标识符是函数名。
charGetCHAR()
{intk;
k=getchar();
if(k>=’a’&&k<=’z’)returnk-32;
elsereturn0;
}
4.关于函数体与函数返回。
①函数体是实现函数功能的程序片断,函数体的设计与通常的编程在编程思想和技术上没有任何差别。
②返回语句return使函数退出运行返回到父程序继续执行,同时将函数值带回父程序。
return语句共有4种形式。
return(表达式);
return表达式;
return;
无return语句。
③return语句可以安排在函数体任何位置,也可安排多条return语句。
5.关于多个函数的位置关系:
并列关系而非嵌套关系。
6.关于主函数main()
①程序中有且仅有一个main()函数,程序从main()函数开始执行。
②main()函数也有形参,参数由操作系统给出,即“命令行参数”。
二、函数调用
1.函数调用的一般形式(p115)
函数名(实参表)
2.函数调用与函数执行过程(p116)
(1)为函数的形参分配内存空间;
(2)计算实参表达式的值,并将实参表达式的值赋给对应的形参;
(3)为函数的局部变量分配内存空间;
(4)执行函数体内的语句片段;
(5)函数体执行完毕或执行了函数体内的return语句(若return语句带表达式,则计算出该表达式的值,并以此值作为函数的返回值)后,释放为这次函数调用分配的全部内存空间;
(6)将函数及返回值返回到父程序的函数调用处,继续执行父程序。
[例7-2]如下给出了程序中调用max函数的全过程说明。
#include
floatmax(floatx,floaty)
{floatz;
z=x>y?
x:
y;
returnz;
}
main()
{floata=19.8,b=-98.8,c;
c=max(a,b);
printf("MAX(a,b)=%f\n",c);
}
三、函数的参数传递方式
1.传值方式
[例7-3]返回阶乘的函数及其调用,函数调用时参数采用传值方式。
#include
floatfac(intn)
{intf=1.0;
while(n>=1){f=f*n;--n;}
return(f);
}
main(){
intk=6;
printf("%8.1f\n",fac(k));
}
2.传地址方式
[例7-4]返回阶乘的函数及其调用,函数调用时采用传地址方式。
#include
floatfac(int*n)
{intf=1.0;
while(*n>=1){f=f*(*n);--(*n);}
return(f);
}
main(){
intk=6;
printf("%8.1f\n",fac(&k));
}
[要点]传值方式中函数对形参的处理是在函数内部变量中进行的,形参在函数内的改变不会使与之结合的实参变量发生变化,称变量直接操作。
传地址方式中函数对形参的处理是在形参的所指对象单元即与形参结合的实参变量上进行的,形参在函数中的改变实质是实参变量的改变,称变量间接操作。
四、函数的类型说明
[函数类型说明有三种方法]
①将函数定义放在函数调用之前。
②在函数调用之前的任何位置安排一条类型说明语句,形式为:
返回值类型函数名();
③在调用函数的父程序内的变量定义处,顺便说明函数返回值类型。
[规定]如果函数返回int,char类型可以不进行函数类型说明。
§7.2指针与函数的参数传递
一、向函数中传递变量的指针
[例7-5]试图用swap()函数将两实参变量的值交换。
void_swap(intx,inty)
{intz;
z=x;x=y;y=z;
}
main()
{inta=10,b=20;
_swap(a,b);printf("a=%d,b=%d\n",a,b);
}
[结论]传值方式不能将“形参的值”“传回”父程序中的实参。
[例7-6]用swap函数将两实参变量的值交换。
#include
voidswap(int*x,int*y)
{intz;
z=*x;*x=*y;*y=z;
}
main()
{inta=10,b=20;
swap(&a,&b);printf("a=%d,b=%d\n",a,b);
}
[结论]传地址方式可以将“形参的值”“传回”父程序中的实参。
二、通过指针向函数中传递一维数组
[方法]定义一个指针形参,函数调用时将实参数组的首地址赋值给指针形参,从而达到“对形参数组的处理是在实参数组上进行的”的效果。
[例7-7]求整型数组各元素之和。
intadd(int*x,intn)
{intsum,i;
for(sum=0,i=0;ireturnsum;
}
main(){
intarr[4]={1,3,4,5},s;
s=add(arr,4);printf("%d\n",s);
}
数组的元素描述形式也可采用下标法或元素指针法。
for(sum=0,i=0;ifor(sum=0,i=0;i20001arr[0]
20023arr[1]
20044arr[2]
20065arr[3]
20082000
x
20104n
2012sum
2014i
三、通过指针向函数中传递字符串
[方法]定义一个指向字符(串)的指针变量作形参,调用时将字符串的首地址与形参变量结合使形参指针指向了实参字符串。
这样在函数中对字符串的处理实质是在实参字符串上进行的。
[例7-8]将字符串中所有小写字母改成大写字母进行输出,小写转大写工作由自定义函数StrToUpr()完成。
voidStrToUpr(char*s)
{while(*s!
='\0')
{if(*s>='a'&&*s<='z')*s=*s-('a'-'A');
++s;}
}
main(){
charstr[40];
gets(str);StrToUpr(str);puts(str);
}
[例7-9]用函数实现字符串的复制。
#include
voidStrCopy(char*from,char*to)
{while(*from!
='\0')*to++=*from++;
*to='\0';
}
main(){
charstr1[40],str2[40];
gets(str1);StrCopy(str1,str2);puts(str2);
}
四、通过指针向函数中传递二维数组
[方法]传二维数组首地址以使函数中的形参指针指向二维数组,形成“对形参数组处理实质上是在实参二维数组上进行”的效果。
[例7-10]求二维数组中元素的最大值。
[程序1]
intArr2Max(inta[][3],intm)/*intArr2Max(int(*a)[3],intm)*/
{intmax=-32768,i,j;
for(i=0;ifor(j=0;j<3;j++)if(a[i][j]>max)max=a[i][j];
returnmax;
}
main(){
intarr[2][3]={{1,4,7,},{4,18,6}};
printf("MAX=%d\n",Arr2Max(arr,2));
}
[程序2]形参描述为指向一维数组的指针,函数描述改为intArr2Max(int(*a)[3],intm)。
[程序3]形参描述为指向一维数组的指针,元素的处理采用游动的元素指针法。
#include
intArr2Max(int(*a)[3],intm)
{intmax=-32768,j;
int(*p)[3];
for(p=a;pfor(j=0;j<3;j++)
if((*p)[j]>max)max=p[0][j];
returnmax;
}
main(){
intarr[2][3]={{1,4,7,},{4,18,6}};
printf("MAX=%d\n",Arr2Max(arr,2));
}
五、返回指针的函数
[例7-11]某字符数组中存有两个字符串以‘\0’做为串结束符,即字符数组中先存一个字符串以‘\0’结束,从‘\0’的下一字符位置又存有一个字符串以‘\0’结束,如下程序可以打印出第2个字符串。
#include
char*SecondStr(char*s)
{while(*s!
='\0')s++;
return(s+1);
}
main()
{charstr[40]="abcdef\0ABCDEFGH",*str2;
str2=SecondStr(str);puts(str2);
}
§7.3函数程序设计
[要点1]必须了解开发环境所能提供的系统函数。
[要点2]如何设计给定功能的函数,设计必须严格按如下步骤进行。
(1)清楚知道函数所要完成的功能。
(2)入口参量设计。
要说明参数个数,传递方式,形参名,参数含义。
(3)出口参量设计。
要说明出口参量个数,参量传递方式,参量含义。
(4)写出正确的函数头描述。
(5)函数体设计。
[要点3]如何划分函数。
一、给定功能设计函数
[例7-12]设计函数计算n!
[设计过程]
(1)明确函数功能:
求一个正整数的阶乘。
(2)入口参量设计。
(3)出口参量设计。
(4)函数头描述:
floatfac(intn)
(5)函数体设计。
floatfac(intn)
{inti;
floatp;
for(p=1,i=1;i<=n;i++)p*=i;
returnp;
}
[例7-13]设计函数求一维数组中的最大值和最小值。
[设计过程]
入口参量。
出口参量。
函数头描述。
voidMaxMin(a,n,max,min)
floata[],*max,*min;/或float*a,*max,*min;*/
intn;
函数体设计。
[函数及调用程序]
voidMaxMin(a,n,max,min)
floata[],*max,*min;
intn;
{inti;
*max=*min=a[0];
for(i=1;iif(a[i]>*max)*max=a[i];
if(a[i]<*min)*min=a[i];
}
}
main(){
floata[5]={1,23,45,-9,7},c,d;
MaxMin(a,5,&c,&d);printf("MAX=%6.1fMIN=%6.1f\n",c,d);
}
[例7-14]编写函数将3个整数排序并求和。
[设计过程]
参量设计。
函数头描述。
intSortSum(int*x1,int*x2,int*x3)
[函数设计结果]
intSortSum(int*x1,int*x2,int*x3)
{intt;
if(*x1>*x2){t=*x1;*x1=*x2;*x2=t;}
if(*x1>*x3){t=*x1;*x1=*x3;*x3=t;}
if(*x2>*x3){t=*x2;*x2=*x3;*x3=t;}
return(*x1+*x2+*x3);
}
_二、借助函数编写程序
[例7-15]计算S=Cn1+Cn3+…+Cnk(n由键盘输入,k为不大于n的最大整数)。
[设计过程]
程序结构为:
{输入n}
{累加器s清0}
for(i=1;i<=n;i+=2){
{计算Cni=>p}Cni=n!
/(i!
*(n-i)!
)
{s+=p}
}
{输出s}
[设计函数]floatfac(intn);
#include"stdio.h"
floatfac(intn)
{inti;
floatp;
for(p=1,i=1;i<=n;i++)p*=i;
returnp;
}
main(){
intn,i,sum;
scanf("%d",&n);
for(sum=0,i=1;i<=n;i+=2)sum+=fac(n)/fac(i)/fac(n-i);
printf("%d\n",sum);
}
[例7-16]对M行N列矩阵的每行分别求和,将最小的和数输出。
[思考过程]
函数Sum():
求和及存入一维数组b[M]。
函数Min():
求数组最小值。
[Sum()函数的设计]
入口参量:
一个M行N列的二维数组,描述为intx[][N]。
出口参量:
一个M个元素的一维数组,描述为inty[]或int*y。
函数头描述:
voidSum(intx[][N],inty[])
函数:
voidSum(intx[][N],inty[])
{inti,j;
for(i=0;iy[i]=0;for(j=0;j}
}
[Min()函数的设计]
入口参量:
一个M个元素的一维数组,描述为intx[]或int*x。
出口参量:
以函数返回值形式返回的x[]数组最大值。
函数头描述:
intMin(int*x)
函数:
intMin(int*x)
{inti,min;
min=x[0];
for(i=1;iif(x[i]returnmin;
}
[主函数main()]
#include
#defineM3
#defineN3
main(){
inta[M][N]={{1,2,3},{1,2,2},{3,4,5}};
intb[M];
Sum(a,b);printf("Min=%d\n",Min(b));
}
[例7-36]求一组分数之和S=,以输入了0(分子为0或分母为0)结束输入及求和过程。
#include
intgcd(intm,intn)/*用欧氏“辗转相除法”求m,n的最大公约数*/
{/*函数体请参见[例4-29]*/}
main(){
ints1,s2,a,b,k;
s1=0;s2=1;
scanf("%d%d",&a,&b);
while(a!
=0&&b!
=0){
k=gcd(a,b);a/=k;b/=k;
s1=s1*b+s2*a;s2=s2*b;
k=gcd(s1,s2);s1/=k;s2/=k;
scanf("%d%d",&a,&b);
}
printf("%d/%d=%7.2f\n",s1,s2,(float)s1/s2);
}
§7.4函数嵌套调用与递归调用
一、函数的嵌套调用
[例7-22]用函数实现起泡排序。
voidswap(int*x,int*y)
{intt;
t=*x;*x=*y;*y=t;
}
voidBubbleSort(intx[],intn)
{inti,j;
for(i=0;ifor(j=0;jif(x[j]>x[j+1])swap(&x[j],&x[j+1]);
}
main(){
inta[100],n,i;
printf("inputn=");scanf("%d",&n);
for(i=0;iBubbleSort(a,n);
for(i=0;i}
二、函数的递归调用
[递归问题特征]
(1)细化出的子问题与原问题性质相同但比原问题简单。
(2)问题有“不含递归的”最简解。
[例7-23]用递归方法求阶乘。
#include
longfac(intn)
{if(n==1)return1;
elsereturnn*fac(n-1);
}
main(){
printf("%ld\n",fac(4));
}
[递归函数设计要点]
(1)递归函数中含有从原问题到子问题转换的递归调用语句。
(2)递归函数有引起问题越来越简单并反映原问题与子问题性质的形参。
(3)递归函数中必须有不含递归的最简情况处理语句。
[例7-18]菲波拉奇数列第一项是0,第二项是1,以后每一项是前2项的和。
用递归函数求菲波拉奇数到的第n项。
intfib(intn)
{if(n==1)return0;
if(n==2)return1;
returnfib(n-1)+fib(n-2);
}
main(){
intk=8;
printf("Fib(%d)=%d\n",k,fib(k));
}
[例7-19]用递归函数实现辗转相除法求最大公约数。
intgcd(intm,intn)
{if(n==0)returnm;
elsereturngcd(n,m%n);
}
main(){
inta,b;
scanf("%d%d",&a,&b);printf("gcd(%d,%d)=%d\n",a,b,gcd(a,b));
}
§7.5变量的存储类型
一、变量的存储性质
[变量的数据性质]
[变量的存储性质]
[变量存储类型]
auto自动变量
static静态变量
extern外部变量
register寄存器变量
[变量定义的完整格式](变量存储类型标识符)变量数据类型标识符变量表;
二、自动变量(局部变量)
三、外部变量(全局变量)
四、静态变量
[内部静态变量与局部变量的区别]
[外部静态变量与全局变量的区别]
五、寄存器型变量
六、再论变量初始化
1.静态变量的初始化
2.动态变量的初始化
[例7-20]阅读下列程序并回答问题。
(1)程序中定义的各个变量的存储类型是什么?
分配在什么数据区?
生存期、作用域是什么?
(2)写出程序运行结果。
#include
intn=1;
main(){
staticintx=5;
inty;
y=n;
A:
printf("MAIN:
x=%2dy=%2dn=%2d\n",x,y,n);
B:
func();
C:
printf("MAIN:
x=%2dy=%2dn=%2d\n",x,y,n);
D:
func();
}
func()
{staticintx=4;
inty=10;
x+=2;n+=10;y+=n;
E:
printf("FUNC:
x=%2dy=%2dn=%2d\n",x,y,n);
}
M