c笔记之函数.docx
《c笔记之函数.docx》由会员分享,可在线阅读,更多相关《c笔记之函数.docx(33页珍藏版)》请在冰豆网上搜索。
c笔记之函数
函数
一个C程序可由一个主函数和若干个子函数组成。
每个子函数完成一个特定的功能(功能相对独立的程序段)。
用户角度分类
标准函数,即库函数
自定义函数
函数形式分类
无参数函数
有参数函数
函数定义一般形式
类型说明函数名([形式参数说明])
{
函数体
}
形式参数说明
类型说明变量名[,类型说明变量名。
。
。
]
1.一个C程序可以分为若干个函数
2.每个程序有且只能有一个主函数(main),其他函数都是“子函数”
3.子函数可以相互调用,但主函数不能被调用
4.一个C源程序由一个或多个文件构成,一个源程序文件是一个编译单位
各函数间的信息的往来是由参数传递和返回语句实现的。
函数的参数:
调用时,实参值传给形参;
仅与位置有关,与名字无关;
注意二者的个数、类型。
形式参数和实际参数
1.定义参数时,必须说明形参的类型。
形参只能是变量或数组。
2.函被调用前,形参不占用内存;函数调用结束后,形参所占有的内存也将被回收。
3.实参可以是常量、变量或表达式。
4.实参与形参的类型必须一致。
字符型和整型可以互相匹配。
5.C语言中实参对形参的数据传递是“值传递”,即单向传递。
它仅由参数的对应位置确定,与名字无关。
实参形参传递方式
常量、变量、表达式、变量传递(单向)
数组元素
数组名数组传递组首地址(“双向”)--〉共享同一个存储空间
eg1:
#include
intsum(inta,intb)
{
a=a+b;
b=a+b;//无效语句
returna;
}
main()
{
inta=1,b=3,c;
c=sum(a,b);//a,b值不变
printf("Sumof%d,%dis%d\n",a,b,c);
}
eg2:
#include
intmax(intx,inty)
{
intz;
z=(x>y)?
x:
y;
returnz;
}
main()
{
inta,b,c;
scanf("%d%d",&a,&b);//输入:
空格或换行隔开
c=max(a,b);
printf("Maxis%d\n",c);
}
eg3:
函数返回值
#include
intmax(intx,inty)
{
//intz;
//z=(x>y)?
x:
y;
//returnz;
//if(x>y)
//returnx;
//else
//returny;
return(x>y)?
x:
y;
}
main()
{
inta,b,c;
scanf("%d%d",&a,&b);//输入:
空格或换行隔开
c=max(a,b);
printf("Maxis%d\n",c);
}
eg4:
按从右往左的顺序,计算实参各个表达式的值。
#include
intf(inta,intb)
{
intc;
printf("a=%d,c=%d\t",a,b);
if(a>b)c=1;
elseif(a==b)c=0;
elsec=-1;
returnc;
}
intmain()
{
inti=2,p;
p=f(i,i);//a=2,c=20
printf("%d\n",p);
i=2;
p=f(++i,i);//a=3,c=30
printf("%d\n",p);
i=2;
p=f(i++,i);//a=2,c=3-1
printf("%d\n",p);
i=2;
p=f(i,++i);//a=3,c=30
printf("%d\n",p);
i=2;
p=f(i,i++);//a=3,c=21
printf("%d\n",p);
}
函数的调用
1.先定义,再使用
#include
floatf(floatx)
{
return2*x*x+3*x+1;
}
main()
{
floatx;
scanf("%f",&x);
printf("y=%f\n",f(x));
}
2.如果被调函数的定义在主调函数之前,可以先给出原形说明。
原形说明
类型说明函数名(参数类型[变量名],
参数类型,...);变量名可写可不写
#include
floatf(float);//原形说明
main()
{
floatx;
scanf("%f",&x);
printf("y=%f\n",f(x));
}
floatf(floatx)
{
return2*x*x+3*x+1;
}
3.调用库函数
#include
#include
floatf(float);
main()
{
floatx,y;
scanf("%f",&x);
y=sin(x*3.1415926/180);
printf("sin(%f*3.1415926/180)=%f\n",x,y);
}
函数的嵌套调用
一个函数又调用另一个函数
注意点:
返回到主调函数的调用处
参数传递是单向的
eg:
#include
voidb(intx);
voida(intx)
{
x+=11;
b(x);
printf("a_sub:
%d\n",x);
}
voidb(intx)
{
x+=22;
printf("b_sub:
%d\n",x);
}
main()
{
intx=0;
a(x);
printf("main:
%d\n",x);
}
/*
b_sub:
33
a_sub:
11
main:
0
--------------------------------
*/
eg1:
用弦截法求方程的根。
x*x*x-5*x*x+16*x-80=0
#include
#include
floatf(floatx)
{
return((x-5)*x+16)*x-80;
}
floatxpoint(floatx1,floatx2)//求弦截点x的坐标
{
return(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1));
}
floatroot(floatx1,floatx2)//求区间(x1,x2)上的根
{
inti;
floatx,y,y1;
y1=f(x1);
do
{
x=xpoint(x1,x2);
y=f(x);
if(y*y1>0)
{
y1=y;
x1=x;
}
else
{
x2=x;
}
}while(fabs(y)>0.00001);
returnx;
}
main()
{
floatx,x1,x2,y1,y2;
do
{
printf("inputx1,x2:
");
scanf("%f%f",&x1,&x2);
y1=f(x1);
y2=f(x2);
}while(y1*y2>0);//是否存在根
x=root(x1,x2);
printf("arootis%f\n",x);
}
eg2:
mn!
编写求C=------------的程序。
nm!
(n-m)!
分析:
重复三次求阶乘的运算,只是每次的值不同。
#include
floatfac(intk)//求阶乘
{
floatt=1;
inti;
for(i=2;i<=k;i++)
t*=i;
returnt;
}
main()
{
floatc;
intm,n;
printf("inputm,n:
");
scanf("%d%d",&m,&n);
c=fac(n)/(fac(m)*fac(n-m));
printf("%d!
/(%d!
*(%d-%d)!
)=%.0f\n",n,m,n,m,c);
}
/*
inputm,n:
58
8!
/(5!
*(8-5)!
)=56
--------------------------------
*/
函数的递归调用
是指在调用一个函数时又直接或间接地调用了函数本身。
直接递归调用
eg:
intf(intx)
{
inty,z;
...注意:
这两个递归都无法结束。
z=f(y);因此应含有某条件控制
...递归调用结束。
}
间接递归调用
eg:
intf1(intx)
{
inty,z;
...
z=f2(y);
...
}
intf2(intt)
{
intu,v;
...
v=f1(u);
...
}
eg1:
有5个人坐在一起,问第5个人多少岁?
答,比第4个人大2岁。
第4个人说他比
第3个人大2岁,第3个人比第2个人大2岁,第3个人比第2个人大2岁,第2个人
比第1个人大2岁,问第1个人时回答是10岁。
那么第5个人到底多大?
#include
intage(intn)
{
intc;
if(n==1)c=10;//递归结束条件
elsec=age(n-1)+2;//相当于数据结构“栈”
returnc;
}
main()
{
printf("%d\n",age(5));
}
eg2:
求阶乘n!
(n>0)
①循环法
floatfac(intn)
{
floatf=1;
if(n>1)
for(i=2;i<=n;i++)
f*=i;
elsef=-1;
returnf;
}
②递归法
递归公式:
n!
=1(n=0,1)
n*(n-1)!
(n>1)
#include
floatfac(intn)
{
floatf;
if(n>1)f=fac(n-1)*n;
elseif(n==0||n==1)f=1;
elsef=-1;
returnf;
}
main()
{
intn;
floaty;
printf("inputaintegernumber:
");
scanf("%d",&n);
y=fac(n);
if(y<0)
printf("error:
%d<0\n",n);
else
printf("%d!
=%.0f",n,y);
}
数组作为函数的参数
1.数组元素做函数实参
eg:
求5个任意整数中的最大数。
#include
intmax(intx,inty)
{
return(x>y?
x:
y);
}
main()
{
inta[5],i,m;
printf("enter5integers:
\n");
for(i=0;i<5;i++)
scanf("%d",&a[i]);
m=a[0];
for(i=0;i<5;i++)
m=max(m,a[i]);
printf("maxis%d\n",m);
}
2.一维数组作为函数的参数
函数的形参是数组,对应的实参必须是数组名。
1.实参数组与形参数组的类型必须一致。
2.用数组名做参数时,传递的是数组的首地址。
因此形参数组也可以不指定大小。
但需另设一个参数,传递数组元素的个数。
3.数组做函数参数时,形参数组和实参数组共享同一内存单元。
如果形参数组的元素的值被修改,实参数组的元素的值也就被改变了。
eg1:
求5个任意整数中的最大数。
#include
#defineN5
intmax(intx[N])
{
inti,m;
m=x[0];
for(i=0;iif(mm=x[i];
returnm;
}
main()
{
inta[N],i;
printf("enter5integers:
\n");
for(i=0;iscanf("%d",&a[i]);
printf("maxis%d\n",max(a));
}
形参数组不指定大小,另设一个参数传递数组元素的个数。
#include
#defineN5
intmax(intx[],intn)
{
inti,m;
m=x[0];
for(i=0;iif(mm=x[i];
returnm;
}
main()
{
inta[N],i;
printf("enter5integers:
\n");
for(i=0;iscanf("%d",&a[i]);
printf("maxis%d\n",max(a,N));
}
eg2:
用比较法排序(从大到小)
#include
#defineN5
voidsort(intx[],intn)
{
inti,j,t;
for(i=0;ifor(j=i+1;jif(x[i]{
t=x[i];
x[i]=x[j];
x[j]=t;
}
}
main()
{
inta[N],i;
printf("enter5integers:
\n");
for(i=0;iscanf("%d",&a[i]);
sort(a,N);//a是数组名,传递数组的首地址
printf("enterthearray:
\n");
for(i=0;iprintf("%d",a[i]);
}
3.多维数组作为函数的参数
如果形参是多维数组,可以省略第一维的大小,但不能省略其他维的大小。
eg:
有一个3×4的矩阵,求最大元素的值。
#include
intmax(intx[][4])
{
inti,j,m;
m=x[0][0];
for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(mm=x[i][j];
returnm;
}
main()
{
staticinta[3][4]={{1,3,5,7},{2,4,6,8},{15,13,17,5}};
printf("maxis%d\n",max(a));
}
局部变量与全局变量
局部变量(多用)
在函数内定义的变量;形参也是局部变量;作用域为本函数。
局部变量只在自己的范围内有效。
如果局部变量的有效范围有重叠,则有效范围小的优先。
1.在一个函数内部定义的变量
2.函数的形式参数
3.在某个复合语句中定义的变量
全局变量/外部变量(少用)
在函数之外定义的变量(外部/全程变量)是全局变量
有效范围:
从定义变量的位置开始到源文件结束
1.利用全局变量可以在传递数据
利用全局变量可以减少函数的参数。
2.应尽量少使用全局变量。
3.如果全局变量与局部变量同名,则全局变量优先。
eg:
有5个学生的学习成绩,求平均分、最高分和最低分。
分析:
用一个函数返回三个数据,除了用函数值外,可以借助于全局变量。
#include
#defineN5
floatmax=0,min=0;
floataverage(floatscore[],intn)
{
inti;
floatsum=score[0];
max=min=score[0];
for(i=1;i{
sum=sum+score[i];
if(maxif(min>score[i])min=score[i];
}
returnsum/n;
}
main()
{
floatavg,score[N];
inti;
for(i=0;iscanf("%f",&score[i]);
avg=average(score,N);
printf("max:
%f,min:
%f,average:
%f\n",max,min,avg);
}
变量的存储类别
静态存储方式:
编译时分配空间,在程序运行期间占有固定存储空间(static变量、全局变量)
动态存储方式:
程序执行时动态分配存储空间(auto变量、register变量、形参)
若没有指定存储方式,默认动态存储方式auto变量。
eg:
#include
intsub()
{
staticinty=1;//保留值
y++;
returny;
}
main()
{
intj;
for(j=1;j<=10;j++)
printf("%d",sub());
printf("\n");
}
/*
234567891011
--------------------------------
*/
1.变量的动态存储和静态存储
变量的划分
⑴全局变量与局部变量:
按变量的作用域
局部变量:
1.自动变量
2.静态局部变量
3.寄存器变量
4.形式参数
全局变量
⑵静态存储变量和动态存储变量:
按变量的存储类别,即生存期
动态存储:
1.自动变量
2.寄存器变量
3.形式参数
静态存储:
1.静态局部变量
2.全局变量
⑶按变量的存放位置:
动态存储区:
1.自动变量
2.形式参数
静态存储区:
1.静态局部变量
2.全局变量
寄存器:
--寄存器变量
(内存中供用户使用的存储空间包括:
程序区
静态存储区:
编译时分配空间
动态存储区:
执行时分配空间)
变量或函数的属性:
数据类型:
1.整型、2.字符型...
存储类别:
1.自动型auto
2.静态型static
3.寄存器register
4.外部型extern
2.局部变量的存储类别
⑴自动变量
存储在动态存储区,用auto说明--〉通常,将auto省略
eg:
intfunc1(inta)形参a,变量b、c都是自动变量。
{调用该函数时,系统给它们分配
autointb,c=3;存储空间,函数调用结束时自动
...释放存储空间
}
⑵局部静态变量
占用静态存储区,用static说明
1.局部静态变量属于静态存储类别。
在程序整个运行期间都不释放存储空间。
2.局部静态变量在编译时赋初值(仅赋一次初值)。
3.如果定义局部静态变量时没有赋初值,编译时会自动赋初值。
4.局部静态变量只能在定义它的函数内被使用。
(它存在但不能被其他函数使用)
eg:
打印1到5的阶乘。
#include
floatfac(intn)
{
staticfloatf=1;
f=f*n;//f=1,1,2,6,24
returnf;
}
main()
{
intj;
for(j=1;j<=5;j++)
printf("%d!
=%.0f\n",j,fac(j));
}
/*
1!
=1
2!
=2
3!
=6
4!
=24
5!
=120
--------------------------------
*/
⑶寄存器变量(了解)
存储在寄存器中,用register说明
1.计算器的寄存