程序设计专题一 结构化程序设计与递归函数 主讲教师: 刘新国.

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

C语言程序设计 主讲教师 :张群燕 电话:
第一章 C语言概述 计算机公共教学部.
Oracle数据库 Oracle 子程序.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
全国计算机等级考试 二级基础知识 第二章 程序设计基础.
C语言程序设计 第八章 函数.
高级语言程序设计 主讲人:陈玉华.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
Chap 10 函数与程序结构 10.1 函数的组织 10.2 递归函数 10.3 宏定义 10.4 编译预处理.
第13章 编译预处理 宏定义 文件包含 条件编译.
STRUCTURE 授課:ANT 日期:2010/5/12.
Function.
程序设计专题一 结构化程序设计与递归函数 主讲教师: 刘新国.
管理信息结构SMI.
走进编程 程序的顺序结构(二).
辅导课程六.
第7章 编译预处理 本章要求: 本章重点: 本章难点: 掌握用#define定义无参数宏和带有参数宏定义和调用方法;
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
THE C PROGRAMMING LANGUAGE
第二章 Java语言基础.
2.1 C语言的数据类型 2.2 常量与变量 2.3 变量赋初值 2.4 各类数值型数据间的混合运算 2.5 C语言的运算符和表达式
第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归
第九章 预处理命令.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
1.3 C语言的语句和关键字 一、C语言的语句 与其它高级语言一样,C语言也是利用函数体中的可执行 语句,向计算机系统发出操作命令。按照语句功能或构成的不 同,可将C语言的语句分为五类。 goto, return.
C语言程序设计 主讲教师:陆幼利.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
C语言概述 第一章.
第1讲 C语言基础 要求: (1) C程序的组成 (2) C语言的标识符是如何定义的。 (3) C语言有哪些基本数据类型?各种基本数
$9 泛型基础.
第 二 章 数据类型、运算符与表达式.
第1章 c++概述 1.1 C++语言的简史及特点 1.2 简单的C++程序 1.3 C++语言的基本组成
Chap 10 函数与程序结构 10.1 函数的组织 10.2 递归函数.
Oop8 function函式.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
Chap 5 函数 5.1 计算圆柱体积 5.2 使用函数编写程序 5.3 变量与函数.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
C程序设计.
第4章 Excel电子表格制作软件 4.4 函数(一).
C语言程序设计 李祥 QQ:
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第3章 数据类型、运算符与表达式.
第九节 赋值运算符和赋值表达式.
第2章 数据类型、运算符与表达式 本章要点: 基本数据类型 常量和变量 算术运算符和算术表达式 关系运算符和关系表达式
第二章 类型、对象、运算符和表达式.
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第2章 数据类型与表达式 学习目的与要求: 掌握C 语言的基本数据类型及使用方法 掌握C程序中常用的运算符和表达式 了解数据类型的转换.
第二章 基本数据类型 ——数据的表示.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
第9章 预处理命令.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
本节内容 指针类型.
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Python 环境搭建 基于Anaconda和VSCode.
本节内容 结构体.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第二章 数据类型、运算符和表达式 §2.1 数据与数据类型 §2.2 常量、变量和标准函数 §2.3 基本运算符及其表达式 目 录 上一章
第18讲 从C到C++ 计算机与通信工程学院.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
Chap 10 函数与程序结构 10.1 圆形体积计算器 10.2 汉诺塔问题 10.3 长度单位转换 10.4 大程序构成.
<编程达人入门课程> 本节内容 有符号数与无符号数 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
本节内容 指针类型 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Presentation transcript:

程序设计专题一 结构化程序设计与递归函数 主讲教师: 刘新国

专题要点 用结构化程序设计的思想解决问题 将多个函数组织起来,将多个源程序文件组织起来 理解程序设计规范及其重要性 函数嵌套求解复杂的问题 理解和使用函数递归 类型定义与宏定义 编译预处理

程序结构 main( ) 函数1 函数2 …… 函数m 函数1_1 函数1_2 函数m_1 函数m_n

函数定义 好的函数名字:描述函数所做的所有事情。如: 一个函数只实现一个功能 函数参数: checkOrderInfo(...) calcMonthlyRevenues(...) 一个函数只实现一个功能 函数参数: 按照输入-修改-输出的顺序排列参数 考虑对参数采用某种表示输入、修改、输出的命名规则 使用所有的参数 把状态或出错变量放在最后 不要把函数的参数用作工作变量 在接口中对参数的假定加以说明 尽可能少的参数(限制在大约7个以内)

2. 源程序文件组织 .c文件:实现文件 .h文件:自定义的头文件 一个程序通常包含多个.c和.h文件 函数实现 全局变量定义 类型定义,函数说明 一个程序通常包含多个.c和.h文件 几个到几千个 系统越大越复杂,文件越多

头文件( .h 文件) 为了方便模块函数被其他模块调用,编写头文件,保存: 正确使用头文件可提高代码的可读性、可维护性、以及开发效率 宏定义 常量定义 数据类型定义 外部变量声明 函数声明(函数原型要求) 正确使用头文件可提高代码的可读性、可维护性、以及开发效率 在.c文件中通过命令包含.h头文件。例如: #include <stdio.h> #include "mydata.h" 包含自定义的头文件时,一般用" "

文件模块(.c文件) 编译单元 连接程序 在编译一个.c文件时,预处理器首先递归包含头文件,形成一个含有所有必要信息的单个源文件。 把各个目标程序中产生的符号联系起来,构成一个可执行程序。

模块编译链接 prog1.o 编译 prog1.c a1.h, …, b1.h prog2.c a2.h, …, c2.h progM.c a.h, b.h, c.h …… 链接 prog2.o 编译 可执行文件 progM.o …… 编译

头文件编写 头文件由三部分内容组成: 头文件应该只用于声明,不应该包含 版权声明和版本信息(起始处) 预处理块 定义和申明 结构和枚举类型定义 typedef定义和宏定义 具名常量定义 外部变量声明 函数申明 头文件应该只用于声明,不应该包含 “占据存储空间的变量或函数”的定义

包含(#include)头文件 头文件可以嵌套包含 避免循环包含(为什么),避免头文件被多重复包含 A.h包含B.h,B.h包含C.h,。。。 避免循环包含(为什么),避免头文件被多重复包含 虽然函数、变量的声明都可以重复,不会影响程序编译和运行,但会增加编译处理的时间 当头文件中包含结构的定义、枚举定义等一些定义时,这些定义是不可以重复的,必须通过一定措施防止发生

#define保护 #ifndef _HEADERNAME_H #define _HEADERNAME_H vecmat.h <头文件内容> #endif 注意宏定义_HEADERNAME_H 在模块中 必须是唯一的 不要重复 vecmat.h #ifndef _VEC_MAT_H #define _VEC_MAT_H typedef struct { float x, y, z; } vec; float m[3][3]; } mat; #endif // ifndef _VEC_MAT_H

编译预处理 编译器对源代码开始编译之前,首先对.c文件进行预处理 预处理指令 编译器通过预处理指令,对源代码做相应转换。 或者说,扫描源代码,对其进行初步的转换,生成新的源代码提供给编译器。 预处理指令 以#号开头的代码行 #号必须是该行除了空白字符外的第一个字符。 #号后是指令关键字 在关键字和#号之间允许存在任意个数的空白字符。 整行语句构成了一条预处理指令 编译器通过预处理指令,对源代码做相应转换。

常用的预处理指令 #include 文件包含指令 #define 宏定义指令 #undef 宏定义取消指令 条件编译指令 #ifdef/#ifndef <条件对应的代码> #endif #if表达式 <表达式非零时编译的代码> #else <否则编译的代码> #elif #error 停止编译预处理并输出错误信息 #include <stdio.h> #define _LIB_VERSION 2 #undef _linux #ifndef M_PI #define M_PI 3.1415926 #endif #if _LIB_VERSION ==2 <适合版本2的代码> #else <适合其他版本的代码> #error "Only support V 2"

#define保护 通过#define保护,当头文件被重复include的时候, 内容不会被重复include #ifndef _VEC_MAT_H #define _VEC_MAT_H typedef struct { float x, y, z; } vec; float m[3][3]; } mat; #endif // ifndef _VEC_MAT_H 通过#define保护,当头文件被重复include的时候, 内容不会被重复include <在同一个程序模块中不重复>

#define保护 保证了在编译一个c文件时,头文件的不被重复编译 在编译其他.c文件时,该头文件任然会被编译 因此,一般地,头文件中不能出现函数定义和变量的定义。 否则如果有多个c文件包含它时,仍然会编译生成重复的变量和函数定义。 重复的变量或函数定义会导致Link错误!

举例:不规范的头文件 // in header.h #ifndef _HEADER_H #define _HEADER_H extern void Foo1(); /*函数声明 */ extern int a1; /*外部变量声明 */ struct A; /*前置声明结构A */ int a2; //全局变量定义,应当避免 void Foo2() //函数定义,应当避免 {} typedef struct /* 结构B定义 */ { int i; struct A m; }B; #endif 如果有多个程序模块文件,例如A.c和B.c,他们都include了该头文件。那么当他们被分别编译的,都生成了一份全局变量a2和函数Foo2。编译是ok的,但是在Link阶段,会出现重复定义的冲突,导致失败。

头文件的作用 通过头文件了解函数功能 通过头文件能加强类型安全检查 用户经常不能拿到源代码(涉密),但是可以拿到头文件和库文件(编译后的二进制文件)。 用户可以按照头文件中的(接口)函数声明,调用库函数,而不必关心接口怎么实现的。 编译器会从库中提取相应的二进制代码。 例如我们使用printf,scanf标准库函数 通过头文件能加强类型安全检查 如果某个接口/函数被实现或被使用时,其方式与头文件中的声明不一致,编译器就会报错 该简单规则能大大减轻程序员调试和改错负担

宏定义#define命令 #define 宏名标识符 宏定义字符串 说明: #define PI 3.14 编译时,把程序中所有与宏名相同的标识符,用宏定义字符串替代 说明: 宏名一般用大写字母,以与变量名区别 宏定义不是C语句,后面不得跟分号 宏定义可以嵌套使用 多用于符号常量、简单的操作和函数等 #define MAX(a, b) ((a)>(b) ? (a) : (b))

宏基本定义 宏定义可以写在程序中任何位置,它的作用范围从定义书写处到文件尾。 可以通过“#undef”强制指定宏的结束范围。

宏的作用范围 #define A “This is the first macro” void f1() { printf( “A\n” ); printf(“%s\n”, A); } #define B “This is the second macro” A 的有效范围 void f2( ) printf( B ) ; B 的有效范围 #undef B int main(void) f1( ); f2( ); return 0;

x*x z+x*z+x x>y ? x : y 10.3.2 带参数的宏定义 10.3.2 带参数的宏定义 #define MAX(a,b) a>b ? a : b #define SQR(x) x*x … int x, y, z x = MAX(x,y); y = SQR(x); y = SQR(z+x); x>y ? x : y x*x z+x*z+x

(x)*(x) (z+x)*(z+x) 10.3.2 带参数的宏定义 建议使用(),减少麻烦 (x)>(y) ? (x) : (y) 10.3.2 带参数的宏定义 建议使用(),减少麻烦 #define MAX(a,b) (a)>(b) ? (a) : (b) #define SQR(x) (x)*(x) … int x, y, z x = MAX(x,y); y = SQR(x); y = SQR(z+x); (x)>(y) ? (x) : (y) (x)*(x) (z+x)*(z+x)

用宏实现两个变量的交换 #define f(a, b, t) (t)=(a),(a)=(b),(b)=(t) void main( void ) { int x,y,t ; scanf(“%d%d”, &x, &y); f(x,y,t);/*使用宏*/ printf(“%d %d\n”, x, y) ; } (t)=(x),(x)=(y),(y)=(t);

嵌套的宏定义与调用 #define F(x) x - 2 #define D(x) x*F(x) void main() { printf("%d,%d", D(3), D(D(3))) ; }

嵌套的宏定义与调用 #define F(x) x - 2 #define D(x) x*F(x) 计算 D(3), D(D(3)) 先全部替换好,最后再统一计算 不可一边替换一边计算,更不可以人为添加括号 D(3) = 3*F(3) = 3*3-2 = 7 D(D(3)) = D(3)*F(D(3)) = 3*F(3)*D(3)-2 = 3*3-2*3*F(3)-2 = 3*3-2*3*3-2-2 = -13

宏定义应用示例 判断字符c是否为小写字母。 将数字字符(‘0’~‘9’)转换为相应的十进制整数,-1表示出错。 最大值、最小值 #define LOWCASE(c) (((c) >= 'a') && ((c) <= 'z') ) 将数字字符(‘0’~‘9’)转换为相应的十进制整数,-1表示出错。 #define CTOD(c) (((c) >= '0') && ((c) <= '9') ? c - '0' : -1) 最大值、最小值 #define MAX(a,b) ((a) >= (b) ? (a) : (b)) #define MIN(a,b) ((a) <= (b) ? (a) : (b))

文件包含#include命令 为了避免一个文件过长,可以把程序组织为多个文件。 程序文件程序文件模块。 每一个文件包含若干个函数。 程序文件程序文件模块。 程序  文件  函数 各程序文件模块分别编译,再连接 整个程序只允许有一个main()函数

文件包含 格式 例如 作用 注意 #include <需包含的文件名> #include "需包含的文件名" #include <stdio.h> #include "myfunc.h" 作用 把被包含的文件内容插入到#include命令所在位置 注意 编译预处理命令,以#开头。 行尾没有分号。

[例10-7] 文件包含举例 文件length.h /* 1英里=1609米 */ #define mile_to_meter 1609 /* 1英尺=30.48厘米 */ #define foot_to_centimeter 30.48 /* 1英寸=2.54厘米 */ #define inch_to_centimeter 2.54

[例10-7] 文件包含举例 文件 prog.c #include <stdio.h> #include "length.h" void main() { float foot, inch, mile; printf("%f miles = %f\n", mile, mile*mile_to_meter); … }

.h头文件常规用法 统一的定义和声明 好处 宏定义 变量声明 函数申明 外部变量申明 自定义的数据类型(结构) 避免多次重复定义 避免不一致 方便维护和修改

常用标准头文件 ctype.h 字符处理 math.h 与数学处理函数有关的说明与定义 stdio.h 输入输出函数中使用的有关说明和定义 string.h 字符串函数的有关说明和定义 stddef.h 定义某些常用内容 stdlib.h 杂项说明 time.h 支持系统时间函数

10.3.5 编译预处理 编译预处理是C语言编译程序的组成部分,它用于解释处理C语言源程序中的各种预处理指令。 10.3.5 编译预处理 编译预处理是C语言编译程序的组成部分,它用于解释处理C语言源程序中的各种预处理指令。 文件包含(#include)和宏定义(#define)都是编译预处理指令 在形式上都以“#”开头,不属于C语言中真正的语句 增强了C语言的编程功能,改进C语言程序设计环境,提高编程效率

编译预处理 由于#define等编译预处理指令不是C语句,不能被编译程序翻译 需要在真正编译之前作一个预处理,解释完成编译预处理指令 从而把预处理指令转换成相应的C程序段,最终成为由纯粹C语句构成的程序 经编译最后得到目标代码。

编译预处理功能 编译预处理的主要功能: 文件包含(#include) 宏定义(#define) 条件编译

编译预处理功能 编译预处理的主要功能: 文件包含(#include) 宏定义(#define) 条件编译

条件编译 #define _flag 1 #define _flag 0 #if _flag 程序段1 #else 程序段2 #endif

条件编译 #define _zhongwen #ifdef _zhongwen #define msg "早上好" #else #define msg "Good morning" #endif … main() { printf(msg); }

条件编译(用于调试) #define _mydebug 0 #if _mydebug #define _dbg(x) (x) #else #define _dbg(x) #endif main() { int x; … _dbg(printf("%d",x); }

大程序构成 - 多文件模块 学生信息库系统 文件模块 student.h input_output.c aver_sort.c 建立 new_student() 输出 output_student() 计算平均成绩 average() 平均成绩排序 sort() 修改 modify() 查询 search_student() 文件模块 student.h input_output.c aver_sort.c modify.c student_system.c

大程序构成 - 多文件模块 用户头文件 - student.h #include<stdio.h> 宏定义,数据类型定义(结构) #include<stdio.h> #include<string.h> #define MaxSize 50 struct student { int num; char name[10]; int computer, english, math; float average; };

大程序构成 - 多文件模块 用户头文件 - student.h《续》 extern int count; 外部变量,外部函数 extern int count; void new_student(struct student students[]); void output_student(struct student students[]); void average(struct student students[]); void sort(struct student students[]); void modify(struct student students[]); void search_student(struct student students[], int num);

大程序构成 - 多文件模块 输入/出程序文件 – input_output.c #include "student.h" void new_student(struct student students[]) { … } void output_student(struct student students[])

大程序构成 - 多文件模块 计算平均成绩及排序文件 – aver_sort.c #include "student.h" void average(struct student students[]) { … } void sort(struct student students[])

大程序构成 - 多文件模块 查询和修改文件 – modify.c #include "student.h" void modify(struct student students[]) { … } void search_student(struct student students[], int num)

大程序构成 - 多文件模块 主函数程序– student_system.c #include "student.h" int count = 0; int main() { struct student students[MaxSize]; … /* 调用函数,实现功能*/ }

10.4.3 文件模块之间的沟通 外部变量 声明格式如下: extern 类型名 变量名; 例如: extern int count; 10.4.3 文件模块之间的沟通 外部变量 在文件A中使用文件B中定义的全局变量c的时候,需要在使用之前进行声明 声明格式如下: extern 类型名 变量名; 例如: extern int count; 如果不希望其他文件使用某个全局变量,那么需要将其定义为static类型的全局变量

10.4.3 文件模块之间的沟通 外部函数 声明格式如下: extern 类型名 函数名(参数类型表); 关键字 extern可以省略 10.4.3 文件模块之间的沟通 外部函数 在文件A中使用文件B中定义的函数f的时候,需要在使用之前进行声明 声明格式如下: extern 类型名 函数名(参数类型表); 关键字 extern可以省略 例如: void new_student(struct student students[]); void output_student(struct student students[]);

10.4.3 文件模块之间的沟通 静态函数 声明格式如下: static 类型名 函数名(参数类型表) { … } 10.4.3 文件模块之间的沟通 静态函数 如果不希望文件中的某个函数在其他的文件中调用,那么可以将其定义为静态的 也称作:内部函数 声明格式如下: static 类型名 函数名(参数类型表) { … }

1. 编码规范 高质量的程序 正确性:语法正确、功能正确。使之可行 可读性:通用的、必需的习惯用语和模式可以使代码更加容易理解。使之优雅 可维护性:程序应对变化的能力。使之优化 ……

1. 编码规范 阅读附件(课程主页下载) 网上搜索资料(bing或者百度C编码规范) 仅供参考(标准不唯一,无需全盘接受) 《C编码规范》 http://cn.bing.com/search?q=c%E7%BC%96%E7%A0%81+%E8%A7%84%E8%8C%83&FORM=AWRE 仅供参考(标准不唯一,无需全盘接受)

若干C代码规范 不直接使用基础类型 利用typedef重新定义,大小和符号 代替基本数据类型

若干C代码规范 《MISRA—C-2008工业标准》建议为所有基本数值类型和字符类型使用typedef重新定义。 对于32位计算机,它们是: typedef char char_t; typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef signed long int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long uint64_t; typedef float float32_t; typedef double float64_t; typedef long double float128_t;

若干C代码规范 变量、函数的命名符合编码规范 Pascal命名规则:当变量名和函数名称是由二个或二个以上单字连结在一起,而构成的唯一识别字时: 第一个单字首字母采用大写字母 后续单字的首字母亦用大写字母 例如:FirstName、LastName。

若干C代码规范 小心使用全局变量 用访问器子程序来取代全局数据 把数据隐藏到模块里面 写子程序读/写/初始化该数据 GetValue/SetValue 把数据隐藏到模块里面 用static关键字来定义该数据 写子程序读/写/初始化该数据 要求模块外部的代码使用该访问器子程序来访问该数据,而不直接(使用变量名字)操作它。

模块化开发 应用自顶向下的设计 一个函数实现一个简单的功能 一个源文件包含功能相对集中的若干函数定义 把一个相对复杂的功能,划分成相对独立的子功能,直到每个子功能相对简单 每个子功能用一个函数来实现 一个函数实现一个简单的功能 如果一个函数的代码很多(比如150行以上),最好把它分成可以调用的小函数来完成 一个源文件包含功能相对集中的若干函数定义 如果一个源文件中包含很多个函数(比如50个以上),最好再分成几个更小的源文件 每个源文件都包含一组功能相关的函数