第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用

Slides:



Advertisements
Similar presentations
河內塔(Hanoi)問題.
Advertisements

《C语言程序设计》复习
親愛的老師您好 感謝您選用本書作為授課教材,博碩文化準備本書精選簡報檔,特別摘錄重點提供給您授課專用。 說明: 博碩文化:
计算学科的基本问题 本章首先介绍一个对问题进行抽象的典型实例——哥尼斯堡七桥问题。然后,通过“梵天塔”问题和“停机问题”分别介绍学科中的可计算问题和不可计算问题。从“梵天塔”问题再引出算法复杂性中的难解性问题、P类问题和NP类问题,证比求易算法,P=NP是否成立的问题。
第一章 C语言概述 计算机公共教学部.
C语言基础——指针的高级应用 Week 05.
第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
C语言程序设计 第八章 函数.
C语言程序设计 第十二章 位运算.
C语言程序设计 课程 第5章 数组 主讲:李祥 博士、副教授 单位:软件学院软件工程系.
高级语言程序设计 主讲人:陈玉华.
第5章 函数与预处理 《 C语言程序设计》 (Visual C++ 6.0环境) 本章导读
第一章 C语言概述.
由C程序结构所知,一个完整的C语言程序是由一个且只能有一个main()函数(又称主函数)和若干个其他函数组合而成的。而前面各章仅学习main()函数的编程,本章将介绍其他函数的编程,包括其他函数的定义、调用、参数传递及变量的作用域等。
主讲教师:吴琼 微信群:C语言2016 QQ群: 密码scu2016 昵称:“真名+学号”
選擇排序法 通訊一甲 B 楊穎穆.
第3章 顺序结构程序设计 本章要点: 格式化输出函数──printf() 格式输入函数——scanf() 字符输出函数——putchar()
第4章 函数与预处理 4.1 概述 4.2 定义函数的一般形式 4.3 函数参数和函数的值 4.4 函数的调用 *4.5 内置函数
Chap 10 函数与程序结构 10.1 函数的组织 10.2 递归函数 10.3 宏定义 10.4 编译预处理.
项目六 用指针优化学生成绩排名 项目要求 项目分析
C程序设计.
If … else 選擇結構 P27.
目录 第八章 数组 1 简单学生成绩管理系统的开发 2 一维数组 3 多维数组 4 字符数组 5 数组作函数参数.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
计算概论 第十八讲 C语言高级编程 结构与习题课 北京大学信息学院.
C语言程序设计 李祥.
第八章 函数.
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
QQ: 李祥 QQ: 欢迎多种方式的学习交流,祝大家学有所成.
作弊是否很有诱惑性? 上堂课已经讲了 作业不一定在两个小时里都能完成 答疑没有一个人? 作弊是有记录的 心理系很多同学集体作弊,让人震惊
第6章 函数 学习的意义.
C语言 程序设计基础与试验 刘新国、2012年秋.
第13章 结构体的应用 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组
第八章 使用指针.
第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归
第0章作业: 教材P12-练习与实践 1.写出用符号’*’输出描绘汉字”大”的流程图。
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
第1讲 C语言基础 要求: (1) C程序的组成 (2) C语言的标识符是如何定义的。 (3) C语言有哪些基本数据类型?各种基本数
C语言大学实用教程 第5章 函数与程序结构 西南财经大学经济信息工程学院 刘家芬
資料結構與C++程式設計進階 排序與搜尋 講師:林業峻 CSIE, NTU 6/ 14, 2010.
C语言复习2----函数.
第一章 程序设计和C语言 主讲人:高晓娟 计算机学院.
C语言程序示例: 1.输入10个数,按从小到大的顺序排序。 2.汉诺塔问题。.
1.2 C语言程序的结构与书写规则 一、 C语言程序的总体结构
C程序设计.
Main() { Dfas Asdfasf fasdfa } #include <stdio.h> void main( ) {
函数 概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 开发方法: 自上向下,逐步分解,分而治之
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
第十章 指针 指针是C语言的重要概念,是C语言的特色,是C语言的精华。 10.1 地址和指针的概念 内存中的每一个字节都有一个地址。
C程序设计.
第5章 函 数.
第一章 C语言概述 教师:周芸.
C语言程序设计 李祥 QQ:
資料結構與C++程式設計進階 遞迴(Recursion) 講師:林業峻 CSIE, NTU 6/ 17, 2010.
第2章 基本数据及其运算 本章学习的目标: 1、掌握基本数据的各种表示,基本数据常数的书写方法;
第二章 类型、对象、运算符和表达式.
本节内容 函数嵌套调用的内存布局 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
第五章 逻辑运算和判断选取控制 §5.1 关系运算符和关系表达式
遞迴 Recursion.
第十二章 位运算.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
第九章 指针 C程序设计中使用指针可以: 使程序简洁、紧凑、高效 有效地表示复杂的数据结构 动态分配内存 得到多于一个的函数返回值.
C/C++基礎程式設計班 陣列 講師:林業峻 CSIE, NTU 3/14, 2015.
Chap 10 函数与程序结构 10.1 圆形体积计算器 10.2 汉诺塔问题 10.3 长度单位转换 10.4 大程序构成.
資料!你家住哪裏? --談指標 綠園.
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
C程序设计 复习 1、计算机系统的组成 外部设备:输入、输出设备(同人打交道《十进制》)
Presentation transcript:

第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用 理解并掌握全局变量与局部变量,并掌握函数中全局变量与局部变量的使用方法 了解变量的存储方式

函数是程序设计语言的重要里程碑之一,它标志着程序模块化设计和软件重用的开始。简单地说,模块化设计就是把一个复杂的问题按照功能划分为若干简单的功能模块,以模块为单位进行程序设计。模块化的目的是为了降低程序复杂度,使程序设计、调试和维护等操作简单化。一般地,将复杂问题划分为不同的模块以后更适合软件的集体开发,不同的模块由不同的程序员设计,只需要确定好模块之间的接口关系,就可以实现模块之间的相互调用,而模块内部的具体实现可以由程序员自己设计。在C语言中,模块是通过函数来实现的。

基本内容 概述 函数的定义与调用 参数的传递 函数的嵌套与递归调用 全局变量与局部变量 变量的存储方式 本章小结

概述 #include <stdio.h> int main() { printf(“this is the first program.\n”); return 1; } 标准的库函数并不能满足用户所有的需求,用户还可以根据程序的需要自定义函数,通过对函数的调用来完成相应的功能。

概述 例5-1 编写程序,计算 。 int m,n,i,fac1, fac2, fac3; 例5-1 编写程序,计算 。 int m,n,i,fac1, fac2, fac3; printf("请输入两个整数n和m(n>m): "); scanf("%d%d",&n,&m); fac1=fac2=fac3=1; for(i=1; i<=m;i++) fac1=fac1*i; for(i=1;i<=n;i++) fac2=fac2*i; for(i=1;i<=n-m;i++) fac3=fac3*i; printf("计算结果为:%d\n", fac2/(fac1*fac3));

概述 这三次循环中,除了循环的次数(即终值)不同以外,其它的代码完全一样,为减少代码的重写,可以把这部分通用代码从程序中抽出来,利用函数来实现。 int fac(int n){ int i,result=1; for(i=1;i<=n;i++) result=result*i; return result; } int m,n; printf("请输入两个整数n和m(n>m): "); scanf("%d%d",&n,&m); printf("计算结果为:%d\n", fac(n)/(fac(m)*fac(n-m)));

概述 (1)从用户使用的角度看,函数包括两种:由系统提供的、无需用户定义的标准函数,这些函数根据不同的功能存放在不同的头文件中。用户根据需要编写具有特定功能的自定义函数。 (2)C语言中所有的函数都是平行的,它们之间都是互相独立的。函数只能嵌套调用,不能嵌套定义。 (3)一个源程序文件中,可以由一个或多个函数以及其它有关内容(如数据声明与定义)组成,但必有一个main函数。程序总是从main函数开始和结束的。

基本内容 概述 函数的定义与调用 参数的传递 函数的嵌套与递归调用 全局变量与局部变量 变量的存储方式 本章小结

函数的定义 数据类型 函数名(数据类型 形式参数1, …, 数据类型 形式参数n) { 函数体 } int fac(int n){ int i,result=1; for(i=1;i<=n;i++) result=result*i; return result; } 数据类型 函数名(数据类型 形式参数1, …, 数据类型 形式参数n) { 函数体 }

函数的定义 例5-2 编写函数,判断某一年是否为闰年。要求如果是闰年,函数返回1,不是返回0。 解题思路:判断某一年是否闰年,只要判断该年是否能被400整除或能被4整除并且不能被100整除即可。将年作为函数的形式参数,在函数中对其进行判断。由于函数要求返回的值是1或者0,可以将函数的返回值定义为整型。 int judge_year(int year){ if ((year%4==0 && year%100!=0) ||(year%400==0)) return 1; else return 0; }

函数的定义 (1)在对函数的形式参数进行定义时,需要声明每一个变量的类型,不能像通常的变量声明那样,使用变量列表。 int max(int a, int b) //正确的参数定义 int max(int a,b) //错误的参数定义 (2)函数的返回类型原则上应与函数体内return语句中表达式的类型保持一致,如果二者出现不一致的情况,以函数的返回类型为准。当数据的类型是数值型时,系统会进行自动类型转换。

函数的定义 例5-3 编写函数,计算两个数的最大值。 int imax(float a, float b){ float c; c=(a>b)? a:b; return c; } void main(){ float x,y; int z; printf("请输入两个实数:"); scanf("%f%f",&x,&y); z=imax(x,y); printf("两个数的最大值是:%d\n",z);

函数名(实际参数1, 实际参数2,…, 实际参数n); 函数的调用 函数名(实际参数1, 实际参数2,…, 实际参数n); (1)定义函数时使用的参数称作形式参数,调用函数时使用的参数称作实际参数。形式参数必须是变量,而实际参数可以是常量、变量、表达式或函数,但必须有确定的值。例如: c=max(9,5); //实参是常量 c=max(x,y); //实参是变量 c=max(x+2,y*3); //实参是表达式 c=max(max(x,y),z); //求三个数的最大值,实参是函数 (2)传递的实际参数与函数定义的形式参数顺序和类型应保持一致; (3)执行函数调用时,形式参数和实际参数是两个不同的存储单元。 (4)在一个函数中可以有多个return语句,但只要执行到其中一个return语句,就结束该函数的调用。

函数的调用 例5-4 输入一个整数,判断该整数是否满足如下条件:它加上100后是一个完全平方数,再加上168又是一个完全平方数。请编写函数实现。 解题思路:判断一个数是否是完全平方数,只需要判断该数开平方后得到的整数平方是否与该数相等,如果相等,这个数是完全平方数,如果不相等,这个数不是完全平方数。给函数传递一个整数,判断该数加上100后是否是一个完全平方数,若是,然后再加上168,判断新数是否还是一个完全平方数,条件满足返回值为1,否则返回值为0。 int judge(int n){ int x,y; x=(int)sqrt(n+100); y=(int)sqrt(n+268); if (x*x==n+100 &&y*y==n+268) return 1; else return 0; }

函数的声明 C语言中的被调函数或者库函数,或者是用户自定义的函数。 (1)如果是库函数, 则需要引入相应的头文件; (2)如果是用户自定义的函数,有两种情况: ① 被调函数在主调函数之前进行定义,则不用进行函数声明,主调函数可以直接调用被调函数。 ② 被调用在主调函数之后进行定义,则在主调函数调用之前对被调函数进行函数声明。 函数类型 函数名(形参类型1 形参1,形参类型2 形参2,……); 函数类型 函数名(形参类型1,形参类型2,……);

函数的声明 例5-5 编写程序,计算一个整数各位数字之和,例如123,各位数字之和为1+2+3=6。 #include <stdio.h> int sum(int number); //函数声明 void main(){ int number, result; scanf("%d", &number); result=sum(number); printf("整数%d的各位数字之和是%d \n",number,result); } int sum(int number) { //函数定义 int result=0; while(number>0){ result=result+number%10; number=number/10; return result; 解题思路:首先编写求各位数字之和的sum函数,它的类型为int型,它有一个参数number,通过循环计算出number中每位数字的和result,其类型也应为int型。若sum函数在main函数之后进行定义,在调用函数之前,要对sum函数进行声明。

基本内容 概述 函数的定义与调用 参数的传递 函数的嵌套与递归调用 全局变量与局部变量 变量的存储方式 本章小结

参数的传递——普通变量作为函数参数 在C语言对函数进行调用时,将主调函数的实参传给被调函数的形参,同时编译系统为形式参数分配内存单元。在函数调用结束后,编译系统会立即释放形参所占用的内存单元。这里有两点需要强调: (1)函数中数据传递是单向的,只能把实参传给形参; (2)函数中的形参只在函数内部有效,在函数调用过程中,形参值的改变不会影响实参。一旦函数调用结束,形参变量所占的内存空间被释放。

参数的传递——普通变量作为函数参数 例5-6 输入两个整数,编写函数实现两个整数值的交换。 解题思路:首先编写数值交换的swap函数,它有两个参数,是两个简单变量,由于函数的功能是实现两个数的交换,无需返回值,所以它的函数类型为void型,若swap函数在main函数之后进行定义,在调用函数之前,要对swap函数进行声明。 #include <stdio.h> int main(){ void swap(int, int); int a,b; printf("请输入两个整数: "); scanf("%d%d", &a,&b); printf("交换前:a=%d,b=%d\n",a,b); swap(a,b); printf("交换后:a=%d,b=%d\n",a,b); return 0; } void swap(int x,int y){ int temp; printf(“函数swap中,交换前: x=%d,y=%d\n",x,y); temp=x; x=y; y=temp; printf("函数swap中,交换后:x=%d,y=%d\n",x,y); }

参数的传递——数组元素作为函数参数 数组元素只能作为实参,不能作为形参。这是因为形参是在函数被调用时才分配存储空间,而数组中的元素是在定义数组时系统已经分配了存储空间,因而编译系统在函数调用时无法为某一个数组元素单独分配存储空间。而将数组元素作为实参传递给函数的形参时,只需将数组元素看成是一个具体的变量传递给函数的形参,形参的相关运算并不能改变实参的值。 C语言中,函数参数的传递有两种:值传递和地址传递。数组元素作函数参数实现的是值传递,数组名作函数参数实现的是地址传递。

参数的传递——数组元素作为函数参数 例5-7 给定一个长度为10的数组,要求输出该数组中的最大数及其在该数组中的位置。 int max(int x, int y) ; int a[10]={10,100,98,789,98, 0,121,981,78,191}; int i,maxNumber,index; maxNumber=a[0]; index=0; for( i=1;i<10;i++) if (max(maxNumber, a[i])>maxNumber){ maxNumber=a[i]; index=i; } printf("数组中的最大值是%d,是数组中第%d个元素\n",maxNumber,index+1); int max(int x, int y){ return x>y?x:y; 解题思路:若求数组中的最大值和最大值在数组中的位置,假设第一个元素为最大元素,编写求两个数的最大值函数max,该函数包含两个参数,其中一个参数是存储最大值的变量,一个参数是数组元素,然后扫描整个数组,不断更新最大元素以及其所在的位置,最终找出该数组中最大元素及其所在的位置。

参数的传递——数组名作为函数参数 在C语言中的函数中,除了数组元素可以作为参数外,数组名也可以作为参数。与数组元素作为参数不同的是,数组元素作为参数时是将数组元素的值传递给函数的形参,而数组名作为参数时,向形参传递的是数组首元素的地址。

参数的传递——数组名作为函数参数 例5-9 用选择法对数组中的N个整数按从小到大的顺序进行排序。 解题思路:所谓的选择排序法就是:取待排序序列中的第1个元素,依次与序列中的其它元素进行比较,找出最小值与该值在数组中的位置,将最小值与第1个元素进行交换。然后取第2个元素,依次与序列中从第3个元素开始的元素进行比较,找出次小值与第2个元素进行交换。重复执行上述操作,直到所有元素都排好序为止。 void sort(int a[],int n){ int i,j,k,temp; for(i=0;i<n-1;i++){ k=i; for(j=i+1;j<n;j++) if(a[k]>a[j]) k=j; if(i!=k){ temp=a[i]; a[i]=a[k]; a[k]=temp; }

void sort(int a[],int n); 参数的传递——数组名作为函数参数 (1)用数组名作为函数参数,需要在主调函数和被调函数中分别定义数组,不能只在一方定义。如上例中的数组a是形参数组名,它与主调函数中的实参数组名score相对应。 (2)在C语言的编译系统中,并不检查形参中数组的大小,只是将实参数组的首地址传给形参,编译系统不为形参分配新的存储空间,两个数组共同占有相同的存储单元。 (3)由于编译系统中并不检查形参中数组的大小,因此可以在形参中数组名后加一个空括号即可。如上例中的sort函数的定义方式: void sort(int a[],int n); (4)实参数组应与形参数组类型一致。

基本内容 概述 函数的定义与调用 参数的传递 函数的嵌套与递归调用 全局变量与局部变量 变量的存储方式 本章小结

函数的嵌套与递归调用 在C语言中,所有的函数是互相平行、相互独立的。不能在一个函数中定义另一个函数,也就是说函数不能嵌套定义。但C语言允许函数之间互相调用,同时允许被调用的函数中再调用其它的函数。在C语言中,允许被调用的函数进一步调用其它函数,称为函数的嵌套调用。在函数调用中,若一个函数直接或间接地调用自身,称作函数的递归调用。

函数的嵌套调用 int max4(int a, int b, int c, int d) { int temp1, temp2, temp; 例5-12 编写程序,从输入的4个整数找出其中的最大数。 解题思路:编写求两个数的最大值函数max2,再编写求4个数的最大值函数max4,在主调函数传递4个整数给max4中的形参。在max4函数中首先将4个数分为两组,找出两组数中的最大值后,再找出这两个最大值的最大值。 int max4(int a, int b, int c, int d) { int temp1, temp2, temp; temp1=max2(a,b); temp2=max2(c,d); temp=max2(temp1,temp2); return temp; } int max2(int a, int b) return a>b?a:b;

函数的嵌套调用 int main() { int a,b,c,d; int maxValue; printf("请输入4个整数:\n "); scanf("%d%d%d%d", &a,&b,&c,&d); maxValue=max4(a,b,c,d); printf("4个数的最大值是:%d\n", maxValue); return 0; }

函数的递归调用 一个递归的问题可以分为“回溯”和“递推”两个阶段。一般地,递归函数的定义需要解决两点:(1)函数的结束条件;(2)函数的递归方式。 函数的结束条件表示递归不能无限制运行下去,必须在有限步内执行结束。而函数的递归方式则表明规模较大的问题解与规模较小的问题之间的关系,通过规模较小的问题解逐渐得到规模较大的问题解。

函数的递归调用 例5-14 编程用递归方法计算阶乘函数。 #include <stdio.h> int fac(int n); int main(){ int n,result; printf("请输入整数n: "); scanf("%d", &n); result=fac(n); printf("%d!=%d\n", n,result); return 0; } int fac(int n){ if (n==1) return 1; else return n*fac(n-1); }

函数的递归调用 int fac(int n){ if (n==1) return 1; else return n*fac(n-1); }

函数的递归调用 例5-15 Hanoi塔问题。相传印度教的天神在创造世界时,建了一座神庙,庙里竖立了3根柱子。天神将64个直径大小不一的金盘子,按照从大到小的顺序依次套放在第一根柱子上,形成了一座Hanoi塔。天神让庙里的僧侣们将第一根柱子上的盘子借助第2根柱子全部移到第3根柱子上。同时规定:每次只能移动一个盘子;盘子只能在3根柱子上来回移动而不能放在他处;在移动过程中,3根柱子上的盘子必须始终保持大盘在下,小盘在上。天神说当这64个盘子全部移到第三根柱子上后,世界末日就要到了。试编程实现Hanoi塔上盘子的移动步骤。

函数的递归调用 解题思路:该问题没有明显的递推规律,因此解决问题关键是找出递归函数的定义方式。如果只有一个盘子,只需要将该盘子从A移动到C即可。如果有多于一个盘子,最终的目标是将这个盘子从A移动到C,并且仍然按照原来的大小顺序。因此需要将A柱上最大的盘子移动到C柱上最下面,这就需要将上面的盘子移动到B柱上。即移动需要分为三步:(1)将上面的个盘子借助C柱移动到B柱,将最大的盘子从A柱移动到C柱,将B柱上的个盘子借助A柱移动到C柱。

函数的递归调用 #include <stdio.h> void hanoi(int n, char a, char b, char c); int main(){ int n; printf("请输入要移动的盘子数: "); scanf("%d", &n); hanoi(n, 'A','B','C'); return 0; } void hanoi(int n, char a, char b, char c){ if (n==1) printf("%c---->%c\n",a,c); else{ hanoi(n-1, a, c, b); hanoi(n-1, b, a, c); }

基本内容 概述 函数的定义与调用 参数的传递 函数的嵌套与递归调用 全局变量与局部变量 变量的存储方式 本章小结

全局变量与局部变量 在不同位置定义的变量,其作用域是不同的。例如,有的变量是在函数内部定义的,当函数被调用时,该变量被分配存储空间,而当函数调用结束后,该变量所占的存储空间被编译系统收回,此时再引用该变量就会出现编译错误。因此,C语言中的变量有着不同的作用域和生存周期。根据变量的作用域,可以将变量分为全局变量和局部变量;根据变量的生存周期,可以将变量分为静态存储方式与动态存储方式。

全局变量与局部变量 所谓变量的作用域,指的是变量的空间有效性。如果一个变量是在函数内部定义的,则该变量是局部变量。如果变量是在函数外部定义的,称该变量为全局变量。全局变量与局部变量的主要区别有: (1)全局变量在程序开始时分配存储空间,在程序结束时释放;局部变量在函数被调用时分配存储空间,在函数调用结束时释放存储空间。 (2)局部变量只在定义该变量的函数内部有效,不能在函数外部引用该变量;而全局变量在定义后可以在程序的所有地方引用。 (3)对局部变量而言,只能在定义该变量的函数内部对其进行修改;而全局变量在定义以后,程序的任何地方都可以修改。 (4)若不给变量初始化,全局变量的初值为0(数值型数据),局部变量的初值为任意值。

全局变量与局部变量

全局变量与局部变量 例5-18 写出下列程序的运行结果。 #include <stdio.h> int n=5; void test(){ int n=3; //此时的n为局部变量 n=n+1; //修改局部变量的值 printf("local variable:n=%d\n",n); } int main(){ n++; //修改全局变量的值 printf("global variable:n=%d\n",n); test(); return 0;

基本内容 概述 函数的定义与调用 参数的传递 函数的嵌套与递归调用 全局变量与局部变量 变量的存储方式 本章小结

变量的存储方式 根据变量的时间有效性,变量可以分为静态存储方式和动态存储方式。静态存储方式,是指在程序运行期间由系统分配固定的存储空间的方式,而动态存储方式,是指在程序运行期间根据需要进行动态的分配存储空间的方式。当一个C语言程序编译完成后,内存中将会为编译好的程序分配一部分存储空间。一般地,这部分存储空间可以分为三部分: (1)程序区:存放编译好的程序代码; (2)静态存储区:用来存储全局变量,当程序开始运行时为全局变量分配存储空间,程序运行结束时释放; (3)动态存储区:用来存放局部变量、函数调用的返回地址等。当函数调用结束后,这些存储空间将被自动释放。

变量的存储方式——自动变量 自动变量是C语言中变量和函数默认的存储类别,它的特点是:在函数调用时为其分配存储空间,在调用完成后自动释放这些存储空间。 auto 数据类型 变量名; #include <stdio.h> int main() { int a,b; auto int c; printf("请输入两个整数: "); scanf("%d%d",&a,&b); c=a+b; printf("%d+%d=%d\n",a,b,c); return 0; } int a; auto int a;

变量的存储方式——静态(static)变量 静态变量与局部变量的区别在于当函数调用结束后,动态变量所占的存储空间被释放,而静态变量所占的存储空间不被释放,因而局部变量的值得以保留,在下一次调用该函数时,该局部变量的初始值为上一次调用结束时的值。 static 数据类型 变量名;

变量的存储方式——静态(static)变量 #include <stdio.h> int main(){ int f(int); int i; for(i=0;i<2;i++) printf("result=%d\n",f(i)); return 0; } int f(int a){ static int b=3; b++; return a+b;

变量的存储方式——静态(static)变量 例5-20 编程计算从整数1到输入的整数m的阶乘。 解题思路:由于1!=1,2!=2*1!,…,m!=m*(m-1)!,所以定义fac函数。函数中定义静态局部变量f,并赋初值为1,表示求得的某个数的阶乘。多次调用该函数,每调用一次,f保留上一次得到的值,而参数的值是从1到m。 #include <stdio.h> int main(){ int fac(int); int i,m, result; printf("请输入一个整数: "); scanf("%d",&m); for(i=1;i<=m;i++) printf("%d!=%d\n", i, fac(i)); return 0; } int fac(int n){ static int f=1; f=f*n; return f; }

变量的存储方式——静态(static)变量 (1)静态变量存储在静态存储区,每次函数调用后不释放所占用的存储空间,因此静态变量的值得以保留;而自动变量存储在动态存储区,每次函数调用后需要释放所占用的存储空间; (2)静态存储变量只进行一次初始化操作,在后续的调用过程中将不再进行静态变量的初始化工作;而在函数的每一次调用时都需要对自动变量进行初始化。如果静态变量不进行初始化,其初始值为0或者为空字符,而自动变量如果不进行初始化,它的值是不确定的; (3)静态变量从本质上仍然属于局部变量,因此除了定义它的函数可以引用它以外,其它函数并不能引用它或者对它的值进行修改; (4)由于静态变量需要一直占用程序的存储空间,同时会降低程序的可读性,因此在编写程序中,不提倡使用静态变量。

变量的存储方式——寄存器(register)变量 在计算机运行程序时,所有的变量都要放到CPU内部的寄存器中。由于CPU内部的寄存器数量是有限的,因此需要频繁地在内存和寄存器之间进行数据的存取。考虑到寄存器中数据的操作速度远高于内存中数据的操作速度,因此经常把使用频繁的局部变量声明为寄存器变量,将其存储在CPU的寄存器中,这样可以有效提高程序的运行效率。这样的变量称为寄存器变量。 register 数据类型 变量名;

变量的存储方式——寄存器(register)变量 例5-21 求n!,当n的值很大时,可以把循环变量作为寄存器变量,以节省程序的执行时间。 #include <stdio.h> int main() { int n; register int i,f; f=1; scanf("%d", &n); for(i=1;i<=n;i++) f=f*i; printf("%d!=%d.\n", n,f); return 0; } (1)由于计算机中寄存器的数量是有限的,因此不能定义任意多个寄存器; (2)只有自动变量和形式参数可以定义为寄存器变量,静态局部变量不能定义为寄存器变量。

变量的存储方式——外部(extern)变量 在程序中,全局变量的作用域是从定义它的位置开始,到整个程序结束。如果想在定义全局变量前的函数中引用这些变量,需要对全局变量进行声明,声明该全局变量为“外部变量”,表明该变量是一个已经定义的外部变量。 extern 数据类型 变量名;

变量的存储方式——外部(extern)变量 #include <stdio.h> int f(int, int); int main(){ extern int a,b; //对外部变量进行声明 printf("%d和%d的和是%d.\n", a,b,f(a,b)); return 0; } int a=12, b=23; int f(int x, int y){ return x+y;

变量的存储方式——外部(extern)变量 当一个C程序由多个文件组成时,也可以利用extern在一个文件中引用另一个文件中定义的外部变量。 #include <stdio.h> int x; //对函数进行外部函数声明 extern int pow(int m); int main() { int y,n; printf("输入两个整数x和n:\n"); scanf("%d%d",&x,&n); y=pow(n); printf("%d^%d=%d\n",x,n,y); return 0; } extern x; //对x进行外部变量声明 int pow(int n) { int result=1; int i; for(i=0;i<n;i++) result=result*x; return result; }

基本内容 概述 函数的定义与调用 参数的传递 函数的嵌套与递归调用 全局变量与局部变量 变量的存储方式 本章小结

本章小结 本章介绍了函数的定义、调用及函数的声明; 本章介绍了函数的值传递和地址传递两种方式; 本章介绍了函数的嵌套调用与递归调用; 本章介绍了全局变量和局部变量在程序中的作用; 本章介绍了变量的生存周期,介绍了自动变量、静态变量、寄存器变量和外部变量。

本章小结 本章结束