C语⾔程序设计---7:⽤函数实现模块化程序设计
/*输⼊两个数,求较⼤的值。*/
#include<stdio.h>
void main()
{
int a,b;
int max(int a,int b);
scanf("%d%d",&a,&b);
printf("\n两者中较⼤的值为:%d\n",max(a,b));
}
int max(int a,int b)
{
return (a>b)?a:b;
}
函数声明中的参数名可以省写,如上例中的声明也可以写成 int max(int,int);
在调⽤函数的过程中调⽤另⼀个函数,称为函数的嵌套调⽤。
在调⽤⼀个函数过程中直接或间接调⽤本函数,称为函数的递归调⽤。
函数的调⽤过程
1. 在定义函数中指定的形参,在未出现函数调⽤时,它们并不占内存中的存储单元。在发⽣函数调⽤时,函数max中的形参被分配到内
存单元中。
2. 将实参对应的值传递给形参。
3. 在执⾏max函数期间,由于形参已经有值,就可以进⾏有关的运算(如把a和b⽐较)
4. 通过return语句将函数的值带回到主调函数。
5. 调⽤结束,形参单元被释放。注意,实参单元仍保留并维持原值,没有改变。如果在执⾏⼀个被调⽤函数时,形参的值发⽣改变,但
不会改变主调函数的实参的值。
注意:在C语⾔中,实参向形参的数据传递是“值传递”,单向传递,只由实参传给形参,⽽不能由形参传给实参。
数组名作函数参数
/*有10个学⽣成绩,⽤⼀个函数求平均成绩。*/
#include<stdio.h>
void main()
{
float average(float);      /*声明的形参可以省略*/
float score[10];
for(int i=0;i<10;i++)
scanf("%f",&score[i]);
printf("平均值是:%4.2f\n",average(score));
}
float average(float array[10])
{
float sum = 0;              /*必须给初始值*/
for(int i=0;i<10;i++)
sum+=array[i];
return sum/10;
}
由于数组名代表数组的⾸地址,只是将数组的⾸元素的地址传递给所对应的形参,对应的形参应当是数组名或指针变量。
⽤数组作为函数参数,在调⽤函数时并不另外开辟⼀个存放形参数组的空间,这点是和⽤变量作函数参数是不同的。
数组名代表数组的⾸元素的地址,因此,⽤数组名作函数实参时,只是将实参数组的⾸元素的地址传给形参数组,形参数组名获得了实参数组的⾸元素的地址。因此array[0]和score[0]具有同⼀地址,共占同⼀存储单元,具有相同的值。
在程序中,定义函数average时声明了形参数组array的⼤⼩为10,但在实际应⽤中,指定其⼤⼩并不起任何中,因为C语⾔编译对形参数组⼤⼩不做检查,所以形参数组可以不指定⼤⼩,在定义数组时,可以在数组名后⾯跟⼀个空的⽅括号,它们效果是相同的。
形参数组名实际上是⼀个指针变量名。
形参数组中各元素的值如发⽣变化会使实参数组元素的值同时发⽣变化,这⼀点是与变脸作函数参数的情况不相同,务请注意。
/*输⼊10个数,选择排序*/
#include<stdio.h>
void main()
{
void sort(int array[],int);    /*有两个参数时,形参不能省*/
int array[10],n=10,i;
for(i=0;i<n;i++)
scanf("%d",&array[i]);
sort(array,n);
for(i=0;i<n;i++)
printf("%d  ",array[i]);
printf("\n");
}
void sort(int array[],int n)
{
int x;
for(int i=0;i<n;i++)
{
for(int j=i+1;j<10;j++)
{
if(array[i]>array[j])
{
x = array[i];
array[i] = array[j];
array[j] = x;
}
}
}
}
⽤变量名或数组元素作函数参数时,传递的是变量的值,⽤数组名作函数参数时,传递的是数组⾸元素的地址。可知,调⽤函数时的
虚实结合的⽅式有两类:⼀类是值传递⽅式,⼀类是地址传递⽅式。
值传递⽅式时,系统为形参另开辟存储单元,实参与形参不是同⼀单元,因此形参的值改变不会导致实参值得改变,值传递是单向
的,只能从实参传到形参,⽽不能由形参传到实参。
地址传递⽅式时,传递的是地址,系统不会为形参数组另外开辟⼀段内存单元来存放数组的值,⽽是使形参数组与实参数组共占同⼀
段内存单元。由于这个特点,可以利⽤在函数中改变形参数组的值来改变实参数组的值。从现象上看,好似传递是双向的,从实参传
递到形参,⼜从形参传递到实参。但是从严格意义上说,传递仍然是单向的,仅仅传递的是地址⽽已。由于地址共享,才会出现改变
形参数组的值也改变实参数组的值的现象。这是⼀个可以利⽤的重要技巧。
⼆维数组是由若⼲个⼀维数组组成的,在内存中,数组是按⾏存放的,因此,在定义⼆维数组时,必须指定列数(即⼀⾏中包含⼏个元素)。
float highest_score(float array[][5]);  /*正确*/
float highest_score(float array[][]);  /*错误*/
float highest_score(float array[4][]);  /*错误*/
变量的作⽤域和⽣存期
在同⼀个源⽂件中,外部变量和局部变量同名,则在局部变量的作⽤范围内,外部变量被“屏蔽”,即它不起作⽤,此时局部变量是有效的。
设置全局变量的作⽤是增加函数间数据联系的渠道。由于同⼀源程序⽂件的所有函数都能引⽤全局变量的值,因此如果在⼀个函数中改变了全局变量的值,就能影响到其他函数,相当于各个函数间有直接的传递通道。由于函数的调⽤只能带回⼀个返回值,因此有时可以利⽤全局变量增加函数间的联系渠道,在调⽤函数时有意改变某个全局变量的值,这样,当函数执⾏结束后,不仅能得到⼀个函数返回值,还能使全局变量获得⼀个新值,从效果上看,相当于通过函数调⽤能得到⼀个以上的值。
虽然全局变量有以上优点,但建议不必要时不要使⽤全局变量,因为:
1、全局变量在程序的全部执⾏过程中都占⽤存储单元,⽽不是仅在需要时才开辟单元。
2、它使函数的通⽤性降低了,因为函数在执⾏时要依赖于其所在的程序⽂件中定义的外部变量。如果将⼀个函数移到另⼀个⽂件
中,还要讲有关的外部变量及其值⼀起移过去。但若该外部变量与其他⽂件的变量同名时,就会出现冲突,降低程序的可靠性和通⽤性。、
在程序设计中,在划分模块时要求模块的“内聚性”强、与其他模块的“耦合性”弱,即模块的功能要单⼀(不要把许多互不相⼲的功能放到⼀个模块中),与其他模块的相互影响要尽量少,⽽⽤全局变量是不符合这个原则的。
⼀般要求把C程序中的函数做成⼀个封闭体,除了可以通过“实参-形参”的渠道与外界发⽣联系外,没有其他渠道。这样的程序移植性好,可读性强。
使⽤全局变量过多,会减低程序的清晰性,⼈们旺旺难以清楚地判断出瞬时各个外部变量的值,在各个函数执⾏时都可能改变外部变量的值,程序容易出错。因此,要限制使⽤全局变量。
变量的存储⽅式和⽣存期
auto-⾃动变量
函数的形参
在函数中定义的变量(包括在复合语句中定义的变量)
static-静态变量
/*输出1~5的阶乘值*/
#include<stdio.h>
void main()
{
int fac(int);
for(int i=1;i<=5;i++)
printf("%d!=%d\n",i,fac(i));
}
int fac(int n)
{
static int f=1;c语言用递归函数求n的阶乘
f = f*n;
return f;
}
运⾏结果:
1!=1
2!=2
3!=6
4!=24
5!=120
静态局部变量属于静态存储类别,在静态存储区内分配存储单元,在程序整个运⾏期间都不释放。
⽽⾃动变量(即动态局部变量)属于动态存储类别,占动态存储区空间⽽不占静态存储区空间,函数调⽤结束后即释放。
对静态局部变量是在编译时赋初值的,即只赋初值⼀次,在程序运⾏时它已有初值,以后每次调⽤函数时不再重新赋初值⽽只是保留上次函数调⽤结束时的值。
⽽对⾃动变量赋初值,不是在编译时进⾏的,⽽是在函数调⽤时进⾏,每调⽤⼀次函数重新给⼀次初值,相当于执⾏⼀次赋值语句。
如在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时⾃动赋初值0(对数值型变量)和空字符(对字符变量)。
⽽对⾃动变量来说,如果不赋初值则它的值是⼀个不确定的值。这是由于每次函数调⽤结束后存储单元已释放,下次调⽤时⼜重新另分配存储单元,⽽所分配的单元中的值是不可知的。
虽然静态局部变量在函数调⽤结束后仍然存在,但其他函数是不能引⽤它的,因为它是局部变量,只能被本函数引⽤,⽽不能被其他函数引⽤。
⽤静态存储会多占内存(长期占⽤不释放,⽽不能像动态存储那样,⼀个存储单元可供多个变量使⽤,节约内存),降低程序的可读性,当调⽤次数多时往往弄不清静态局部变量的当前值是什么。因此,若⾮必要,不要多动静态局部变量。
有时在程序设计中希望某些外部变量只限于被本⽂件引⽤,⽽不能被其他⽂件引⽤。这时可以在定义
外部变量时加⼀个static声明。这种加上static声明,只能⽤于本⽂件的外部变量,称为静态外部变量。
static对局部变量和全局变量的作⽤不同。
对局部变量来说,它使变量由动态存储⽅式改变为静态存储⽅式。
⽽对全局变量来说,它使变量局部化(局部于本⽂件),但仍未静态存储⽅式。
register-寄存器变量
由于现在计算机的运⾏速度愈来愈快,性能愈来愈好,优化的编译系统能够识别使⽤频繁的变量,从⽽⾃动将这些变量存在寄存器中,⽽不需要程序设计者指定。
extern-外部变量的作⽤范围
在任⼀个⽂件中定义外部变量Num,⽽在另⼀⽂件中⽤extern对Num作“外部变量声明”,即“extern Num;”。在编译和连接时,系统会由此知道Num是⼀个已在别处定义的外部变量,并将在另⼀⽂件中定义的外部变量的作⽤域扩展到本⽂件,在本⽂件中可以合法地引⽤外部变量Num。
变量存储类别函数内函数内函数外函数外-作⽤域存在性作⽤域存在性⾃动变量和寄存器变量√√××静态局部变量√√×√
静态外部变量√√√(只限本⽂件)√外部变量√√√√
内部函数和外部函数
表达式:
[]
.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。