有参函数
形参与实参
- 形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用
- 实参出现在主调函数中,进入被调函数后,实参变量也不能使用
- 形参和实参的功能是作数据传送
特定:
- 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。
因此,形参只有在函数内部有效。
函数调用结束返回主调函数后则不能再使用该形参变量 - 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。
因此应预先用赋值、输入等办法使实参获得确定值 - 实参和形参在数量上、类型上、顺序上应严格一致,否则会发生
类型不匹配
的错误 - 函数调用中发生的数据传送是单向的。
即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。
因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化
#include<stdio.h>
int main(){
int n;
printf("input number:\n");
scanf("%d",&n);
s(n);
printf("n=%d\n",n);
}
int s(int n){
int i;
for(i=n-1;i>=1;i--){
n=n+i;
}
printf("n=%d\n",n);
}
函数的返回值
- 函数的值只能通过
return
语句返回主调函数 - 函数值的类型和函数定义中函数的类型应保持一致。
如果两者不一致,则以函数类型为准,自动进行类型转换。 - 如函数值为整型,在函数定义时可以省去类型说明
- 不返回函数值的函数,可以明确定义为“空类型”,类型说明符为
void
函数调用
被调用函数的声明和函数原型
一般形式
类型说明符 被调函数名(类型 形参, 类型 形参...);
或者
类型说明符 被调函数名(类型, 类型...);
省去主调函数中对被调函数的函数说明
- 如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调用。这时系统将自动对被调函数返回值按整型处理
- 当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数再作说明而直接调用
- 如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主调函数中,可不再对被调函数作说明
char str(int a);
float f(float b);
main(){
...
}
char str(int a){
...
}
float f(float b){
...
}
- 对库函数的调用不需要再作说明,但必须把该函数的头文件用include命令包含再源文件前部
函数的嵌套调用
- C语言中不允许作嵌套的函数定义。
- 因此各函数之间是平行的,不存在上一级函数和下一级函数的问题。
- 但C语言允许再一个函数的定义中出现对另一个函数的调用。
例如:计算 S = 2 2 ! + 3 2 ! S=2^2!+3^2! S=22!+32!
#include<stdio.h>
long f1(int p){
int k;
long r;
long f2(int);
k=p*p;
r=f2(k);
return r;
}
long f2(int q){
long c=1;
int i;
for(i=1;i<=q;i++){
c=c*i;
}
return c;
}
int main(){
int i;
long s=0;
for(i=2;i<=3;i++){
s=s+f1(i);
}
printf("s=%ld\n",s);
}
函数的递归调用
用递归方式 计算 n ! n! n!
#include<stdio.h>
long ff(int n){
long f;
if(n<0)
printf("n<0, input error\n");
else if(n==0||n==1)
f = 1;
else
f = ff(n-1)*n;
return(f);
}
int main(){
int n;
long y;
printf("input a integer number: \n");
scanf("%d",&n);
y = ff(n);
printf("%d!=%ld",n,y);
}
数组作为函数参数
数组元素
作函数实参
数组元素作为函数实参使用与普通变量是完全相同的,在发生函数调用时,把作为实参的数组元素的值传给形参,实现单向值得传送
#include<stdio.h>
void nzp(int v){
if(v>0)
printf("%d\n",v);
else
printf("%d\n",0);
}
int main(){
int a[5],i;
printf("input 5 numbers:\n");
for(i=0;i<5;i++){
scanf("%d",&a[i]);
nzp(a[i]);
}
}
数组名
作为函数参数
用数组名作函数参数与数组元素作实参不同之处
- 用
数组元素
作为实参时,只用数组类型和函数得形参变量的类型一致,那么作为下标变量的数组元素的类型也和函数形参变量的类型一致的,因此,并不要函数的形参也是下标变量。换句话说,对数组元素的处理是按普通变量对待的;
用数组名
作函数参数时,则要求形参和相对应的实参都必须是类型相同的数组,都必须有明确的数组说明。当形参和实参二者不一致时,即会发生错误。
2.当普通变量或下标变量作函数参数时,形参变量和实参变量是由编译系统分配的两个不同的内存单元。在函数调用时发生的值传送是把实参变量的值赋予形参变量。在用数组名作函数参数时,不是进行值的传送,即不是把实参数组的每一个元素的值都赋予形参数组的各个元素。因为实际上形参数组并不存在,编译系统不为形参数组分配内存。数组名就是数组的首地址。因此在数组名作为函数参数时所进行的传送只是地址的传送,也就是说把实参数组的首地址赋予形参数组名。形参数组取该首地址之后,也就等于有了实在的数组。实际上是形参数组和实参数组为同一数组,共同拥有一段内存空间。
#include<stdio.h>
void nzp(int a[5]){
int i;
printf("\nvalues of array a are:\n");
for(i=0;i<5;i++){
if(a[i]<0)
a[i]=0;
printf("%d ",a[i]);
}
}
int main(){
int b[5],i;
printf("input 5 numbers:\n");
for(i=0;i<5;i++){
scanf("%d",&b[i]);
}
printf("initial values of array b are:\n");
for(i=0;i<5;i++){
printf("%d ",b[i]);
}
nzp(b);
printf("\nlast values of array b are:\n");
for(i=0;i<5;i++){
printf("%d ",b[i]);
}
}
局部变量
局部变量也称为内部变量,局部变量是在函数内作定义说明的,其作用域仅限于函数内,离开该函数后再使用这种变量是非法的。
- 主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用。同时,主函数中也不能使用其他函数中定义的变量。因为主函数也是一个函数,它与其它函数是平行关系。这一点是与其他语言不同的,应予以注意。
- 形参变量是属于被调用函数的局部变量,实参变量是属于主调函数的局部变量。
- 允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元。互不干扰,也不会发生混淆
- 在复合语句中也可以定义变量,其作用域只在复合语句范围内
全局变量
- 全局变量也称外部变量,它是函数外部定义的变量
- 它不属于哪一个函数,它属于一个源程序文件
- 其作用域是整个源程序
- 在函数中使用全局变量,一般应作全局变量说明
- 只有在函数内经过说明的全局变量才能使用,全局变量的说明符为
extern
- 但在一个函数之前定义的全局变量,在该函数内使用可不再加以说明
变量的存储类别
动态存储与静态存储
静态存储方式
指在程序运行期间分配固定的存储空间的方式
动态存储方式
是在程序运行期间根据需要进行动态的分配存储空间的方式
auto
变量
- 函数中的局部变量,如不专门声明为static存储类型,都是动态分配存储空间的,数据存储在动态存储区中
- 函数中的形参在函数中定义的变量(包括在复合语句中定义的变量),都属此类,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间
- 这些局部变量称为自动变量
- 自动变量用关键字
auto
作存储类别声明
int f(int a){
auto int b,c = 3; // b,c 是自动变量
}
用static
声明局部变量
有时希望函数中的局部变量的值在函数结束后不消失而保留原值,这时应该指定局部变量为“静态局部变量”,用关键词 staic 进行声明
#include<stdio.h>
f(int a){
auto b = 0;
static c = 3;
b = b + 1;
c = c + 1;
return(a+b+c);
}
int main(){
int a = 2, i;
for(i=0;i<3;i++){
printf("%d\n",f(a));
}
}
register
变量
为了提高效率,C允许将局部变量得值放在CPU中的寄存器中,这种变量叫"寄存器变量", 用关键字 register
作声明
#include<stdio.h>
int fac(int n){
register int i, f=1;
for(i=1;i<=n;i++){
f = f*i;
}
return(f);
}
int main(){
int i;
for(i=0;i<=5;i++){
printf("%d!=%d\n",i,fac(i));
}
}
用extern
声明外部变量(全局变量)
- 外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。
- 如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了
- 如果在定义点之前的函数想引用外部变量,则应该在引用之前用关键字
extern
对该变量作“外部变量声明",表示该变量是一个已经定义的外部变量 - 有了此声明,就可以从"声明"处起,合法地使用该外部变量