为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

C语言程序设计 教学课件 ppt 作者 罗朝盛 第6章 函数

2019-05-05 84页 ppt 968KB 15阅读

用户头像 个人认证

希望

暂无简介

举报
C语言程序设计 教学课件 ppt 作者 罗朝盛 第6章 函数☆☆第6章函数*第6章函数 本章要求 理解模块化程序设计思想; 掌握函数的定义与调用方法; 掌握C语言的参数传递方式,尤其是数组参数的传递特点; 掌握变量的作用域和存储方式。 本章重点 函数的定义与调用 参数传递 变量的作用域和存储方式 本章难点 参数传递 变量的作用域和存储方式☆☆第6章函数*第6章函数6.1函数概述6.2函数的定义6.3函数调用与参数传递6.4函数与指针6.5main函数的参数6.6函数与变量的作用域6.7应用程序举例☆☆第6章函数*6.1函数概述 6.1.1模块化程序设计方法 模块是较小的、能够完成一定任...
C语言程序设计 教学课件 ppt 作者 罗朝盛 第6章 函数
☆☆第6章函数*第6章函数 本章要求 理解模块化程序思想; 掌握函数的定义与调用; 掌握C语言的参数传递方式,尤其是数组参数的传递特点; 掌握变量的作用域和存储方式。 本章重点 函数的定义与调用 参数传递 变量的作用域和存储方式 本章难点 参数传递 变量的作用域和存储方式☆☆第6章函数*第6章函数6.1函数概述6.2函数的定义6.3函数调用与参数传递6.4函数与指针6.5main函数的参数6.6函数与变量的作用域6.7应用程序举例☆☆第6章函数*6.1函数概述 6.1.1模块化程序设计方法 模块是较小的、能够完成一定任务的、相对独立的程序段,可以被看作组成一个程序的逻辑单元 C语言使用函数作为程序的组成单元 简化程序设计 便于调试和维护 使用函数进行程序设计时,一个完整的程序由一个主函数main和若干个其它函数组成,由主函数根据需要调用其它函数来实现相应功能,调用的关键在于函数之间的数据传递 对于每一个函数,它仍然由顺序、选择和循环三种基本结构组成☆☆第6章函数*6.1函数概述 例6-1编写一个显示欢迎信息的程序,要求所有的信息均在一个星号组成的矩形框中显示。 程序代码如下:#include<stdio.h>#include<string.h>#defineUSERNAME"XiaoQiang"voidmessage(char*s); /*函数声明*/voidmain(){charname[10];message("Pleaseinputyourname!"); /*函数调用*/scanf("%s",name);if(strcmp(name,USERNAME)==0)message("WelcometotheCworld!");elsemessage("ErrorUsername"); /*函数调用*/}☆☆第6章函数*6.1函数概述voidmessage(char*s) /*函数定义*/{intn,i;n=strlen(s); /*求字符串S的长度*/for(i=1;i<=n+4;i++)printf("%c",'*');printf("\n");printf("*%s*\n",s);for(i=1;i<=n+4;i++)printf("%c",'*');printf("\n");}☆☆第6章函数*6.1函数概述 程序输出如下:****************************Pleaseinputyourname!****************************XiaoQiang****************************WelcometotheCworld!**************************** C程序的层次关系☆☆第6章函数*6.1函数概述 6.1.2C函数的分类 从使用角度划分 函数,即库函数 自定义函数 从函数形式划分 无参函数 有参函数 从函数的结果划分 无返回值函数 有返回值函数 从函数的存储类型划分 外部函数(extern) 静态函数(static)☆☆第6章函数*6.2函数的定义 6.2.1函数的定义形式类型符函数名([形式参数]){函数体} 说明 类型符使用C语言提供的数据类型标识符,用于说明函数返回值的类型 函数名是一个标识符,应当遵循C语言中标识符的命名规则 形式参数可以是0个、一个或多个,表示该函数被调用时所需的一些必要信息 对于有参函数,形式参数的定义与变量的定义形式相似 函数体是一组放在一对花括号中的语句,一般包括声明部分和执行部分 在函数中,形式参数可以作为已知的变量,不需要对它赋值就可使用它,它的值是函数调用时由实参传递给形参变量而得到的☆☆第6章函数*6.2函数的定义 6.2.2函数返回值 C语言通过return语句获得函数返回值的,其格式如下: return表达式;或return(表达式); 例6-2无参有返回值函数的定义与使用。函数getach用于随机生成一个小写字母。 程序代码如下:#include<stdio.h>#include<stdlib.h>chargetach(void); /*函数声明*/voidmain(){inti;charc;randomize(); /*初始化随机数发生器*/printf("Output10characters:\n");☆☆第6章函数*6.2函数的定义for(i=1;i<=10;i++){c=getach(); /*函数调用*/printf("%c",c);}getch();}chargetach(void) /*函数定义,随机产生一个小写字母*/{return('a'+random(26)); /*函数返回值*/} 说明: 表达式的值即函数返回值,它应与所定义的函数返回值的类型一致 一个函数可以有多条return语句,执行到哪一条return语句,哪一条起作用 return语句的另一作用是终止执行函数 为增加程序的可读性,建议只在函数结尾处使用一次return语句☆☆第6章函数*6.2函数的定义 6.2.3形式参数的设计 设计形式参数应从函数的功能分析入手,那个数据需要调用函数提供,这就应定义一个形式参数接收该数据 例6-3编写一个函数求两个整数的最大公约数。intmaxgynum(intn,intm){intr,t;if(m<n) /*如果m<n,则交换变量m和n的值,使得m>n*/{t=m;m=n;n=t;}r=m%n; /*求余*/while(r!=0){m=n;n=r;r=m%n;}returnn;}☆☆第6章函数*6.2函数的定义voidmain(){intn,m,gyshu;printf("Enterm,n=?");scanf("%d%d",&m,&n);gyshu=maxgynum(n,m);printf("ThemaxGyshu=%d\n",gyshu);}☆☆第6章函数*6.2函数的定义 6.2.4函数原型 在使用自定义函数时,除了进行函数的定义外,还需要在调用该函数之前对其进行原型声明 函数原型声明和函数定义的区别 函数原型声明的作用是将函数类型告诉编译系统,使程序在编译阶段对调用函数的合法性进行全面的检查,避免函数调用时出现参数的个数或类型不一致的运行错误。 函数定义部分则是函数的实际实现代码 函数原型声明的格式:类型符函数名(形式参数);☆☆第6章函数*6.2函数的定义 6.2.4函数原型 说明: (1)函数原型声明语句最后的分号不能省略,其作用是表示该语句是进行函数声明而不是函数定义。 (2)在原型声明中,形式参数名可以省略。 (3)如果被调用函数的定义出现在调用函数之前,可以不对被调用函数进行原型声明。 (4)如果被调用函数已在所有函数定义之前进行了原型声明,则在各个调用函数中不必再对该函数进行原型声明☆☆第6章函数*6.3函数调用与参数传递 6.3.1函数的调用方式 有参函数调用的格式:函数名(实际参数) 无参函数的调用格式:函数名() 说明 函数总是在某个函数体中被调用 函数调用可以在结尾处加上分号,单独作为一条语句 对于有返回值的函数,其调用也可以出现在某条语句中 函数的调用过程☆☆第6章函数*6.3函数调用与参数传递 6.3.2参数传递 形式参数与实际参数的区别 形式参数又称为形参或虚参,它表示一个函数被调用时所需的一些必要信息。事实上,形参是一种局部变量(有关内容将在5.3.1节具体讨论),它在函数被调用前并没有被分配存储空间,也没有具体的值。形参仅仅是一个“符号”。 实际参数又称为实参,它是调用函数向被调用函数提供的一些具体信息,可以是常量、变量或表达式,它有具体的值。对于实参变量而言,它已经被分配了相应的存储空间。 调用有参函数时,必须要提供与形参相匹配的实参。所谓匹配是指实参与形参的个数相等,对应实参与形参的类型相同或赋值兼容。 在调用有参函数时,系统将会根据形参的类型为其分配存储空间,而存储空间中的内容即形参的值,则来自调用函数所提供的实参。 当被调用函数执行完毕返回调用函数时,形参的存储空间又被系统收回,形参的值也就不复存在了。 注意,C语言中的参数传递是一种单向的“值传递”。当实参为变量时,函数调用时仅仅是将实参变量的值复制了一份交给形参,形参与对应实参的存储空间完全不同,在函数调用过程中对形参的改变,根本不会影响到实参的值。☆☆第6章函数*6.3函数调用与参数传递 例6-4:参数传递。 程序代码如下:#include<stdio.h>voidswap(inta,intb);/*声明函数原型*/voidmain(){intx,y;x=10;y=20;printf("Beforeswapping:x=%dy=%d\n",x,y);swap(x,y);/*调用函数*/printf("Afterswapping:x=%dy=%d\n",x,y);}voidswap(inta,intb)/*定义函数*/{intt;t=a;a=b;b=t;}☆☆第6章函数*6.3函数调用与参数传递 程序输出如下:Beforeswapping:x=10y=20Afterswapping:x=10y=20☆☆第6章函数*6.3函数调用与参数传递 6.3.3指针变量作参数 例6-5指针变量作参数。程序代码如下:#include<stdio.h>voidswap(int*a,int*b); /*函数声明*/voidmain(){intx,y;x=10;y=20;printf("Beforeswapping:x=%dy=%d\n",x,y);swap(&x,&y); /*函数调用*/printf("Afterswapping:x=%dy=%d\n",x,y);}☆☆第6章函数*6.3函数调用与参数传递voidswap(int*a,int*b) /*函数定义*/{intt;t=*a;*a=*b;*b=t;}程序输出结果如下:Beforeswapping:x=10y=20Afterswapping:x=20y=10☆☆第6章函数*6.3函数调用与参数传递 注意:不能试图通过调用以下函数来交换实参变量的值。 程序代码如下:voidswap(int*a,int*b){int*t;t=a;a=b;b=t;}☆☆第6章函数*6.3函数调用与参数传递 例6-6编写一个函数用于求解一元二次方程的实根 程序代码如下:#include<stdio.h>#include<math.h>/*函数声明*/voidroot(floata,floatb,floatc,float*x1,float*x2);voidmain(){floata,b,c,x1,x2;do{printf("inputa,b,c=");scanf("%f,%f,%f",&a,&b,&c);}while(b*b-4*a*c<0);root(a,b,c,&x1,&x2); /*函数调用*/printf("x1=%f,x2=%f",x1,x2);}☆☆第6章函数*6.3函数调用与参数传递/*函数定义*/voidroot(floata,floatb,floatc,float*x1,float*x2){*x1=(-b+sqrt(b*b-4*a*c))/2;*x2=(-b-sqrt(b*b-4*a*c))/2;}程序的运行结果如下:inputa,b,c=1,2,3inputa,bc=1,5,6x1=-2.000000,x2=-2.000000☆☆第6章函数*6.3函数调用与参数传递 6.3.4数组参数 一维数组参数 例6-7定义一个函数max_value用于返回一个10个元素组成的一维整型数组中的最大值。 程序代码如下:#include<stdio.h>#include<stdlib.h>intmax_value(inta[]); /*函数声明*/voidmain(){intx[10],i;printf("Array:");randomize();for(i=0;i<10;i++){x[i]=random(90)+10;printf("%3d",x[i]);}printf("\nMaxvalue:%2d",max_value(x)); /*函数调用*/}☆☆第6章函数*6.3函数调用与参数传递intmax_value(inta[]) /*函数定义*/{inti,t;t=a[0];for(i=1;i<10;i++)if(a[i]>t)t=a[i];return(t);} 一维数组参数的定义和使用原则 一维形参数组的定义形式为:类型名形参数组名[],不用指定元素个数,但一对方括号不可缺少,否则无法说明该参数为一数组。 调用使用数组参数的函数时,与形参数组对应的实参是一个同类型的数组名,不需要指定元素个数,也不需要加上方括号。☆☆第6章函数*6.3函数调用与参数传递 一维数组参数 数组参数传递 在函数中对形参数组所做改变,将被保存在形参数组所对应的存储空间中,这也就间接改变了实参数组,因为它们对应同样的存储空间。当函数调用结束后,形参数组不再对应任何存储空间,形参数组也就没有具体的元素了。但是,实参数组仍然对应原来的存储空间,而存储空间中改变后的值就是实参数组新的元素值。 通常情况下,数组做函数参数,需要再定义一个整型形参,用于传递数组元素个数的信息。☆☆第6章函数*6.3函数调用与参数传递 例6-8编写一个实现一维数组排序的函数。 程序代码如下:#include<stdio.h>#include<stdlib.h>voidsort(inta[],intn); /*函数声明*/voidmain(){intx[10],i;randomize();printf("Beforesorting:\n");for(i=0;i<10;i++){x[i]=random(90)+10;printf("%3d",x[i]);}sort(x,10); /*函数调用*/printf("\nAftersorting:\n");for(i=0;i<10;i++)printf("%3d",x[i]);}☆☆第6章函数*6.3函数调用与参数传递voidsort(inta[],intn) /*函数定义*/{inti,j,k,t;for(i=0;i<n-1;i++){k=i;for(j=i+1;j<n;j++)if(a[k]>a[j])k=j;if(k!=i){t=a[i];a[i]=a[k];a[k]=t;}}}☆☆第6章函数*6.3函数调用与参数传递 例6-9编写一个判断一个字符串是否为“回文”的函数。所谓“回文”是指顺读和倒读都相同的字符串,如“ABCDCBA”。 程序代码如下:#include<stdio.h>#include<string.h>#defineLEN20inthuiwen(chars[]);/*或inthuiwen(char*s);*/voidmain(){charstr[LEN];puts("Inputastring:");gets(str);if(huiwen(str)==0)printf("no\n");elseprintf("yes\n");}☆☆第6章函数*6.3函数调用与参数传递inthuiwen(chars[])/*或inthuiwen(char*s)*/{char*h,*t;h=s; /*让t指向字符串的首字符*/t=s+strlen(s) /*让t指向字符串的最后一个字符*/while(*h==*t&&h<=t){h++;t--;}if(h>t)return(1);elsereturn(0);}☆☆第6章函数*6.3函数调用与参数传递 多维数组参数 多维形参数组的定义形式为:类型名形参数组名[][数值]……[数值],即除了最左边的方括号可能留空外,其余都要填写数值。 调用使用多维数组参数的函数时,与形参数组对应的实参是一个同类型的数组名,也不需要加上任何方括号。 例6-10编写一个函数用于查找并返回3×4的矩阵中的最大元素。 程序代码如下:#include<stdio.h>intmax_value(inta[][4],intn);/*声明函数原型*/voidmain(){intx[3][4];intm,i,j;for(i=0;i<3;i++)for(j=0;j<4;j++)scanf("%d",&x[i][j]);☆☆第6章函数*5.3函数调用与参数传递for(i=0;i<3;i++){for(j=0;j<4;j++)printf("%d",x[i][j]);printf("\n");}m=max_value(x,3);/*调用函数*/printf("\nThemaxvalueis%d\n",m);}intmax_value(inta[][4],intn)/*定义函数*/{intm,i,j;m=a[0][0];for(i=0;i<n;i++)for(j=0;j<4;j++)if(m<a[i][j])m=a[i][j];return(m);}☆☆第6章函数*6.3函数调用与参数传递 6.3.5函数的嵌套调用 C语言中的函数定义是相互独立的,不允许函数的“嵌套”定义,即不允许在一个函数体内包含另一个函数的定义。但允许嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数。 例6-11编写一个小学四则运算练习程序,程序可根据用户的选择随机生成加、减、乘、除练习题目,并分析运算结果是否正确。 程序代码如下:#include<stdio.h>#include<stdlib.h>voidexam(intn);voidadd(void);voidsub(void);voidmul(void);voiddivision(void);☆☆第6章函数*6.3函数调用与参数传递voidmain(){intn;while(1){printf("********\n");printf("*1-ADD*\n");printf("*2-SUB*\n");printf("*3-MUL*\n");printf("*4-DIV*\n");printf("*0-EXIT*\n");printf("********\n");printf("Pleaseselect0-4:");scanf("%d",&n);if(n<0||n>4)printf("Invalidnumber!\n");elseif(n==0)break;elseexam(n);}}☆☆第6章函数*6.3函数调用与参数传递voidexam(intn){switch(n){case1:add();break;case2:sub();break;case3:mul();break;case4:division();}}☆☆第6章函数*6.3函数调用与参数传递voidadd(void){intx,y,z,result;randomize();x=random(100);y=random(100);z=x+y;printf("%d+%d=",x,y);scanf("%d",&result);if(result==z)printf("OK\n");elseprintf("Sorry\n%d+%d=%d\n",x,y,z);}☆☆第6章函数*6.3函数调用与参数传递voidsub(void){intx,y,z,result;randomize();x=random(100);y=random(100);z=x-y;printf("%d-%d=",x,y);scanf("%d",&result);if(result==z)printf("OK\n");elseprintf("Sorry\n%d-%d=%d\n",x,y,z);}☆☆第6章函数*6.3函数调用与参数传递voidmul(void){intx,y,z,result;randomize();x=random(100);y=random(100);z=x*y;printf("%d*%d=",x,y);scanf("%d",&result);if(result==z)printf("OK\n");elseprintf("Sorry\n%d*%d=%d\n",x,y,z);}☆☆第6章函数*6.3函数调用与参数传递voiddivision(void){intx,y,z,result;randomize();do{x=random(100);y=random(100);}while(x%y!=0||y==0);z=x/y;printf("%d/%d=",x,y);scanf("%d",&result);if(result==z)printf("OK\n");elseprintf("Sorry\n%d/%d=%d\n",x,y,z);}☆☆第6章函数*6.3函数调用与参数传递☆☆第6章函数*6.3函数调用与参数传递 6.3.6函数的递归调用 一个函数不仅可以调用其它函数,还可以直接或间接调用它本身,这种调用过程被称作递归(recursion)。 例6-12用递归的方法计算n!。 程序代码如下:floatfact(intn){floatf;if(n<0)printf("n<0,error!\n");elseif(n==0||n==1)f=1;elsef=n*fact(n-1);return(f);}☆☆第6章函数*6.4函数与指针 6.4.1返回指针值的函数 定义形式为: 类型名*函数名(形式参数) 例如:int*f(inta,intb); 例6-13有30个学生成绩(每人5门课程),要求编写一个函数用于查询指定学生的成绩。#include<stdio.h>#include<stdlib.h>#defineM30#defineN5int*search(intscore[][N],intnum); /*函数原型说明*/☆☆第6章函数*6.4函数与指针voidmain(){intscore[M][N],i,j,num;int*p;randomize(); /*初始化随机种子数*/for(i=0;i<M;i++)for(j=0;j<N;j++)score[i][j]=random(100); /*用随机函数random()产生0~100整数*/printf("Inputanumber(1-30):");scanf("%d",&num);p=search(score,num);printf("No.%dscores:",num);for(j=0;j<N;j++)printf("%3d",*(p+j));getch();}☆☆第6章函数*6.4函数与指针int*search(intscore[][N],intnum){int*p;p=&score[num][0]; /*取得第num行的第0行的元素地址*/return(p);}☆☆第6章函数*6.4函数与指针 6.4.2函数的指针 C程序需要编译后才能执行,构成C程序的每一个函数在编译时都被分配了一块存储空间,其中存放着实现该函数功能的各条指令。函数名代表了函数存储空间的起始地址,即函数的指针。 C语言允许定义一个指针变量存放函数的入口地址,这种指针变量被称为指向函数的指针变量,其定义形式如下: 类型名(*指针变量名)(参数类型); 例6-14编写一程序,根据用户输入的半径,分别计算圆柱体和圆锥体的体积。#include<stdio.h>#definePI3.14floatv1(floatr,floath);floatv2(floatr,floath);☆☆第6章函数*6.4函数与指针voidmain(){float(*v)(float,float),r,h;intn;printf("Youwanttocalculatethevolumeof:1-Cylind,2-Cone?");scanf("%d",&n);switch(n){case1:v=v1;break;case2:v=v2;break;default:v=NULL;}☆☆第6章函数*6.4函数与指针if(v!=NULL){printf("Inputr,h=");scanf("%f,%f",&r,&h);printf("%f",(*v)(r,h));}}floatv1(floatr,floath){return(PI*r*r*h);}floatv2(floatr,floath){return(PI*r*r*h/3.0);}☆☆第6章函数*6.4函数与指针 说明:(1)与其它指针变量相同,指向函数的指针变量在使用前也必须进行初始化操作,具体形式为“指针变量=函数名”。不要写成“指针变量=函数名(形式参数)”的形式。(2)指向函数的指针变量可以先后指向不同的函数,但需注意函数返回值的类型与定义指针变量时所说明类型的一致性。(3)通过指向函数的指针变量调用函数时,只需将“(*指针变量名)”代替传统调用中的函数名即可。(4)对于指向函数的指针变量,++和--等运算是无意义的。☆☆第6章函数*6.4函数与指针 6.4.3指向函数的指针变量作参数 例6-15设计一个函数,调用它时可以计算圆柱体或者圆锥体的体积。#include<stdio.h>#definePI3.14floatv1(floatr,floath);floatv2(floatr,floath);floatvol(floatr,floath,float(*f)(float,float));☆☆第6章函数*6.4函数与指针voidmain(){floatr,h;printf("Inputr,h=");scanf("%f,%f",&r,&h);printf("Volumeofcylind:%f\n",vol(r,h,v1));printf("Volumeofcone:%f\n",vol(r,h,v2));}floatv1(floatr,floath) /*求圆柱体的体积*/{return(PI*r*r*h);}☆☆第6章函数*6.4函数与指针floatv2(floatr,floath) /*求圆锥柱体的体积*/{return(PI*r*r*h/3.0);}floatvol(floatr,floath,float(*f)(float,float)){return((*f)(r,h));}☆☆第6章函数*6.5main函数的参数 带参数的main函数头部的定义形式如下: main(intargc,char*argv[]) /*或者main(intargc,char**argv)*/ C程序的执行流程是从main函数开始的,而main函数则是由系统调用的,因此传递给main函数的实参来自系统 例7-18main函数的参数。#include<stdio.h>main(intargc,char**argv){inti;printf("Thecommandlinehas%darguments:\n",argc-1);for(i=1;i<argc;i++) printf("%d:%s\n",i,*(argv+i));}☆☆第6章函数*6.6函数与变量的作用域 6.6.1局部变量与全局变量 变量作用域例6-17变量作用域示例。#include<stdio.h>#include<stdlib.h>voidtrans(void);voidmain(){inta[10],i;printf("Before:\n");randomize();for(i=0;i<10;i++){a[i]=random(10);printf("%2d",a[i]);}trans();printf("\nAfter:\n");for(i=0;i<10;i++)printf("%2d",a[i]);}☆☆第6章函数*6.6函数与变量的作用域voidtrans(void){inti,t;for(i=0;i<5;i++){t=a[i];a[i]=a[9-i];a[9-i]=t;}}☆☆第6章函数*6.6函数与变量的作用域 局部变量 在一个函数内部定义的变量被称作局部变量,也叫内部变量。局部变量只在定义它的函数范围内有效,即在此函数之外无法使用这些变量。 在一个函数内部,还可以在复合语句中定义变量,其作用域只局限于该复合语句 一般要求将局部变量的定义放在函数的开始,尽量不要在函数中间定义局部变量。复合语句中的局部变量一般用于小范围内的临时变量。☆☆第6章函数*6.6函数与变量的作用域 全局变量 全局变量又称为外部变量,它是在函数之外定义的变量,其作用范围为从定义的位置开始到本源程序文件的结束。#include<stdio.h>#include<stdlib.h>voidtrans(void);inta[10]; /*a作用域开始*/voidmain(){inti;printf("Before:\n");randomize();for(i=0;i<10;i++){a[i]=random(10);printf("%2d",a[i]);}trans();printf("\nAfter:\n");for(i=0;i<10;i++)printf("%2d",a[i]);}☆☆第6章函数*6.6函数与变量的作用域voidtrans(void){inti,t;for(i=0;i<5;i++){t=a[i];a[i]=a[9-i];a[9-i]=t;}}/*a作用域结束*/☆☆第6章函数*6.6函数与变量的作用域 说明 全局变量在其定义位置之后的所有函数中均可直接使用 全局变量的作用在于增加了函数之间的数据传递通道,使得函数之间的数据联系不只局限于参数传递和return语句,通过全局变量可以从函数中得到一个以上的返回值 在全局变量的作用域中,所有函数均可直接访问全局变量,也就是说如果在一个函数中改变了全局变量的值,就能影响到其它函数 函数设计原则☆☆第6章函数*6.6函数与变量的作用域#include<stdio.h>#include<stdlib.h>voidtrans(inta[],intn);voidmain(){inta[10],i;printf("Before:\n");randomize();for(i=0;i<10;i++){a[i]=random(10);printf("%2d",a[i]);}trans(a,10);☆☆第6章函数*6.6函数与变量的作用域printf("\nAfter:\n");for(i=0;i<10;i++)printf("%2d",a[i]);}voidtrans(inta[],intn){inti,t;for(i=0;i<n/2;i++){t=a[i];a[i]=a[n-i-1];a[n-i-1]=t;}}☆☆第6章函数*6.6函数与变量的作用域 关于变量同名 局部变量同名 不同函数中定义的局部变量(包括形参)可以同名,由于其任用域不同,因此互不影响 同一函数中不能定义两个同名的局部变量(包括形参) 全局变量与局部变量同名 当全局变量与某个函数中的局部变量同名时,在该函数内部局部变量的作用域将“覆盖”同名全局变量的作用域 例6-18:全局变量与局部变量同名 程序代码如下:#include<stdio.h>voidfirst(void);voidsecond(void);charcolor='B';/*定义全局变量*/☆☆第6章函数*6.6函数与变量的作用域voidmain(){printf("Colorinmain()is%c\n",color);first();printf("Colorinmain()is%c\n",color);second();printf("Colorinmain()is%c\n",color);}voidfirst(void){charcolor;/*定义局部变量*/color='R';printf("Colorinfirst()is%c\n",color);}voidsecond(void){color='G';printf("Colorinsecond()is%c\n",color);}☆☆第6章函数*6.6函数与变量的作用域 程序输出如下:Colorinmain()isBColorinfirst()isRColorinmain()isBColorinsecond()isGColorinmain()isG☆☆第6章函数*6.6函数与变量的作用域 6.6.2动态存储变量与静态存储变量 动态存储变量 系统在程序运行期间根据需要对存储空间进行动态分配的变量称为动态存储变量 在函数中定义的局部变量和形参都属于动态存储变量 动态存储变量的值在函数调用结束后就无法使用了,即变量的生存期并不等于程序的整个执行期 每次调用函数时,系统会为这些变量重新分配存储空间,这就意味着如果在一个程序中两次调用同一个函数,系统分配给这个函数中的局部变量和形参的存储空间可能是不同的 可以在函数内部定义局部变量时使用auto关键字,从而显式声明该变量采用动态存储方式 注意,不能在声明形参时使用auto关键字,因为形式参数只能采用动态存储方式☆☆第6章函数*6.6函数与变量的作用域 静态存储变量 系统在程序运行期间为其分配固定存储空间的变量称为静态存储变量 全局变量就是一种静态存储变量,系统在程序开始执行时为其分配存储空间,直到程序执行完毕才释放,因此整个程序执行期都是全局变量的生存期 可以使用static关键字将局部变量的存储方式声明为静态存储方式,在函数调用结束后保留其局部变量的值,即不释放局部变量所占据的存储空间,从而在下一次调用该函数时可能继续使用上一次调用结束时的结果 例6-19编程计算1-1/2!+1/3!-1/4!+…+(-1)n-1/n!,精度为0.000001。程序代码如下:#include<stdio.h>doubleterm(intn);☆☆第6章函数*6.6函数与变量的作用域voidmain(){inti=1,k=1;doubles=0.0,t;do{t=term(i);s=s+k/t;i++;k=-k;}while(1.0/t>1e-6);printf("%lf\n",s);getch();}doubleterm(intn){staticdoublet=1.0; /*静态局部变量的声明与初始化*/t=t*n;return(t);}☆☆第6章函数*6.6函数与变量的作用域 说明: 静态局部变量的生存期是从该变量被分配存储空间开始,即定义该变量的函数被调用开始,直到程序结束。但是,静态局部变量的作用域仍然局限于定义它的函数,静态局部变量在上一次调用结束后被保留下来的值,也只能在该函数的下一次调用中使用,而不能被其它函数使用 可以使用static关键字将全局变量的作用域局限于定义它的文件中,而不能被其它文件访问☆☆第6章函数*6.6函数与变量的作用域 6.6.3内部函数与外部函数 内部函数 如果一个函数只能被本文件中的函数调用,则称之为内部函数。通过使用static关键字,可以将一个函数定义为内部函数,定义格式如下:static类型符函数名(形式参数){函数体} 外部函数 如果一个函数可以被其它文件中的函数调用,则称之为外部函数 定义 通过使用extern关键字,可以在一个文件中将一个函数定义为外部函数,定义格式如下:extern类型符函数名(形式参数){函数体} 声明 在需要调用此外部函数的其它文件中,使用extern关键字声明该函数的原型☆☆第6章函数*6.7程序应用举例 例6-20验证哥德巴赫猜想,即一个大于等于6的偶数可以表示为两个素数之和,如6=3+3、8=3+5、10=3+7……。#include<stdio.h>intprime(intn); /*声明函数原型*/voidguess(intn); /*声明函数原型*/voidmain(){intn,n1,n2;do /*此循环确保输入的n为大于等于6的偶数*/{printf("Pleaseinputanevennumber(>=6):");scanf("%d",&n);}while(!(n>=6&&n%2==0));guess(n); /*调用函数*/}☆☆第6章函数*6.7程序应用举例voidguess(intn) /*定义函数*/{intn1,n2;for(n1=3;n1<n/2;n1+=2){n2=n-n1;if(prime(n1)&&prime(n2))/*调用函数*/printf("%d=%d+%d\n",n,n1,n2);}}☆☆第6章函数*6.7程序应用举例intprime(intn) /*定义函数*/{inti,flag;flag=1;for(i=2;i<=n/2;i++)if(n%i==0){flag=0;break;}return(flag);}☆☆第6章函数*6.7程序应用举例 例6-21设计一个函数将给定的十六进制整数字符串转换为十进制数。#include<stdio.h>#include<string.h>#defineSIZE10longconvert(charh[]);voidmain(){chars[SIZE];longd;gets(s);d=convert(s);printf("%s=>%ld\n",s,d);}☆☆第6章函数*6.7程序应用举例longconvert(charh[]){inti;charc;longp=0;for(i=0;h[i]='\0';i++){c=h[i];if(c>='0'&&c<='9')p=p*16+c-'0';elseif(c>='A'&&c<='F')p=p*16+10+(c-'A');elseif(c>='a'&&c<='f')p=p*16+10+(c-'a');elseprintf("error!\n");}return(p);}☆☆第6章函数*6.7程序应用举例 例6-22设计一个函数用于删除一个字符串中的指定字符,从而得到一个新的字符串。例如,从字符串“Welcome”中删除“e”后,字符串变为“Wlcom”。#include<stdio.h>voiddel_char(char*a,charch);voidmain(){char*a="AscADef";printf("%s\n",a);del_char(a,'A');printf("%s\n",a);}☆☆第6章函数*6.7程序应用举例voiddel_char(char*a,charch){char*p;while(*a!='\0'){if(ch==*a)for(p=a;*p!='\0';p++)*p=*(p+1);elsea++;}}☆☆第6章函数*6.7程序应用举例 例6-23设计一组处理字符串的函数,包括求字符串长度、字符串比较、字符串连接、字符串复制。即相当于标准函数strlen()、strcmp()、stract()、strcpy()的功能。#include<stdio.h>intlength(char*s); /*求字符串长度*/intcompare(char*s1,char*s2); /*比较字符串大小*/voidconcat(char*s1,char*s2,char*s3);/*连接字符串*/voidcopy(char*s1,char*s2); /*复制字符串*/#defineN20☆☆第6章函数*6.7程序应用举例voidmain(){char*s1="Welcome",*s2="Hello",s3[N];intt;printf("Lengthof\"Welcome\":%d\n",length(s1));t=compare(s1,s2);if(t>0)printf("%s>%s\n",s1,s2);elseif(t<0)printf("%s<%s\n",s1,s2);elseprintf("%s=%s\n",s1,s2);if(length(s1)+length(s2)<=N){concat(s1,s2,s3);printf("%s+%s=%s\n",s1,s2,s3);}elseprintf("spaceisnotenoughforconnect\n");☆☆第6章函数*6.7程序应用举例if(length(s1)>=length(s2)){printf("Beforecopy:%s\n",s1);copy(s1,s2);printf("Aftercopy:%s\n",s1);}elseprintf("spaceisnotenoughforcopy\n");}☆☆第6章函数*6.7程序应用举例intlength(char*s){intn=0;while(*s!='\0'){n++;s++;}return(n);}☆☆第6章函数*6.7程序应用举例intcompare(char*s1,char*s2){intn;while(*s1!='\0'&&*s2!='\0'){if(*s1!=*s2)break;/*当找到不相同的字符则跳出循环*/s1++;s2++;}if(*s1>*s2)n=1;elseif(*s1<*s2)n=-1;elsen=0;return(n);}☆☆第6章函数*6.7程序应用举例voidconcat(char*s1,char*s2,char*s3){/*此函数将字符串s1,s2连接到字符串s3中*/while(*s1!='\0'){*s3=*s1;s3++;s1++;}while(*s2!='\0'){*s3=*s2;s3++;s2++;}*s3='\0';}☆☆第6章函数*6.7程序应用举例voidcopy(char*s1,char*s2){while(*s2!='\0'){*s1=*s2;s1++;s2++;}*s1='\0';}☆☆第6章函数* 面对一个复杂的问题,最好的处理方法就是将其分解成若干个小的功能模块,然后编写函数去实现每一个模块的功能,最终通过主函数调用这些函数来实现总体目标。本章主要向大家介绍了用户自定义函数的定义与使用方法。 使用函数时,最重要的是掌握调用者与被调用者之间的数据传递。这种传递主要是通过形参与实参相结合来实现的,因此被调用者需要从调用者处获得多少数据,就应该定义多少个形参,当要获得的一批相关数据时,可以考虑使用数组参数。 C语言中的参数传递是一种单向的“值传递”。当实参为变量时,函数调用时仅仅是将实参变量的值复制了一份交给形参,形参与对应实参的存储空间完全不同,在函数调用过程中对形参的改变,根本不会影响到实参的值。但是在被调函数中可通过指针类型的形参间接改变调用函数中的变量。 调用函数可能得到一个返回值,当需要返回多个数据时,可以考虑使用数组或指针类型参数,或者通过全局变量在函数之间共享数据。本章小结☆☆第6章函数*本章作业
/
本文档为【C语言程序设计 教学课件 ppt 作者 罗朝盛 第6章 函数】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索