目录
目录
函数的定义
函数概述
(1)函数定义角度:
库函数 :由系统提供,无需定义,可直接使用,但需要在程序开头包含原型声明的头文件。如printf
用户自定义函数 :根据自己的需求编写,自定义函数不仅要在程序中定义函数本身,必须还要在主函数中调用该函数
(2)函数形式:
无参函数 在函数的声明、定义和调用中均不带参数
有参函数 在函数的定义、声明中都有参数
(3)函数兼有其他语言中函数和过程两种功能角度:
有返回值函数 :函数被调用执行完毕,向调用者返回一个执行结果
无返回值函数 :无返回值函数不需要向主调函数提供返回值
4.总结:
一个C语言程序是由一个或多个函数组成,只有一个主函数(main函数)
一个C语言程序由一个或多个源程序文件组成
一个C语言程序只有一个main函数,main函数可以调用其他函数,其他函数不可调用main函数,其他函数可以相互调用,以main函数开头,main函数结尾
函数定义
一般形式:
类型标识符 函数名(类型 形式参数,...)
{
声明部分
执行部分
}
//例
long jiecheng(int k) //类型标识符 函数名(类型 形式参数,...)
{
long p=1;
int i; //声明部分
for(i=1;i<=k;i++)
p*=i;
return p; //执行部分
}
空函数定义格式:
类型说明符 函数名()
{
}
//例
void dummy()
{
}
函数参数和返回值
形式参数和实际参数
形式参数:形参,在定义函数时函数名后面括号中变量名称为形式参数
实际参数:实参,在主调函数中调用一个函数时,函数名后面括号中的参数称为实际参数
当有参函数调用时,需要由实参向形参传递参数。当函数未被调用时,函数的形参并不占据实际的存储单元,也没有实际值;只有当函数被调用时,系统才为形参分配存储单元,并完成实参与形参的数据传递。
//例
#include<stdio.h>
int main() //主函数
{
int max(int x,int y); //x,y为形参
int a=2,b=3,c;
c=max(a,b); //a,b为实参
printf("%d",c);
return 0;
}
int max(int x,int y) //子函数
{
int z;
x=3*x,y=3*y;
z=x>y?x:y;
return z;
}
函数调用的整个执行过程可分成四个步骤:
(1)创建形参变量,为每个形参变量建立相应的存储空间。
(2)值传递(传递数值,传递地址),即将实参的值传递给对应的形参变量。
(3)执行函数体,即执行函数体中的语句。
(4)函数返回(带回函数值、返回调用点、撤销形参变量)。
函数返回值
函数返回值:通过函数调用使主调函数能得到一个确定的值, 通常用return语句获得。
如果需要从被调用函数带回一个函数值供主函数使用,那么被调用函数必须含有return语句;反之,则不需要。
如果函数中没有 return语句,不代表函数没有返回值,只能说明函数返回值是一个不确定的数。
对于不带回值的函数,应当用 void 定义函数为“无类型”(或称“空类型”)。这样,系统就保证不使函数带回任何值,即禁止在调用函数中使用被调用函数的返回值。此时,在函数体中不得出现 return 语句。
函数的调用
函数调用:程序中使用已经定义好的函数。除了主函数外,其他函数都需要通过函数调用来执行。
调用有参函数:函数名(实参列表)
调用无参函数:函数名()括号不能省略
函数调用的三种方式
1.表达式 函数调用出现在一个表达式中 要返回值 例 c=2*max(a,b)
2.参数 函数调用作为另一个函数调用的实参 要返回值 例 d=max(a,max(b,c))
3.语句 函数调用作为一个独立语句 不要求返回值 例 scanf函数的调用
函数声明
调用其他函数时,在调用前,要对其进行声明
函数声明一般形式:
类型标识符 函数名(类型 参数名,...)
类型标识符 函数名(类型,...)
函数原型:通过函数声明语句,向编译系统提供的被调函数信息(函数返回值类型,函数名,参数个数,各参数类型)
函数的嵌套调用和递归调用
嵌套调用
函数不允许嵌套定义,但是允许嵌套调用。嵌套调用,就是函数在被调用过程中又去调用其他函数
递归调用
将要解决的问题分解成比原问题规模小的子问题,当解决这个子问题时,又可以用到原问题的解决方法,并按照这一原则
逐步递推,最终将原问题转化成较小且有已知解的子问题
适用于:分解后的子问题必须与原问题相似
经典例题:汉诺塔问题
用递归求解问题的过程分为递推和回归两个阶段。
递推阶段是将原问题不断地转化成子问题,逐渐从未知向已知推进,最终到送已知解的问题,即递推阶段结束。
回归阶段是从已知解的问题出发,按照递推的逆过程,逐一求值回归,最后到达递归的开始处,即结束回归阶段,获得问题的解。
变量的作用域
变量
全局变量:函数外面定义的变量 作用域 全部函数
局部变量:函数内部定义的变量 作用域 本函数
注:在同一个函数中,不能定义具有相同名字的变量,但是在同一个文件中全局变量和局部变量可以同名。当它们同名时,在局部变量作用范围,全局变量不起作用。
//例
#include<stdio.h>
int a=10; //a全局变量
int main()
{
int max(int a,int b);
int b,c,d; //b,c局部变量
scanf_s("请输入两个与10比较的数:%d%d",&b,&c);
d=max(a,max(b,c));
printf("最大的数为%d",d);
return 0;
}
int max(int a,int b) //在局部变量作用范围,全局变量不起作用
{
int z;
z=a>b?a:b;
return z;
}
变量的存储类别
内存空间
(1)程序存储区 存储代码
(2)静态存储区 存放全局变量
(3)动态存储区 存放函数形参,自动变量及函数调用时的现场保护和返回地址
存储类别
静态存储方式和动态存储方式
(1)auto 自动型 定义自动变量时,前面可以加auto或不加,一般在函数内部或复合语句内部使用。函数中的形参和在函数中定义的变量(包括在符合语句中定义的变量)都属于。系统在每次进入函数复合语句时,为定义的自动变量分配存储空间,并分配在动态存储区
(2)static 静态型
静态局部变量 定义静态局部变量时,前面加 statice 存储类型标识符。静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在程序运行期间都不释放。静态局部变量是在编译时赋初值的,若没有显式赋初值,则系统自动赋初值 0(对数值型变量)或空字符(对字符变量)。以后,每次调用函数时不再重新赋初值,都是保留上一次函数调用结束时的值。
静态全局变量 如果在程序设计时希望某些全局变量只限于被本文件中的函数引用,而不能被其他文件中的函数引用,就应该在定义全局变量时加上 static 进行声明。
(3)register 寄存器型 对寄存器变量的访问要比对内存变量访问速度快得多。如果将使用频率较高的数据存放在所定义的 register 变量中,可以提高运算速度。
(4)extern 外部型 在全局变量定义位置之前的函数需要引用该全局变量,应该在引用之前用关键字 extern 对该变量进行声明,表示把该变量的作用域扩展到这个位置。
#include<stdio.h>
int a=5,b=4;
int main()
{
int c; //正确,但是未使用extern
c=a*b;
printf("%d",c);
return 0;
}
#include<stdio.h>
int main()
{
int c; //错误
c=a*b;
printf("%d",c);
return 0;
}
int a=5,b=4;
#include<stdio.h>
int main()
{
extern a,b; //使用extern
int c;
c=a*b;
printf("%d",c);
return 0;
}
int a=5,b=4;
习题巩固
(1)写出pow()函数原理
提示:pow用power代替,用for语句,pow(2,3)=8
(2)计算 a^b!+b^a! 的值(以 2^3!+3^2! 为例)
提示:看成两步,一步是pow()函数,一步是求阶乘
(3)输入一个含10个元素的数组,求其中的平均值
(4)打印1!,2!,3!,4!,5!
提示:使用static静态局部变量
习题作用
(1)了解函数调用
(2)锻炼函数调用能力
(3)了解函数名作函数参数
(4)了解static静态局部变量的作用
习题答案
(1)
#include<stdio.h>
int main()
{
int power(int x,int y);
int a,b,c;
scanf_s("%d%d",&a,&b);
c=power(a,b);
printf("%d的%d次方=%d",a,b,c);
return 0;
}
int power(int x,int y)
{
int i,z=1;
for(i=1;i<=y;i++)
z=z*x;
return z;
}
(2)
#include<stdio.h>
#include<math.h>
int main()
{
int jiecheng(int x); //jiecheng=阶乘
int a,b,sum;
a=pow(2,3),b=pow(3,2); //pow()函数内的值可以换
sum=jiecheng(a)+jiecheng(b);
printf("总和=%d",sum);
return 0;
}
int jiecheng(int x)
{
int i,y=1;
for(i=1;i<=x;i++)
y*=i;
return y;
}
(3)
#include<stdio.h>
double average(double array[10]);
int main()
{
double result,score[10]={60,95,85.5,45,86.5,98,36,54,68,87};
result=average(score);
printf("平均数=%lf",result);
return 0;
}
double average(double array[10])
{
double result=0;
int i;
for(i=0;i<10;i++)
{
result+=array[i];
}
return (result/10);
}
(4)
#include<stdio.h>
int main()
{
int jiecheng(int i); //jiecheng=阶乘
int n;
for(n=1;n<=5;n++)
{
printf("%d!=%d\n",n,jiecheng(n));
}
}
int jiecheng(int i)
{
static int x=1; //通过此例题,明白static的作用
x=x*i;
return x;
}