C语言基础课件第6章_第1页
C语言基础课件第6章_第2页
C语言基础课件第6章_第3页
C语言基础课件第6章_第4页
C语言基础课件第6章_第5页
已阅读5页,还剩70页未读 继续免费阅读

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第6章函数

C语言程序设计(基于CDIO思想)在C程序中,模块以函数的形式来体现,所以说C程序是由函数构成的语言,是函数式的语言。本章介绍用户如何定义函数以及调用、声明函数的规则;变量的作用域和存储特性;编译预处理命令。2函数的定义、调用和声明主要内容1函数的参数传递2嵌套调用和递归调用

3变量的作用域、变量的存储类型54编译预处理

研究式学习—C程序设计(第五章)3为什么引入函数?模块4大系统模块1模块2模块3C程序由若干小函数组成常用的某些功能可以独立成一个函数,提高程序的可重用性、可靠性、可维护性

研究式学习—C程序设计(第五章)4函数的概念C程序的组织:函数是C程序的基本组成部分,C语言程序由一个或多个函数组成,但至少、且只能包含一个主函数。C语言的函数可以分为三类:主函数:main()标准库函数:由系统提供,如gets(),puts()等。自定义函数:由用户编写文件1文件2….文件n

函数1函数2…函数n程序只有一个main函数

研究式学习—C程序设计(第五章)56.1求多个阶乘之和(函数的定义、调用和声明)我们先研究在一个main()函数里完成的程序

#include"stdio.h"main(){intj;longintt,s=0;for(t=1,j=1;j<=3;j++)t=t*j;s+=t;for(t=1,j=1;j<=5;j++)t=t*j;s+=t;for(t=1,j=1;j<=8;j++)t=t*j;s+=t;printf(“3!+5!+8!=%ld\n”,s);}编程计算3!+5!+8!三个求阶乘的循环语句类似,重复累赘,可重用性、可靠性、可维护性差!

6把求阶乘的程序段独立写成一个函数:main(){longs=0;s=fact(3)+fact(5)+fact(8);printf(“3!+5!+8!=%ld\n”,s);}#include"stdio.h"longfact(intn){longt=1;intj;for(j=1;j<=n;j++)t*=j;returnt;}函数nn!程序运行结果:3!+5!+8!=40446

6.1.1分析与设计7例6_3求3到10的阶乘和#include"stdio.h"main(){longs=0;inti;longfact(intn);/*函数的声明*/for(i=3;i<=10;i++)s=s+fact(i);printf("3!+5!+6!+...+10!=%ld\n",s);}longfact(intn){longt=1;intj;for(j=1;j<=n;j++)t*=j;returnt;}6.1.1分析与设计

研究式学习—C程序设计(第五章)86.1.2函数的定义和调用

{}类型标识符函数名(形式参数表)命名规则与变量名同,函数名不能重复函数返回值的类型,若不说明类型,一律自动按整型处理。当函数无返回值时用void作为类型定义符。若无参数,可写void函数头:函数体函数头函数的定义

研究式学习—C程序设计(第五章)9{

说明部分;语句部分;}当函数要返回一个值时,必须通过return语句返回,其形式如下:return(表达式);

函数的定义函数体:例如:long

fact(intn){long

t=1;intj;for(j=1;j<=n;j++)t*=j;returnt;}类型应该和函数头中的类型一致,有冲突时,服从于函数头中的类型,return后的括号可有可无

研究式学习—C程序设计(第五章)10函数的定义(返回的作用)例6_4返回一个整数的绝对值的函数定义intabsint(intx){if(x>=0)returnx;elsereturn-x;}例6_5无返回值的void函数voidpok(){printf(“0k”);return;}程序的执行从当前函数返回其上级(调用它的函数)

释放该函数的参数及变量所占用的内存空间。

向上级函数返回一个值(函数的类型不是void时)只能通过一个return语句返回一个值可以缺省函数体内不能再定义函数

(不能嵌套定义)intff1(){…

floatff2(){

…}}函数的定义就是给出:函数的名字函数的返回值类型函数的形参名字与类型函数的实现语句(函数体)定义相当于写剧本,并没有被执行(上演)11

6.1.3函数原型、函数声明与函数调用

1.函数原型调用函数时,系统需要知道下列信息:函数类型函数名函数的参数(个数、类型及顺序)知道这些信息后,系统就可以找到该函数。这些信息描述了函数的模型,是函数的用户界面,我们称为函数原型。如:intabsint(int);voidpok();126.1.3函数原型、函数声明与函数调用2.函数的声明在函数调用前,C系统需要知道函数的原型,才能保证函数的正确调用,因此当函数调用在前,定义在后时(当函数为int型时,也可不声明),必须用函数原型声明,以便C系统获取相关信息。声明时参数名可以缺省,但类型名不可以缺省,如:

intff1(intage,charsex);或:

intff1(int,char);声明中的参数名相当于注释,以便系统检查调用时实参的位置,所以可以缺省

研究式学习—C程序设计(第五章)136.1.3函数原型、函数声明与函数调用

3.函数的调用函数必须通过调用才能被执行,函数调用的功能是:u

实参数向形参数传递数据。(由演员担当角色)u

为参数和函数体内的变量分配内存空间。u

中断当前函数的执行,把执行流程转向被调用函数的入口,执行被调用函数。函数调用形式为:函数名(实参表列)如:pok();函数无返回值c=max(a,b);printf(“max=%d”,max(a,b));//函数有返回值,调用表达式作为其他表达式的一部分。以下语句有错?c=max(inta,intb);max(a,b);a=pok();

研究式学习—C程序设计(第五章)14

例6_6单向值传递举例

例6_6单向值传递举例

例6_6单向值传递举例main(){floatnum=5.76,result;

floatmult10(float);result=mult10(num);printf(“result=%f\n”,result);printf(“num=%f\n”,num);}floatmult10(intn)

{n*=10;

return(n);}调用mult10时:实参变量num的值新分配的形参单元n

复制到返回时:

numn在内存mnu与n是两个不同的存储单元,如果同名呢?“值传递”是单向传递

研究式学习—C程序设计(第五章)15例6_7求s=s1+s2+s3+s4的值floatfc(intn)/*求1+1/2+1/3+…+1/n的值*/

{floats;inti;s=0;for(i=1;i<=n;i++)s+=1/(float)i;;}求s=s1+s2+s3+s4的值。其中:

s1=1+1/2+1/3+…+1/50s2=1+1/2+1/3+…+1/100s3=1+1/2+1/3+…+1/150s4=1+1/2+1/3+…+1/200main()/*主函数*/{floatsum;sum=fc(50)+fc(100)+fc(150)+fc(200);printf(“sum=%f”,sum);}166.1.3实战演练1.以下程序通过调用max()函数求a,b中的大数,请写出max()函数的定义。#include"stdio.h"main(){inta,b,c;scanf("%d,%d",&a,&b);c=max(a,b);printf("max=%d",c);}176.1.3实战演练2.下面的函数可以输出数字金子塔,请写出main()函数调用它,输出3、5、7以内的数字金字塔。#include"stdio.h"voidpyra(intn){inti,j;for(i=1;i<=n;i++){for(j=1;j<=n-i;j++)printf("");printf("%d",i);printf("\n");}}186.1.3实战演练3.以下程序求三角形的面积,请写出pb函数和area函数的定义。#include"math.h"#include"stdio.h"

main(){inta,b,c;scanf("%d,%d,%d",&a,&b,&c);

if(pb(a,b,c))printf("area=%d",area(a,b,c));elseprintf(“inputerror!);}196.2成绩统计(函数的参数传递)

有10个同学的某科考试成绩存入s数组,求他们的平均分,并对成绩由高到低排序。6.2.1分析与设计1.数据结构设计数据如何存放,是要考虑的第一个问题。10个数据要存入计算机中,需要存入有10个元素的一维数组中,程序主要就是对这个数组操作。2.总体设计可以将其划分成三个函数实现,average()函数实现求10个同学的平均分,sort()函数完成10个同学成绩的排序,main()函数完成数据的定义、输入,并调用average()函数求出平均分,调用sort()函数完成排序。206.2.1分析与设计

3.排序函数的分析与设计排序函数的头是什么样子?排序就是将数组中的数据排序,不需要返回值,因此函数类型是void,其次要考虑函数有几个参数,是什么类型?送给排序函数进行排序的对象是个一维数组,这是排序函数的第一个参数,其次由于每次需要排序的数目不同,因此还必须有第二个参数,告知该函数需要排序的数据个数,这个参数肯定是个int型变量,这样我们就有下面该函数的轮廓:voidsort(一维数组,intn){

用某种算法对该数组排序}

研究式学习—C程序设计(第五章)21数组名作函数的参数(地址传递)对一组整形数据排序的函数:voidsort(一维数组,intn){

用某种算法对该数组排序}数据个数voidsort(ints[],intn){

用某种算法对该数组排序}C语言允许一维数组作形参时,可不定义大小发生调用时,实参数组的首地址传给形参数组,这样实参数组和形参数组共用同一段内存单元,对形参数组的操作就是对实参数组的操作

研究式学习—C程序设计(第五章)22voidsort(ints[],intn){intj,t,k;for(j=0;j<n-1;j++)for(k=j+1;k<n;k++)if(s[j]<s[k])

{t=s[j];s[j]=s[k];s[k]=t;}

main(){intj,a[]={60,70,55,89,90,100,67,88,76,95};

sort(a,10);for(j=0;j<10;j++)printf(“%d,”,a[j]);printf("平均分=%d",average(a,10));}例6_8用三个函数求10个同学的平均分及成绩排序

发生调用时对s数组的排序,就是对a数组的排序average(ints[],intn){inti,pj=0;for(i=0;i<n;i++)pj=pj+s[i];return(pj/n);}

研究式学习—C程序设计(第五章)23函数间的参数传递在函数被调用时才分配形参的存储单元实参可以是常量、变量或表达式实参类型必须与形参相符单个变量传递时是传递参数值,即单向传递数组作为参数时的情况:*数组元素作实参,与单个变量一样,是“值传递”*数组名作参数,形、实参数都应是数组名,类型要

一样,传送的是数组首地址,是“地址传递”246.2.3实战演练1.完善成绩统计程序,写一个函数求成绩的最高分,再写一个函数求不及格人数,在main()函数中调用它们。分析:求成绩最高分的函数基本框架如下:maxf(ints[],intn){intmax,i;…returnmax}求不及格人数的函数与maxf()函数基本框架相似。256.2.3实战演练2.已有如下main()函数,它调用add1函数使a数组的各个元素加1,请写出add1函数的定义#include<stdio.h>main(){inti;staticinta[]={0,1,2,3,4,5,6,7,8,9};add1(a,10);for(i=0;i<10;i++)printf("%d",a[i]);}

研究式学习—C程序设计(第五章)26“地址传递”举例main(){inti;staticinta[]={0,1,2,3,4,5,6,7,8,9};add1(a,10);for(i=0;i<10;i++)printf(“%d”,a[i]);}

12345678910

0123456789ab调用时a数组的首址送给b数组,使形参数组与实参数组占用同样的存储区域,b[i]++实际上就是a[i]++。调用前后数组内容的变化编程:将一维数组中每个元素的值加上1后显示出来voidadd1(intb[],intn){inti;for(i=0;i<n;i++)b[i]++;}276.3计算10组数中的三角形面积(嵌套调用和递归调用)在main()函数中用随机函数产生10组数,每组三个数,调用函数完成:三个数是三角形的边,求三角形的面积。6.3.1分析与设计1.main()函数设计:在main()函数中,每组三个数用a,b,c来接收,随机数用第5章介绍的rand()函数产生,用循环语句产生10组a,b,c的随机数,每产生一组就调用area()函数求三角形面积。求三角形面积函数area()设计该函数首先要判断a,b,c是否为三角形的边,通过调用pb()函数判是否是三角形的边,函数返回0,说明a,b,c不是三角形的边,否则是三角形的边,则可计算三角形面积。main()函数调用area()函数,该函数又调用pb()函数判是否是三角形的边,形成嵌套调用。28例6_9用嵌套调用的方法计算10组数中的三角形面积#include<stdio.h>#include<stdlib.h>main(){inti,a,b,c,seed;floatmj;floatarea(inta,intb,intc);intpb(inta,intb,intc);printf("inputaintuger(seed):");scanf("%d",&seed); srand(seed); for(i=0;i<10;i++){a=rand()%50;b=rand()%50;c=rand()%50;mj=area(a,b,c);if(mj)printf("%d,%d,%d,mj=%.2f\n",a,b,c,mj);}}floatarea(inta,intb,intc){floats,m;if(pb(a,b,c))/*嵌套调用*/{s=(a+b+c)/2.0;m=sqrt(s*(s-a)*(s-b)*(s-c));return(m);}elsereturn0;}intpb(inta,intb,intc){intt=0;if(a+b>c&&a+c>b&&b+c>a)t=1;returnt;}

研究式学习—C程序设计(第五章)29函数的嵌套调用

C语言中的函数定义是互相独立的,函数和函数之间没有从属关系,一个函数既可以被其它函数调用,也可以调用别的函数,这就是嵌套调用main(){调用f1()函数}f1(){调用f2()函数}f2(){}

研究式学习—C程序设计(第五章)30intf1(inta,intb)/*定义f1函数*/{intc;a+=a;b+=b;c=f11(a,b);/*调用f11函数*/returnc*c;}intf11(inta,intb)/*定义f11函数*/{intc;c=a*b%3;returnc;}main(){intx=11,y=19;printf(“%d\n”,f1(x,y));/*调用f1函数*/}

a=22,b=38c=22*38%3=836%3=2运行结果:4函数的嵌套调用(例6_10)

研究式学习—C程序设计(第五章)31递归调用

intf2(intx){inta,b;…b=f1(a)..}intf1(intx){inta,b;…b=f2(a)..}intf1(intx){inty,z;if()…z=f1(y);/*递归调用*/...}有限次的直接或间接函数自身调用——递归调用recursion.32

递归调用

求n!的方法可以用递归的方法表达:5!=4!*5,4!=3!*4,3!=2!*3,2!=1!*2,1!=1,因此递归公式为:1(n=0,1)/*递归的终点*/n!=n(n-1)!(n>1)/*递归调用*/例6_11用递归的方法求n!#include"stdio.h"floatff(intn){floatf;if(n<0)printf("n<0dataerrar!");elseif(n==0||n==1)f=1;/*递归的终点*/elsef=ff(n-1)*n;/*递归调用*/returnf;}main(){intn;floaty;printf("inputaintegernumber:");scanf("%d",&n);y=ff(n);printf("%d!=%.0f\n",n,y);}程序运行结果:inputaintegernumber:55!=12033

递归调用

调用main()

{…ff(5);f=ff(4)*5;f=ff(3)*4;f=ff(2)*3;f=ff(1)*2;1202462返回

}调用返回346.3.4实战演练1.在main()函数中随机产生10个数,调用even()函数判断是否为偶数,是偶数统计偶数的个数,是奇数,再调用prime()函数判断是否为素数,输出其中的奇数,素数。请填空。for(i=0;i<10;i++){a=rand()%50;if(even(

))cn++;}printf("\n偶数的个数为:%d\n",

);}inteven(intn){if(n%2==0)return1;else{printf("奇数:%d,",n);

if(prime(

))printf(“素数:%d,”,n);return

;}}356.3.4实战演练2.有五个人坐在一起,问第五个人多少岁?他说比第四个人大2岁。问第四个人多少岁?他说比第三个人大2岁。问第三个人多少岁?他说比第二个人大2岁。问第二个人多少岁?他说比第一个人大2岁。最后问第一个人多少岁?他说10岁。请问第五个人多少岁?根据分析,有如下公式:age(n)=10(n=1)age(n-1)+2(n>1)程序如下,请填空:age(intn){intc;if(n==1)c=10;elsec=

;/*递归调用*/return(

);}main(){printf(“%d”,age(5));}36

6.4我国人口何时增加到15亿(变量的作用域)

我国现有人口13亿,请用函数计算,当人口每年增长率分别为2%,1.5%,1%,0.5%时,多少年后我国的人口增加到15亿。要求:调用函数后,能够得到两个值,即需要几年人口达到多少。6.4.1分析与设计该题要求函数返回两个值(多少年,人口数),我们已经知道,通过函数调用,可以用return语句返回一个值给调用函数,如果想返回多个值,怎么办呢?这道题可用return语句返回一个值,用全局变量再得到一个值,这涉及到变量的作用域问题。现在我们编写利用全局变量来完成写一个函数,送入人口增长率后,得到需要几年,人口达到多少的函数,在main()函数中调用该函数时,由于增长率是有规律的,可用循环语句产生增长率,完整的程序如下。37

6.4我国人口何时增加到15亿(变量的作用域)

例6_12我国人口何时增加到15亿#defineP1300000000floatpe;/*全局变量*/fun(floatx){intn=0;

pe=P;/*初始化pe变量为13亿*/while(pe<1500000000){pe=pe*(1+x);/*计算人口数*/n++;/*计算年数*/}returnn;}

main(){floatrat=0.02;intm;while(rat>=0.001){m=fun(rat);printf("ratis%.3f,Itneeds%dyearsandthepopulationis%.0f\n",rat,m,pe); rat-=0.005; }}程序运行结果:ratis0.020,Itneeds8yearsandthepopulationis1523157120ratis0.015,Itneeds10yearsandthepopulationis1508702976ratis0.010,Itneeds15yearsandthepopulationis1509259520ratis0.005,Itneeds20yearsandthepopulationis1502308608

研究式学习—C程序设计(第五章)38floatf1(inta)/*定义f1函数*/{intb,c;

…}charf2(intx)/*定义f2函数*/{intb,j;

…}main()/*主函数*/{intm,n;

…}p,q作用域c1,c2作用域局部变量(函数体内定义)作用域仅仅局限于定义它的函数,在不同的函数内可以定义同名的局部变量(f1、f2函数都有变量b)全局变量(函数体外定义):作用域从它定义的位置开始到本源文件结束,变量名不能重。(c1,c2的作用范围小)intp=1,q=5;/*定义外部变量*/charc1,c2;/*定义外部变量*/

研究式学习—C程序设计(第五章)396.4.3实战演练main(){floatr,area;printf(“r=?”);scanf(“%f”,&r);area=carea(r);printf(“r=%5.2f,carae=%5.2f,cl=%5.2f\n”,r,area,cl);}

1.已有如下main()函数,请写出carea()函数,它接受圆的半径r后,得到圆的面积及圆的周长(c1)。floatcl;/*定义全局变量c1*/floatcarea(floatr){floatar;ar=3.14*r*r;

cl=2*3.14*r;returnar;}40

6.4.3实战演练

2.以下程序中main()函数调用avmaxmin()求出数组中的平均值、最大值和最小值,请写出max、min变量的定义并填空。#include"stdio.h"#defineN10

avmaxmin(intscore[]){inti,pj=0;max=min=score[0];for(i=0;i<N;i++){pj=pj+score[i];if(max<

)max=score[i];if(min

)min=score[i];}return

;}main(){intscore[10]={56,78,45,78,98,46,55,67,87,90},ave;ave=avmaxmin(

);printf(“\naverage=%d,max=%d,min=%d\n”,ave/N,max,min);}416.5计算机出题、判卷、打分(变量的存储类型)由计算机给小学生出5题两位整数相加和5题两位整数相乘的考试题,每题10分,满分100,并由计算机判卷、打分。6.5.1分析与设计1.总体设计本题只需两个函数,一个出题、判卷、打分函数sc()以及main()函数。2.main()函数设计main()函数的任务是显示菜单、接受用户选择、根据用户选择,调用函数做加法或乘法题。3.sc()函数的任务:switch(n)语句选择做加法还是做乘法,该函数的头为:sc(intn)。出题:在循环体中用随机函数出两位整数相加或相乘的题,题目在屏幕上显示(调用printf()函数);学生通过键盘答题(调用scanf()函数)。判卷:判断答题是否正确,用选择结构即可。打分:答题正确要加10分,应设计一个变量来统计分数(p变量),该变量必须能保存上一次的值(做加法或做乘法的分数),下一次调用该函数时,再继续加分,应将该变量设计为静态局部变量。42sc(intn){inti,a,b,c,seed;staticintp=0;printf("inputaintuger(seed):");scanf("%d",&seed);srand(seed);for(i=0;i<5;i++){a=10+rand()%89;b=10+rand()%89;switch(n){case1:printf("%2d:%d+%d=",i+1,a,b);Break;

case2:printf("%2d:%d*%d=",i+1,a,b);break;default:exit(0);}scanf(“%d”,&c);switch(n)/*判断答案*/{case1:if(c==a+b){printf("Right!\n");p+=10;} elseprintf("Wrong!\n");break;case2:if(c==a*b){printf("Right!\n");p+=10;} elseprintf("Wrong!\n");break;default:break;}}return(p);}例6_13计算机出题、判卷、打分43main(){intn,s=0;while(1){printf("*************\n");/*简易菜单*/printf("1addition\n");printf("2multiplication\n");printf("0quit\n");printf("**************\n");scanf("%d",&n);/*选择菜单*/

s=sc(n);/*调用函数*/printf("Yourscoreis%d.\n",s);/*输出分数*/}}例6_13计算机出题、判卷、打分

研究式学习—C程序设计(第五章)44变量的存储区程序代码区静态存储区动态存储区*存放可执行程序的机器指令*存放需要占用固定存储单元的变量*存放不需要占用固定存储单元的变量C语言程序所占用的存储空间通常分为三部分:

全局变量或静态变量存放在静态存储区中,直到整个程序运行结束时才释放存储单元;局部变量或自动变量存放在动态存储区中,函数调用结束时就释放存储单元。

研究式学习—C程序设计(第五章)45变量的完整定义一个变量的完整定义形式为:

存储类型说明符数据类型说明符变量表如:staticintj;externfloatx等

定义变量时不但要说明变量的数据类型,还要说明变量的存储类型。变量的存储类型确定了变量的存储方式、生存期和作用域。作用域:是指变量起作用的有效范围。按变量的作用域可以把变量分为全局变量和局部变量。生存期:是指变量占用存储空间的时限。按变量的生存期可以把变量分为静态变量和动态变量。

研究式学习—C程序设计(第五章)46变量的存储类型存储类型说明符有:auto(自动)型:属于临时性存储,其存储空间可以被若干变量多次覆盖使用register(寄存器)型(一般情况下不这样指定)*存放在CPU的通用寄存器中,目的是提高执行速度*long,double,float不能设为register型,因为超过寄存器长度static(静态)型:存放在静态存储区域中,生命期长extern(外部)型:用于定义或说明变量是外部的。

研究式学习—C程序设计(第五章)47局部变量的存储类型:autostaticregister自动变量的使用:#在函数内定义的变量,若没有指定存储类型就是自动变量。#自动变量是在动态存储区内分配单元的。调用函数时分配这些单元,返回时释放这些单元#自动变量在每调用一次时都赋一次值,且默认初值不确定voidtest_auto(){intva=0;printf(“auto=%d,”,va);++va;/*值不被保存*/}main(){inti;for(i=0;i<2;i++)test_auto();}va为自动变量,运行结果:auto=0,auto=0,48寄存器变量例6_14使用寄存器变量#include"stdio.h"main(){ints;s=power(5,3);printf(“%d\n”,s);}power(intx,registerintn)/*n为寄存器变量*/{intp;for(p=1;n;n--)p*=x;returnp;}程序运行结果为:125

研究式学习—C程序设计(第五章)49全局变量的存储类型

extern(外部)和static(静态)externinti;intx,y;staticfloatf;main(){externintk;charch;…}intk;voidfc(){intv;…}外部变量:没有说明为static的全局变量,可以被另外一个文件引用。但在引用它的文件中要用:extern说明*i是其它源程序文件定义的变量,引用时必须在本程序的开头所有函数外用extern语句说明*x、y是外部变量,可在本源程序或其它源程序中被引用*f是静态外部变量,只能在本源程序中引用,而不能被其它文件访问*k是外部变量,在main()后定义,要在主函数中引用,需用extern说明*i,x,y,f,k都是全局量,x,y,k是定义在本文件的全局变量,作用域为定义之后,i是定义在其他文件中的全局变量,必须用extern说明,才能使用。f是其他文件不得引用的静态全局变量。*v是局部变量,其作用域为fc()函数中*ch是局部变量,其作用域为主函数中注意:1.全局变量分为外部变量和静态变量2.extern能用于说明变量,也能用于定义变量3.所有全局量都是在静态存储区分配存储单元的,其默认的初值为0

研究式学习—C程序设计(第五章)50使用外部变量时应注意以下问题:u

在同一个源程序文件中使用外部变量时,如果使用在前,定义在后,必须用extern进行引用性声明。u

使用另一个源程序文件中定义的外部变量,必须用extern声明后,才能使用。u

当全局变量和局部变量名相同时,在局部变量的作用范围内,局部变量起作用,全局变量被屏蔽全局变量的存储类型

extern(外部)和static(静态)51/*源程序文件f1.c*/#include"stdio.h"externinta=5;charc1=’a’,c2=’b’;main(){externintb;

charc2=’B’;printf(“%c\n”,c1-32);printf(“%c,%d\n”,c2,b*b);printf(“%d!=%d\n”,a,fact());}intb=2;/*定义外部变量b2*/

例6_15外部变量的使用方法/*源程序文件f2.c*/externinta;/*使用另一个源程序文件中定义的外部变量必须进行引用性声明*/fact(){intk,p=1;for(k=1;k<=a;k++)p*=k;return(p);}程序运行结果:AB,45!=120

研究式学习—C程序设计(第五章)52变量存储类型小结staticinta;autocharc;registerintj;externintb;a为内部变量:不释放a为外部变量:其他文件不能引用

说明b是全局变量,定义在其他文件中或定义在本文件中(但调用在前,必须用此句说明)如果在函数体外,也可能是定义全局变量。static具有永久和私有属性

局部变量(私有)+永久(不释放)

全局变量(永久)+私有(其他文件不能用)C,j一定是局部变量

研究式学习—C程序设计(第五章)53内部函数和外部函数内部函数:也称为静态函数,只能在定义它的程序文件中被调用,而不能被其它文件中的函数所调用。*定义形式为:

static

类型标识符函数名(形参表)外部函数:除了内部函数,其余的函数都可以为其它文件调用。*定义形式:

extern

类型标识符函数名(形参表)

*extern缺省时隐含为外部函数,调用文件中也要用extern说明

研究式学习—C程序设计(第五章)54

6.5.4实战演练

1.分析以下程序,写出程序的结果voidtest_static(){staticintvs=0;printf(“static=%d\n”,vs);++vs;}main(){inti;for(i=0;i<4;i++)test_static();}运行结果:static=0static=1static=2static=3*静态局部变量是在静态存储区分配存储单元的,调用结束后其值不消失,但其它函数仍然不能访问*静态局部变量是在编译过程中赋初值的,且只赋一次初值。多次调用时,上一次调用的结果就是下一次调用的初值调用次数vs初值vs结束值123401231234

研究式学习—C程序设计(第五章)556.5.4实战演练

2.已有如下main()函数,它通过5次函数调用fact()函数打印1到5的阶乘值。请设计fact()函数。通过5次函数调用打印1到5的阶乘值。1!=1,在1!的基础上再乘2,就得2!(2!=1!*2),在2!的基础上再乘3,就得3!(3!=2!*3),…,intfact(intx){staticintt=1;t*=x;returnt;}main(){inti;for(i=1;i<=5;i++)printf(“%d!=%d\n”i,fact(i));}

程序运行结果为:1!=12!=23!=64!=245!=120函数必须能保存上一次的阶乘值!

去掉static?去掉for?56不用函数的方法,快速计算若干个三角形的面积。6.6.1分析与设计如要多次调用求三角形面积的函数,就要多次进行参数的传递,多次返回三角形的面积,达不到快速计算的目的。如果用宏定义,就可不用参数传递和函数返回的时间,这样可提高运行的速度。例6_16用带参数的宏定义求三角形的面积#defineAREA(a,b,c)sqrt(s*(s-a)*(s-b)*(s-c))#defineS(a,b,c)(a+b+c)/2.0#definePB(a,b,c)if(a+b>c&&a+c>b&&b+c>a)t=1#include<stdio.h>#include<stdlib.h>#include"math.h"

6.6快速计算三角形的面积(编译预处理)main(){inti,x,y,z,t=0;floats,ar; for(i=0;i<10;i++) {x=rand()%50; y=rand()%50; z=rand()%50; t=0; PB(x,y,z) if(t){s=S(x,y,z);ar=AREA(x,y,z);printf(“%d,%d,%d,ar=%.2f\n”,x,y,z,ar);}}}

研究式学习—C程序设计(第五章)57编译预处理编译预处理:是C语言区别于其它高级语言的一个重要特点。预处理程序是C语言编译系统的组成部分,它负责分析和处理程序中使用的几种预处理语句。预处理程序对预处理语句的处理是在编译程序的其它部分处理之前进行的。预处理语句主要包括如下三种:1.宏定义2.文件包括3.条件编译(自学)

研究式学习—C程序设计(第五章)58编译预处理——宏定义*宏定义可分为两种形式:1.不带参的宏定义,形式为:

#define宏名字符串作用:是用一个指定的宏名(标识符)来代替一个字符串。例如:#defimeN10

在编译预处理时,预处理程序会把程序中该语句以后的所有N都用字符串“10”来替换。宏名用大写字母表示,以区别于变量,宏名后的字符串可以是表达式或语句,并可以进行嵌套定义(引用已定义的宏名)。

59例6_17嵌套宏定义#defineX5/*用X代替5*/#defineYX+1/*用Y代替X+1(嵌套定义)*/#defineZY*X/2/*用Z代替Y*X/2(嵌套定义)*/#include"stdio.h"main(){inta=Y;/*替换为inta=5+1*/printf(“%d,”,Z);/*Z处替换为5+1*5/2*/printf(“%d\n”,--a);}程序的运行结果为:7,5编译预处理——宏定义

研究式学习—C程序设计(第五章)60编译预处理——宏定义2.带参的宏定义,形式为:

#define

宏名(参数表)字符串注意:字符串中应包含参数表中指定参数。

如:#defineCUBE(X)(X)*(X)*(X)…intb=0,a=3;b=CUBE(a);/*替换为b=(a)*(a)*(a)*/使用有参数的宏时请注意几点:(1)在实参数为表达式时,字符串中的参数是否用括号括起来,将影响替换结果,如上例改为:#defineCUBE(X)X*X*X…intb=2,a=3;b=CUBE(b+a);/*替换为b=b+a*b+a*b+a,

*/

研究式学习—C程序设计(第五章)61编译预处理——宏定义(2)有参的宏名和()间不能空格,否则有参宏变成无参宏.#defineCUBE(X)(X)*(X)*(X)intb=2,a=3;b=CUBE(a);/*替换为b=(X)(X)*(X)*(X)(a)*/带参数的宏与函数的主要区别是宏定义不需调用及返回时的开销,宏调用在编译时进行简单的字符串替换,宏调用多,将使编译时间增加,源程序增长。

研究式学习—C程序设计(第五章)62文件包含:是指一个源文件可以将另外一个指定的源文件包括进来。其一般形式为:#include<包括文件名>*编译系统按系统设定的标准目录搜索包括文件或#include"包括文件路径名"*编译系统按指定路径搜索

*未指定路径名时,首先在当前目录中搜索

*找不到时再按系统设定的标准目录搜索包括文件编译预处理——文件包括功能是用相应文件中的全部内容来替换该预处理语句例如:f1.c源程序

#include“stdio.h”

#include<math.h>#include“file1.c”main(){….}编译连接后,可执行文件代码f1.exe:stdio.h代码math.h代码file1.c代码f1.c代码

研究式学习—C程序设计(第五章)63编译预处理——文件包含C语言编译系统中以“.h”为扩展名的文件称为头文件,在使用C语言编译系统提供的库函数进行程序设计时,经常需要在源程序中包含相应的“头文件”,如“stdio.h”、“string.h”等。用C语言设计程序时,通常将全局变量的定义、符号常量的定义、结构类型的定义以及函数类型说明等语句放在头文件中。这样,对于需要该文件的源程序来讲,都可以通过#include语句将其包含到程序中。正确使用#include语句,将会减少不必要的重复工作,提高编程效率。64

6.6.4实战演练

1.已有以下程序,请完成MIN(a,b)宏定义,求a,b中的最小值。

#include“stdio.h”main(){inta,b;scanf(“%d,%d”,&a,&b)printf(“%d\n”,MIN(a,b));}65

6.6.4实战演练

2.已有以下宏定义,求半径为r的圆周长,写一个程序使用该宏定义,求半径为2到10的圆周长。#include“stdio.h”#definePI3.1415#defineCIRFER(r)2*PI*(r)

66

6.7综合设计(单科成绩分析统计程序)

编写一个单科成绩分析统计程序。使其能够输入N个同学的成绩;能求平均分,最高分,最低分;能求各分数段人数及求及格率;能对成绩降序排列;并要求程序应有友好的界面,可点菜完成各功能。6.7.1分析与设计1.数据结构设计需要存入有N个元素的一维数组中,因为有多个函数都要对该数组操作,可将数组定义为全局变量,这样可减少函数间的参数传递。定义如下:#defineN10intscore[N];2.总体设计划分成5个函数实现,input()实现N个数据的输入;avmaxmin()实现求N个同学的平均分,最高分,最低分;sort()完成N个同学成绩的排序;count()完成求各分数段人数和及格率;main()完成系统集成,可通过点菜方式调以上函数。67

6.7综合设计(单科成绩分析统计程序)

3.各函数设计input()函数实现N个数据的输入,只需在该函数中完成N次scanf()函数的输入即可,由于score[N]数组定义为全局的,因此,各函数可直接对其操作,函数可设计为无参数的,函数定义如下:input(){inti;for(i=0;i<N;i++)scanf(“%d”,&score[i]);}count()函数完成求各分数段人数和及格率,在该函数内应定义10个变量求10个分数段,也可定义一个有10个元素的数组来存放,这样程序更简练,因为可以:68

6.7综合设计(单科成绩分析统计程序)

分数是0—9时,cn[0]++;分数是10—19时cn[1]++;…分

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论