本章的主要内容包括:
C语言函数的概念,如何调用 C提供的库函数,如何自己来定义函数,并调用这些函数 。 中的数据表示
多文件组成 C程序的方法
变量生存期作用域
C语言的数学函数 。
第四章 函数和程序结构回首页问题,( 1) 程序越来越长 。 难于理解且可读性下降 。
( 2) 重复代码增多,某段程序可能被执行多次 。
( 3) 某一问题中的代码,无法在其它同类问题中再用 。
必须重复原来的设计编码过程 。
函数是一种机制,能够有效地分解复杂的描述,控制程序规模和复杂性 。 需要抽象成函数的程序段:
( 1) 功能独立,具有独立逻辑意义的程序段
( 2) 重复出现的代码段函数机制提供的好处:
( 1) 函数可以被多次调用,减少程序长度,保持函数意义的一致性 。
( 2) 增加程序可读性 。
( 3) 模块化,结构化更强 。
两种观点:
从函数外部调用者的角度 。
从函数内部实现者的角度 。
4.1概述
C 程序中调用库函数需要两步:
1,使用 include命令指出关于库函数的相关定义和说明 。 include
命令必须以,#”开头,系统提供的头文件以,h作为文件后缀,
文件名用一队尖括号 <>或一对双撇号,” 括起来 。 # include
开头的程序行不是 C语句,末尾不加,;,号 。
2,调用标准库函数调用库函数的形式为:
函数名 (参数表 )
( 1) 表达式中调用:函数是表达式的一个运算对象 。
如 y = z*sin(x)+0.5;
( 2) 作为独立语句:可看作表达式语句如 printf(“%d\n”,a);
4.2 库函数
C语言中定义函数的一般形式为:
函数返回值类型名 函数名 (类型名 形参 1,类型名 形参 2… )
/* 头部 */
{ 说明部分 /* 函数体 */
语句部分
}
return语句的形式如下:
return 表达式; 或 return (表达式 );或 return ;
return的作用:退出函数,并带回函数值 。
4.3 函数定义
4.4.1 函数的调用函数调用的形式为:
函数名 (实际参数列表 )
调用函数时要注意以下几点:
( 1) 调用名字必须与定义名字完全一致 。
( 2) 实参个数与形参个数一致,类型一致,如不匹配,进行自动转换,不兼容的赋值转换 ( 某些类型之间不能进行赋值,如指针和浮点类型之间 ) 并不给出错信息,程序继续运行,但结果不正确 。
( 3) 可以嵌套调用 。 如 a函数调用 b函数,b函数中又调用 c函数 。
C语言规定所有的函数都是互相平行,独立的 。 不容许嵌套定义
( 在一个函数的定义中,包含另一个函数的完整定义 ),但可以嵌套调用 。
4.4 函数的调用和说明
4.4.2 函数说明在调用之前对函数进行说明,称为函数的原型说明 。
形式如下:
类型名 函数名 ( 参数类型列表或参数列表 ) ;
形式上可理解为函数定义的首部加分号,;,,它的作用是检查调用时参数的个数和类型正确与否 。 因此参数列表中,只需类型名即可,如有形参名,可以是任意的用户标识符,不一定要和函数定义的形参相同 。
4.4 函数的调用和说明
C语言中,调用函数和被调函数之间的数据传递有三种方式:
( 1) 实参和形参之间数据传递
( 2) return 语句把函数值返回调用函数 。
( 3) 通过全局变量 。 ( 全局变量在本章稍后讨论 )
C语言中实参和形参之间数据传递的方式叫,值传递,,数据只能从实参单向传递给形参 。 函数调用时,首先计算实参表达式的值,
求出的值分别赋给对应的形参,进入函数体执行,形参本身就是局部于函数的变量,调用时接收实参的值 。 函数内部对形参的赋值与实参变量毫无关系 。 实参变量的值不会被改变 。 实参与形参传递值时,隐含着可能的转换 。 如转换不能进行,编译时产生类型错误 。
C的函数调用机制很简单,值传递是 C语言实参形参结合的唯一方法,
续章节中,我们会看到数组名和指针做函数参数的情形,它们进行实参形参结合的方式离不开值传递这个本质 。
4.5 调用函数和被调函数的数据传递递归函数是指在函数执行过程中,直接或间接调用函数本身的函数 。 前者称简单递归,后者称间接递归 。
递归程序的执行过程递归函数的特点:有一个明确的结束递归的条件 。
递归函数的效率递归与递推的关系
4.7 函数实例
4.6 递归函数
4.8.1 程序结构
C语言规定部不允许在一个函数的内部定义另一个函数,这样,所有函数都定义在程序的表层,整个程序的结构比较简单 。
程序结构讨论 C程序函数及数据,变量定义的组织方法,尤其是需要多个文件组织程序时的程序单元,内容的组织问题 。
4.8.2 变量的作用域和存在期在程序中定义一个变量时有几个方面的含义:
( 1) 给变量一个名字,在程序中通过名字可以操作该变量的存储空间,进行取值和赋值;
( 2) 定义了该变量存储空间中数据的存在形式,范围和运算;
( 3) 程序中哪些地方可以使用该变量;
( 4) 程序运行过程中,该变量的存储空间什么时候分配和撤消 。
4.8 变量的作用域和生存期
4.8.2 变量的作用域和存在期变量的作用域:源程序中的某一部分,在这个范围里,变量定义是有效的,可以使用该变量的名字进行与该变量有关的操作每个变量都有一个确定,作用域,,由变量定义出现的位置确定 。
作用域讲变量的作用范围,一个定义的作用域是源程序中的一段,
可以从源程序正文中把有关的一段划出来 。 因此作用域是静态概念 。 与程序执行过程无干 。
存在期:变量在程序中存在的那段时期称为该变量的,” 。
存在期是动态概念 。 讲的是程序执行的一段时期,在一个变量的存在期里,它所占的存储单元一直保持,只要不对变量重新赋值,单元中的值就保持不变 。
内存中供程序使用的存储空间分为三部分:
程序区,静态存储区和动态存储区 。
4.8 变量的作用域和生存期
4.8.2 变量的作用域和存在期存储类别指的是变量在内存中的存储位置,有静态和动态两种存储类别 。
具体有四种与存储类别有关的说明符:
auto( 自动 ) static( 静态 )
register( 寄存器 ) extern( 外部 )
这些说明符通常与类型名一起出现,可以放在类型名的左边,也可以放在类型名的右边 。 前三种存储类别的声明和定义连用,不能分开 。
4.8.2.1 全局变量的作用域和存在期在函数之外任意位置定义的变量,称全局变量,也叫外部变量 。 它的作用域为从定义变量的位置开始到本源文件结束 。
全局变量只有静态一种存储类别,它的存在期是整个程序的运行期间 。
讨论全局变量定义和使用时的注意事项讨论在不同的函数间使用同一个全局变量进行通信的特点及利弊 。
讨论使用 extern和 static两种说明符定义全局变量的不同点 。
4.8 变量的作用域和生存期
4.8.2 变量的作用域和存在期
4.8.2.2 局部变量的作用域和存在期局部变量是在一个函数内部或复合语句内部定义的变量,只在函数或复合语句体范围内有效,在此函数或复合语句体外不能使用这些变量 。
可以使用 auto( 自动 ),static( 静态 ),register( 寄存器 ) 说明符 。
1,auto变量局部变量定义时使用 auto说明符或没有指定存储类,系统就认为所定义的变量具有自动类别 。 系统对自动变量是动态分配存储空间的,数据存储在动态存储区中 。
局部变量的定义必须放在函数体或复合体中所有可执行语句之前 。
自动变量的作用域是从定义的位置起,到函数体或复合体结束为止 。 它的存储单元在进入这些局部变量所在的函数体 (或复合体 )时生成,退出其所在函数体 (或复合体 )时消失,这就是自动变量的存在期 。 当再次进入函数体 (或复合体 )时,系统将为它们另行分配存储单元,因此,
变量的值不可能被保留 。
讨论使用自动变量的优点 。
4.8 变量的作用域和生存期
4.8.2 变量的作用域和存在期
4.8.2.2 局部变量的作用域和存在期
2,register 变量寄存器变量也是自动变量,它与自动变量的区别仅在于:用 register说明的变量建议编译程序将变量的值保留在 CPU的寄存器中,而不象一般变量那样,占内存单元 。 局部变量的定义必须放在函数体或复合体中所有可执行语句之前 。
讨论寄存器变量的特点和使用注意事项 。
3,static变量在函数体 ( 或复合体 ) 内部用 static说明的变量,称静态局部变量 。 静态局部变量的作用域和自动变量,寄存器变量一样,但其存在期与它们有本质的区别,要一直延长到程序运行结束 。
静态局部变量在静态存储区占据永久性的存储单元,函数退出后下次再进入该函数,静态局部变量仍使用原来的存储单元 。
讨论静态变量的特点和使用注意事项
4.8 变量的作用域和生存期外部变量,静态变量 ( 存储在静态存储区 ) 的定义在程序开始前已经完成,其初始化也在程序执行前完成,且只进行一次 。
对初始化表达式有严格的限制,只能使用不需要执行程序 ( 在编译阶段 ) 就能求出一个常量值的表达式 。
对外部变量,静态变量进行初始化的方法是:直接用字面量或用字面量,符号常量及基本运算符号构造表达式 。 不能包括各种涉及赋值的运算 ( 如 ++,--等 ) 。 如果在定义时不写初始化,
则系统建立时自动初始化为 0。
对存储在动态存储区的局部变量来说,其存储单元是程序执行过程中在调用对应函数或复合体时动态分配的,对初始化表达式形式没有限制,符合类型约束即可 。
由于每次调用后存储单元已释放,下次调用时又重新另分配存储单元,因此,每次建立时均需重新初始化 。 如果定义时不写初始化,所分配单元中的值是不确定的 。 此时,程序在使用该变量前,一定要有使变量存储单元赋值的操作,否则,变量的值是不确定的 。 许多编译系统对这类问题会提出警告 。
4.8.3 变量初始化讨论内部函数和外部函数的特点 。
使用 extern和 static说明符的方法 。
使用内部函数和外部函数的好处 。
4.9多文件程序的组织和调试方法
4.9.1多文件程序的组织方法讨论教材中关于多文件程序组织方法的 5点指导意见
4.9.2多文件程序的运行调试方法
( 1) 编辑源文件
( 2) 建立项目文件
( 3) 打开项目文件
( 4) 编译连接
( 5) 执行
4.8.4 内部函数和外部函数第四章 函数和程序结构本章主要知识点:
C语言关于函数的规定 。 定义方法,说明规定,返回值,函数返回和函数调用 。
函数之间参数传递的规定 。 形参与实参的对应关系,参数传递方式,
void型函数 。
变量的存储类型 。 变量存在期与作用域的概念,4种存储变量类型的说明方式,特点和使用范围,不同存储类型变量在使用时的区别,变量的初始化方法,在函数间使用外部变量传递数据的规定 。
多文件程序的组织和实现方法
常见库函数的使用方法 。
掌握本章内容的关键是理解函数的参数传递机制及变量作用域和存在期的概念 。 回本章首页
C语言函数的概念,如何调用 C提供的库函数,如何自己来定义函数,并调用这些函数 。 中的数据表示
多文件组成 C程序的方法
变量生存期作用域
C语言的数学函数 。
第四章 函数和程序结构回首页问题,( 1) 程序越来越长 。 难于理解且可读性下降 。
( 2) 重复代码增多,某段程序可能被执行多次 。
( 3) 某一问题中的代码,无法在其它同类问题中再用 。
必须重复原来的设计编码过程 。
函数是一种机制,能够有效地分解复杂的描述,控制程序规模和复杂性 。 需要抽象成函数的程序段:
( 1) 功能独立,具有独立逻辑意义的程序段
( 2) 重复出现的代码段函数机制提供的好处:
( 1) 函数可以被多次调用,减少程序长度,保持函数意义的一致性 。
( 2) 增加程序可读性 。
( 3) 模块化,结构化更强 。
两种观点:
从函数外部调用者的角度 。
从函数内部实现者的角度 。
4.1概述
C 程序中调用库函数需要两步:
1,使用 include命令指出关于库函数的相关定义和说明 。 include
命令必须以,#”开头,系统提供的头文件以,h作为文件后缀,
文件名用一队尖括号 <>或一对双撇号,” 括起来 。 # include
开头的程序行不是 C语句,末尾不加,;,号 。
2,调用标准库函数调用库函数的形式为:
函数名 (参数表 )
( 1) 表达式中调用:函数是表达式的一个运算对象 。
如 y = z*sin(x)+0.5;
( 2) 作为独立语句:可看作表达式语句如 printf(“%d\n”,a);
4.2 库函数
C语言中定义函数的一般形式为:
函数返回值类型名 函数名 (类型名 形参 1,类型名 形参 2… )
/* 头部 */
{ 说明部分 /* 函数体 */
语句部分
}
return语句的形式如下:
return 表达式; 或 return (表达式 );或 return ;
return的作用:退出函数,并带回函数值 。
4.3 函数定义
4.4.1 函数的调用函数调用的形式为:
函数名 (实际参数列表 )
调用函数时要注意以下几点:
( 1) 调用名字必须与定义名字完全一致 。
( 2) 实参个数与形参个数一致,类型一致,如不匹配,进行自动转换,不兼容的赋值转换 ( 某些类型之间不能进行赋值,如指针和浮点类型之间 ) 并不给出错信息,程序继续运行,但结果不正确 。
( 3) 可以嵌套调用 。 如 a函数调用 b函数,b函数中又调用 c函数 。
C语言规定所有的函数都是互相平行,独立的 。 不容许嵌套定义
( 在一个函数的定义中,包含另一个函数的完整定义 ),但可以嵌套调用 。
4.4 函数的调用和说明
4.4.2 函数说明在调用之前对函数进行说明,称为函数的原型说明 。
形式如下:
类型名 函数名 ( 参数类型列表或参数列表 ) ;
形式上可理解为函数定义的首部加分号,;,,它的作用是检查调用时参数的个数和类型正确与否 。 因此参数列表中,只需类型名即可,如有形参名,可以是任意的用户标识符,不一定要和函数定义的形参相同 。
4.4 函数的调用和说明
C语言中,调用函数和被调函数之间的数据传递有三种方式:
( 1) 实参和形参之间数据传递
( 2) return 语句把函数值返回调用函数 。
( 3) 通过全局变量 。 ( 全局变量在本章稍后讨论 )
C语言中实参和形参之间数据传递的方式叫,值传递,,数据只能从实参单向传递给形参 。 函数调用时,首先计算实参表达式的值,
求出的值分别赋给对应的形参,进入函数体执行,形参本身就是局部于函数的变量,调用时接收实参的值 。 函数内部对形参的赋值与实参变量毫无关系 。 实参变量的值不会被改变 。 实参与形参传递值时,隐含着可能的转换 。 如转换不能进行,编译时产生类型错误 。
C的函数调用机制很简单,值传递是 C语言实参形参结合的唯一方法,
续章节中,我们会看到数组名和指针做函数参数的情形,它们进行实参形参结合的方式离不开值传递这个本质 。
4.5 调用函数和被调函数的数据传递递归函数是指在函数执行过程中,直接或间接调用函数本身的函数 。 前者称简单递归,后者称间接递归 。
递归程序的执行过程递归函数的特点:有一个明确的结束递归的条件 。
递归函数的效率递归与递推的关系
4.7 函数实例
4.6 递归函数
4.8.1 程序结构
C语言规定部不允许在一个函数的内部定义另一个函数,这样,所有函数都定义在程序的表层,整个程序的结构比较简单 。
程序结构讨论 C程序函数及数据,变量定义的组织方法,尤其是需要多个文件组织程序时的程序单元,内容的组织问题 。
4.8.2 变量的作用域和存在期在程序中定义一个变量时有几个方面的含义:
( 1) 给变量一个名字,在程序中通过名字可以操作该变量的存储空间,进行取值和赋值;
( 2) 定义了该变量存储空间中数据的存在形式,范围和运算;
( 3) 程序中哪些地方可以使用该变量;
( 4) 程序运行过程中,该变量的存储空间什么时候分配和撤消 。
4.8 变量的作用域和生存期
4.8.2 变量的作用域和存在期变量的作用域:源程序中的某一部分,在这个范围里,变量定义是有效的,可以使用该变量的名字进行与该变量有关的操作每个变量都有一个确定,作用域,,由变量定义出现的位置确定 。
作用域讲变量的作用范围,一个定义的作用域是源程序中的一段,
可以从源程序正文中把有关的一段划出来 。 因此作用域是静态概念 。 与程序执行过程无干 。
存在期:变量在程序中存在的那段时期称为该变量的,” 。
存在期是动态概念 。 讲的是程序执行的一段时期,在一个变量的存在期里,它所占的存储单元一直保持,只要不对变量重新赋值,单元中的值就保持不变 。
内存中供程序使用的存储空间分为三部分:
程序区,静态存储区和动态存储区 。
4.8 变量的作用域和生存期
4.8.2 变量的作用域和存在期存储类别指的是变量在内存中的存储位置,有静态和动态两种存储类别 。
具体有四种与存储类别有关的说明符:
auto( 自动 ) static( 静态 )
register( 寄存器 ) extern( 外部 )
这些说明符通常与类型名一起出现,可以放在类型名的左边,也可以放在类型名的右边 。 前三种存储类别的声明和定义连用,不能分开 。
4.8.2.1 全局变量的作用域和存在期在函数之外任意位置定义的变量,称全局变量,也叫外部变量 。 它的作用域为从定义变量的位置开始到本源文件结束 。
全局变量只有静态一种存储类别,它的存在期是整个程序的运行期间 。
讨论全局变量定义和使用时的注意事项讨论在不同的函数间使用同一个全局变量进行通信的特点及利弊 。
讨论使用 extern和 static两种说明符定义全局变量的不同点 。
4.8 变量的作用域和生存期
4.8.2 变量的作用域和存在期
4.8.2.2 局部变量的作用域和存在期局部变量是在一个函数内部或复合语句内部定义的变量,只在函数或复合语句体范围内有效,在此函数或复合语句体外不能使用这些变量 。
可以使用 auto( 自动 ),static( 静态 ),register( 寄存器 ) 说明符 。
1,auto变量局部变量定义时使用 auto说明符或没有指定存储类,系统就认为所定义的变量具有自动类别 。 系统对自动变量是动态分配存储空间的,数据存储在动态存储区中 。
局部变量的定义必须放在函数体或复合体中所有可执行语句之前 。
自动变量的作用域是从定义的位置起,到函数体或复合体结束为止 。 它的存储单元在进入这些局部变量所在的函数体 (或复合体 )时生成,退出其所在函数体 (或复合体 )时消失,这就是自动变量的存在期 。 当再次进入函数体 (或复合体 )时,系统将为它们另行分配存储单元,因此,
变量的值不可能被保留 。
讨论使用自动变量的优点 。
4.8 变量的作用域和生存期
4.8.2 变量的作用域和存在期
4.8.2.2 局部变量的作用域和存在期
2,register 变量寄存器变量也是自动变量,它与自动变量的区别仅在于:用 register说明的变量建议编译程序将变量的值保留在 CPU的寄存器中,而不象一般变量那样,占内存单元 。 局部变量的定义必须放在函数体或复合体中所有可执行语句之前 。
讨论寄存器变量的特点和使用注意事项 。
3,static变量在函数体 ( 或复合体 ) 内部用 static说明的变量,称静态局部变量 。 静态局部变量的作用域和自动变量,寄存器变量一样,但其存在期与它们有本质的区别,要一直延长到程序运行结束 。
静态局部变量在静态存储区占据永久性的存储单元,函数退出后下次再进入该函数,静态局部变量仍使用原来的存储单元 。
讨论静态变量的特点和使用注意事项
4.8 变量的作用域和生存期外部变量,静态变量 ( 存储在静态存储区 ) 的定义在程序开始前已经完成,其初始化也在程序执行前完成,且只进行一次 。
对初始化表达式有严格的限制,只能使用不需要执行程序 ( 在编译阶段 ) 就能求出一个常量值的表达式 。
对外部变量,静态变量进行初始化的方法是:直接用字面量或用字面量,符号常量及基本运算符号构造表达式 。 不能包括各种涉及赋值的运算 ( 如 ++,--等 ) 。 如果在定义时不写初始化,
则系统建立时自动初始化为 0。
对存储在动态存储区的局部变量来说,其存储单元是程序执行过程中在调用对应函数或复合体时动态分配的,对初始化表达式形式没有限制,符合类型约束即可 。
由于每次调用后存储单元已释放,下次调用时又重新另分配存储单元,因此,每次建立时均需重新初始化 。 如果定义时不写初始化,所分配单元中的值是不确定的 。 此时,程序在使用该变量前,一定要有使变量存储单元赋值的操作,否则,变量的值是不确定的 。 许多编译系统对这类问题会提出警告 。
4.8.3 变量初始化讨论内部函数和外部函数的特点 。
使用 extern和 static说明符的方法 。
使用内部函数和外部函数的好处 。
4.9多文件程序的组织和调试方法
4.9.1多文件程序的组织方法讨论教材中关于多文件程序组织方法的 5点指导意见
4.9.2多文件程序的运行调试方法
( 1) 编辑源文件
( 2) 建立项目文件
( 3) 打开项目文件
( 4) 编译连接
( 5) 执行
4.8.4 内部函数和外部函数第四章 函数和程序结构本章主要知识点:
C语言关于函数的规定 。 定义方法,说明规定,返回值,函数返回和函数调用 。
函数之间参数传递的规定 。 形参与实参的对应关系,参数传递方式,
void型函数 。
变量的存储类型 。 变量存在期与作用域的概念,4种存储变量类型的说明方式,特点和使用范围,不同存储类型变量在使用时的区别,变量的初始化方法,在函数间使用外部变量传递数据的规定 。
多文件程序的组织和实现方法
常见库函数的使用方法 。
掌握本章内容的关键是理解函数的参数传递机制及变量作用域和存在期的概念 。 回本章首页