第五章 函数
函数的定义
函数包括库函数(例scanf()、printf(),C语言系统可直接调用)和自定义函数(需要用户自己定义)两种。
函数定义形式
函数定义的一般形式为:
函数类型 函数名(形式参数表) //函数首部
{
函数实现过程 //函数体
}
*函数类型:函数结果返回的类型
计算圆柱体积
#include<stdio.h>
double cylinder(double r,double h); //函数声明 形参表中各个形参之间用逗号隔开。函数的形参的数量可一可多可无。
int main() //每个形参都得有 数据类型 形参名
{
double height,radius,volume;
scanf("%lf%if",&radius,&height);
volume=cylinder(radius,height); //使用自定义函数
printf("volume=%.3lf",volume);
return 0;
}
double culinder(double r,double h) //函数首部 r,h不用再定义
{
double result;
result=3.1415926*r*r*h;
return result; //返回值result的数据类型是double
}
*函数声明是一条C语句,函数首部不是语句,故,函数声明最后有分号(;),函数首部则没有
*用return语句返回运算的结果
函数的调用
函数调用过程
从主函数main()函数开始 | 执行主函数main()函数 |
---|---|
如果遇到某个函数调用,主函数被暂停执行 | main()函数运行到 volume=cylinder(radius,height); 调用cylinder()函数,暂停main()函数,将变量radius和height的值传递给形参r和h |
转而执行相应的函数 | 计算机转而执行cylinder()函数,形参r和h接受变量radius和height的值,执行cylinder()函数,计算圆柱体积 |
该函数执行完后将返回主函数 | 函数cylinder()执行“return result;”,结束函数运行并带着result返回main()函数中调用它的地方 |
然后再从原先暂停的位置继续执行 | 计算机从先前暂停的位置继续执行,将返回值赋给变量volume,输出体积 |
*主调函数:调用其他函数的函数,eg. main()
*被调函数:被调用的函数,eg. cylinder()
函数调用形式
函数名(实际参数) //实际参数可为常量、变量和表达式 eg. cylinder()中的radius和height
*两种情况
赋值语句,eg. volume=cylinder(radius,height);
输出函数的参数, eg. printf("%f",cylinder(radius,height));
参数传递
程序运行遇到函数调用时,实参的值依次传给形参 eg.表格第二步:将变量radius和height的值传递给形参r和h
特点:单向的,只允许实参把值复制给形参,形参的值即使在函数中改变了,也不会反过来影响实参
*实参和形参一 一对应,数量应相同,顺序应一致,初学建议类型也一致
函数结果返回
return 表达式;
一般表达式与函数类型一致,不一致以函数类型为准
return语句作用:结束函数运行和带着运算结果(表达式的值)返回主调函数,只能返回一个值
函数程序设计
计算作用的函数(2)
计算三角形面积
double area(double x,doubley,double z) //使用海伦-秦九韶公式
{
double p=(x+y+z)/2;
return sqrt(p*(p-x)*(p-y)*(p-z));
}
使用函数求最大公约数
辗转相除法,又名欧几里得算法,该算法也是一个迭代过程
int gcd(int m,int n)
{
int r,temp;
if(m<n)
{
temp=m;m=n;n=temp;
}
r=m%n;
while(r!=0)
{
m=n;
n=r;
r=m%n;
}
return n;
}
判断函数
判断完全平方的函数
1+3+5+7+…+(2*m-1)=m^2=n 思路: 每一个完全平方数都可由1,3,5等差序列相加组成
int IsSquare(int n) //1
{ //4=1+3
int i; //9=1+3+5
for(i=1;i>0;i=i+2)
{
n=n-i;
}
if(i==0){ return 1;} //判断函数
else { return 0;} //返回1(真)或0(假)进行判断
}
不返回结果得函数
void 函数名(形参表) //函数首部 函数函数类型为void,表示不返回结果,作用常以屏幕输出等方式体现
{
函数实现过程 //函数体 省略了return语句,当语句执行完毕,遇到最后的大括号即自动返回主调函数
}
该函数无 返回结果,函数调用常以独立的调用语句方式 pyramid(n);
数字金字塔
自测
#include<stdio.h>
int main()
{
int n;
void pyramid(int n);
scanf("%d",&n);
pyramid(n);
return 0;
}
void pyramid(int n)
{
int i,j;
for(i=1;i<=n;i++) //漏写这一步
{ //思路:有n次循环,每一次循环要输出空格(一个内循环)+输出数字(另一个内循环)
for(j=1;j<=n-i;j++) //000010
{ //0002020
printf(" "); //00303030
} //040404040
for(j=1;j<=i;j++) //5050505050
{
printf("%d ",i);
}
putchar('\n');
}
}
局部变量和全局变量
2个复数的运算
c1=x1+(y1)i ;c2=x2+(y2)i
求和:c1+c2=(x1+x2)+(y1+y2)i
乘积:c1*c2=(x1 * x2 - y1 * y2)+(x1 * y2 + x2 * y1)i
#include<stdio.h>
double result_real,result_imag; //全局变量
int main()
{
double imag1,imag2,real1,real2; // 主函数的局部变量
void complex_add(double real1,double imag1,double real2,double imag2); //自定义函数1
void complex_prod(double real1,double imag1,double real2,double imag2); //自定义函数2
scanf("%lf%lf",&real1,&imag1); //输入复数1
scanf("%lf%lf",&real2,&imag2); //输入复数2
complex_add(real1,imag1,real2,imag2); //调用自定义函数1,调用全局变量,实现函数2个结果返回
printf("addition of complex is %f+%fi\n",result_real,result_imag); //输出2个
complex_prod(real1,imag1,real2,imag2); //调用自定义函数2
printf("product of complex is %f+%fi\n",result_real,result_imag);//
return 0;
}
void complex_add(double real1,double imag1,double real2,double imag2)
{
result_real=real1+real2;
result_imag=imag1+imag2;
}
void complex_prod(double real1,double imag1,double real2,double imag2)
{
result_real=real1*real2-imag1*imag2;
result_imag=real1*imag2+real2*imag1;
}
变量生存周期
定义:从定义开始分配存储单元,到运行结束存储单元被回收,整个过程为变量生存周期
局部变量
定义:C语言中,定义在函数内部的变量,其有效作用范围局限于所在的函数内部。eg.real1,imag1
特点:确保各函数间的独立性,避免之间干扰。
作用范围:函数和复合语句
定义位置:局部变量一般定义在开始处,标准C规定其不能定义在中间位置
生存周期:main()函数中全部的局部变量一开始就分配存储单元,main()函数还未运行结束,其局部变量任存在,还在生存周期
其他函数未调用,其局部变量未分配存储单元,调用则其形参和局部变量才分配,结束调用,系统又收回存储单元
*形参是局部变量
全局变量
定义:在函数外而不属于任何函数的变量, eg.result_real, result_imag
定义位置:只要在函数外部即可
副作用:过度使用,导致各函数间互相干扰
生存周期:整个程序执行周期
优先作用
某函数的局部变量与全局变量同名,在该函数中,局部变量起作用,不重名,全局变量仍然有效
函数局部变量与复合语句的局部变量同名,以复合语句为准
静态局部变量
定义格式:static 类型名 变量表
eg.static double f=1;
生存周期:持续到程序结束
特点:存储单元被保留,一旦含静态局部变量的函数被调用,该静态局部变量被重新激活,继续使用上一次函数调用后的值
赋初值:静态变量赋初值只在函数第一次调用时起作用,若无赋初值,系统将自动赋0
变量储存的内存分布
*动态变量区按函数组织有各自的内存单元
结构化程序设计思想
结构化程序设计强调设计的风格和程序结构的规范化,包括3个步骤:
自顶向下分析问题的方法——把大、复杂的问题分解成小问题后解决
模块化设计——遵守模块独立性原则
结构化编码主要原则——编程时应选用顺序、选择和循环3种控制结构
用,若无赋初值,系统将自动赋0
变量储存的内存分布
*动态变量区按函数组织有各自的内存单元
结构化程序设计思想
结构化程序设计强调设计的风格和程序结构的规范化,包括3个步骤:
自顶向下分析问题的方法——把大、复杂的问题分解成小问题后解决
模块化设计——遵守模块独立性原则
结构化编码主要原则——编程时应选用顺序、选择和循环3种控制结构