电子成绩单项目实现.

Slides:



Advertisements
Similar presentations
第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型
Advertisements

第一章 C语言概述 计算机公共教学部.
第九章 字串 (String).
第九章 系 统 安 全 性 9.1 结构体 9.2 结构体型数组  9.3 结构体型指针 9.4 内存的动态分配 9.5 共用体
第7章 结构体、联合体和枚举类型 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
第六章 数 组 主讲教师 贾月乐 联系电话:
C程序设计 第9章 自定义数据类型 主讲教师: 鲁 萍 西安建筑科技大学 理学院.
程式設計 博碩文化出版發行.
C 程式設計— 結構 台大資訊工程學系 資訊系統訓練班.
第二章 C# 基础知识.
C++程序设计 第二讲 清华大学软件学院.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
编译原理与技术 类型检查 2018/11/21 《编译原理与技术》-类型检查.
第3章 C 語言的基本知識.
结构体和共用体 2 梁春燕 华电信息管理教研室.
Chap 9 结构 9.1 构建手机通讯录 9.2 结构变量 9.3 结构数组 9.4 结构指针.
Introduction to the C Programming Language
目录 第八章 数组 1 简单学生成绩管理系统的开发 2 一维数组 3 多维数组 4 字符数组 5 数组作函数参数.
第9章 自訂資料型態 – 結構 9-1 結構資料型態 9-2 結構陣列 9-3 指標與結構 9-4 動態記憶體配置 9-5 聯合資料型態
STRUCTURE 授課:ANT 日期:2010/5/12.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第九章 结构体和共用体 结构体的定义 结构体的使用 共用体的定义 共用体的使用 主讲:李祥 时间:2015年10月.
计算概论 第十八讲 C语言高级编程 结构与习题课 北京大学信息学院.
Object-Oriented Programming in C++ 第一章 C++的初步知识
Chap 8 指针 8.1 寻找保险箱密码 8.2 角色互换 8.3 冒泡排序 8.4 电码加密 8.5 任意个整数求和*
C语言程序设计 李祥.
C 程式設計— 結構 台大資訊工程學系 資訊系統訓練班.
第7章 编译预处理 本章要求: 本章重点: 本章难点: 掌握用#define定义无参数宏和带有参数宏定义和调用方法;
第五章 指针 5.1 指针的概念和定义 5.2 指针运算 5.3 指针和数组 5.4 字符串指针 5.5 指针数组 5.6 指向指针的指针
作弊是否很有诱惑性? 上堂课已经讲了 作业不一定在两个小时里都能完成 答疑没有一个人? 作弊是有记录的 心理系很多同学集体作弊,让人震惊
6.4.1指针与二维数组 1、二维数组结构的分析 设有数组定义为:int a[3][4]; 则有: a表示数组在内存中的首地址。
C语言 程序设计基础与试验 刘新国、2012年秋.
字符串和字符数组 字符串的输入和输出 字符串的基本操作
C++语言程序设计 第二章 C++简单程序设计.
第13章 结构体的应用 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组
Introduction to the C Programming Language
第5讲 结构化程序设计(Part II) 周水庚 2018年10月11日.
第九章 预处理命令.
数组 梁春燕 华电信息管理教研室.
Struct結構 迴圈
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C语言程序设计.
第十章 用户自定义数据类型 目录 学生信息管理系统的开发 结构体数据类型的概述 结构体变量的使用 结构体数组
OOP6 結構Struct 黃兆武.
目录 9.1 结构体类型 9.2 共用体类型 9.3 枚举类型 9.4 类型声明符typedef 1.
第十章 结构体与链表 西安工程大学.
C语言概述 第一章.
C语言复习3----指针.
C语言大学实用教程 第6章 数组 西南财经大学经济信息工程学院 刘家芬
函式庫補充資料.
C语言的特点 1. C程序由许多函数组成 2. C程序必须有且只有一个主函数main( ) 3. 函数用“{”和“}”表示起点和终点
第三章 数据抽象.
C语言程序设计 李祥 QQ:
C程序设计.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第九章 指针.
第2章 数据类型、运算符与表达式 本章要点: 基本数据类型 常量和变量 算术运算符和算术表达式 关系运算符和关系表达式
第二章 基本数据类型 ——数据的表示.
第七章  数 组.
1.4WIN32中的宽字符.
第18讲 从C到C++ 计算机与通信工程学院.
Introduction to the C Programming Language
C/C++基礎程式設計班 陣列 講師:林業峻 CSIE, NTU 3/14, 2015.
C 程式設計— 字元與字串 台大資訊工程學系 資訊系統訓練班.
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
台大資訊工程學系 資料系統訓練班 第119期 吳晉賢
安排座位.
Presentation transcript:

电子成绩单项目实现

效果演示 实例演示

电子成绩单项目我们要实现对若干学生 的信息按照各种方式进行排序输出(按 照成绩,姓名排序) 任务 电子成绩单项目我们要实现对若干学生 的信息按照各种方式进行排序输出(按 照成绩,姓名排序) 所以,首先要实现能够输出一个学生的 信息; 实现滚动输出多个学生的信息 实现对成绩进行排序 实现对姓名进行排序

目录 1. C语言循环结构 2. 显示一个学生信息 3. 滚动显示多个学生的信息 4. 对学生信息进行排序 5. 按照学生姓名进行排序 7. 使用指针实现按姓名 8. 性别类型的定义 9. 大工程文件管理 10. 多文件交叉包含的处理

C语言循环结构

while 循环 3-1 while (表达式) { 语句; } while (index < 100) { . . . 工作原理 while (表达式) { 语句; } 计算表达式的值,当值为真(非0)时,执行循环体语句,一旦条件为假,就停止执行循环体。如果条件在开始时就为假,那么不执行循环体语句直接退出循环。 示例 while (index < 100) { . . . index++; }

规则1: while 循环 3-2 [<初始化>] while(循环条件) { <循环体> } 循环条件中使用的变量需要经过初始化

规则2: while 循环 3-3 index++; while (index < 100) { . . . } 真

while 循环示例1 #include<stdio.h> int main () { 内存 #include<stdio.h> int main () { int num = 1,result = 0; while (num <= 100) result += num; num++; } num result 100 2 1 5050 1

do-while 循环 do 它先执行循环体中的语句,然后再判断条件是否为真,如果为真则继续循环;如果为假,则终止循环。 { 语句; 工作原理 do { 语句; } while (表达式); 它先执行循环体中的语句,然后再判断条件是否为真,如果为真则继续循环;如果为假,则终止循环。 示例 do { . . . scanf(“%c”,&answer); } while (answer != ’n’);

do-while 循环示例 问题描述: 统计1到100的和

While和dowhile流程图 代码实例0

显示一个学生信息

效果演示 项目演示

实现步骤分析 1. 定义学生结构体: 学号,姓名, 成绩 2. 定义学生信息 3. 输出学号 4. 输出姓名 5. 输出成绩 在前面计算器项目中我们已经了解,我们向液晶屏 写入的时候使用write_date函数的时候,该函数的参 数只能是字符,所以对于学号和成绩我们在输出之 前都必须先进行处理—先要将学号和成绩分别拆分 成一个一个的字符,保存到数组中,然后输出数组 中的信息 实例代码1

滚动显示多个学生的信息

实现思路分析 要显示多个学生的信息,所以我们首先要定义一个 包含多个学生信息的数组 – 数组元素为学生 从数组中依次取出每一个学生的信息 显示从数组中取出的当前的学生信息 实例效果

定义结构体数组 结构体数组 三种形式: num name sex age stu[0] stu[1] 25B 形式一: struct student { int num; char name[20]; char sex; int age; }; struct student stu[2]; 形式二: struct student { int num; char name[20]; char sex; int age; }stu[2]; 形式三: struct { int num; char name[20]; char sex; int age; }stu[2];

学生数组的定义和初始化 学生在我们的程序中实际上是我们自定义的一种类 型—结构体struct Stu 所以学生数组的定义如下: Struct Stu st[5]; 如果要初始化: Struct Stu st[5] = {{101, "johnny", 88}, {102, "john", 72}, {104, "rose", 68}, {103, "jack", 76}, {105, "smith", 85}};

代码分析 学号: st[j].num 姓名: st[j].name 成绩: st[j].score 对学生数组中每一个学生的属性的访问 实例代码2

对学生信息进行排序

排序 我们平时在学校考试的时候经常都要进行排名次,所 谓排名次实际上就是对所有学生的成绩按照从高到低 或者从低到高的某种顺序重新进行排列,这就是排序 对于学生信息的排序,实际上有几种排序的方式: 可以 按照学号进行,可以按照成绩进行,也可以按照姓名 进行。所以对学生信息进行排序实际上是按照某种选 择的方式对学生进行重新排列 常用的排序的算法很多,我们在这里给大家介绍逻辑 相对简单,代码实现也相对简单的一种排序算法—冒 泡排序方式

冒泡排序 所谓冒泡排序实际上对所有的数据每次冒出一个最 小的或者最大的方式 流程图如下:

冒泡排序的过程 比如我们现在要对: 5, 7, 9, 2, 6, 3, 1, 4, 8这样9个数 进行排序,那么我们可以这样进行 实例代码3

对学生成绩进行排序 下面我们对学生信息按照成绩进行排序 实现的思路和前面的例子一样,不过现在我们要排 序的是struct Stu st[]数组中的元素,而排序的依据 是st[i].score, 所以将前面排序中的arr[i]变成 st[i].score就可以了 效果演示 代码实例4

按照学生姓名进行排序

字符串排序 我们在前面对学生信息按照成绩进行排序的时候, 由于学生成绩是数值类型的数据,这类数据可以直 接比较,所以在排序的时候可以直接进行比较;而 如果我们要对学生信息按照姓名进行排序,由于姓 名是非数值类型的数据,所以他们不可以直接比较, 也就是说在程序中,我们不能使用st[i].name < st[j].name这样的条件判定 对于非数值类型的数据(字符串)的比较需要采用特殊 的方式,对于字符串的比较一种比较简单的方式是 使用库中定义的字符串比较函数来进行

与字符串有关的内置函数在头文件string.h中定义 要使用标准库字符串处理函数,程序前应该包含: #include <string.h> string.h strlen strcpy strcmp strcat ……

连接前,两串均以‘\0’结束;连接后,串1的‘\0’取消, 新串最后加‘\0’ 字符串连接函数strcat 格式:strcat(字符数组1,字符数组2) 功能:把字符数组2连到字符数组1后面 返值:返回字符数组1的首地址 说明:字符数组1必须足够大 连接前,两串均以‘\0’结束;连接后,串1的‘\0’取消, 新串最后加‘\0’ 字符串拷贝函数strcpy 格式:strcpy(字符数组1,字符串2) 功能:将字符串2,拷贝到字符数组1中去 返值:返回字符数组1的首地址 说明:字符数组1必须足够大 拷贝时‘\0’一同拷贝 不能使用赋值语句为一个字符数组赋值 例 char str1[20],str2[20]; str1={“Hello!”}; () str2=str1; ()

比较规则:对两串从左向右逐个字符比较(ASCII码), 直到遇到不同字符或‘\0’为止 字符串比较函数strcmp 格式:strcmp(字符串1,字符串2) 功能:比较两个字符串 比较规则:对两串从左向右逐个字符比较(ASCII码), 直到遇到不同字符或‘\0’为止 返值:返回int型整数,a. 若字符串1< 字符串2, 返回负整数 b. 若字符串1> 字符串2, 返回正整数 c. 若字符串1== 字符串2, 返回零 说明:字符串比较不能用“==”,必须用strcmp 字符串长度函数strlen 格式:strlen(字符数组) 功能:计算字符串长度 返值:返回字符串实际长度,不包括‘\0’在内 例 对于以下字符串,strlen(s)的值为: (1)char s[10]={‘A’,‘\0’,‘B’,‘C’,‘\0’,‘D’}; (2)char s[ ]=“\t\v\\\0will\n”; (3)char s[ ]=“\x69\082\n”; 答案:1 3 1

对学生信息按照姓名进行排序 下面我们就采用strcmp来对学生信息按照姓名排序 实例效果 实例代码5

C程序设计—指针

如果我们在对学生信息按照姓名进行排序的时候, 如果我们不使用库函数strcmp,那么我们一般都会 要用到指针

指针简介 -1 变量 指针 地址 内存 数据 习惯用语: 若指针变量ptr存放了变量x的地址,我们称“ptr指向x”。 int ptr_x int x 10 7FFED530 指针 地址 0X7FFED530 0X7FFED534 内存 数据 习惯用语: 若指针变量ptr存放了变量x的地址,我们称“ptr指向x”。

指针简介 -2 指针也是一个变量,只不过该变量中存储的是另一个对象 的内存地址 如果一个变量存储另一个对象的地址,则称该变量指向这 个对象 由于指针值是数据,指针变量可以赋值,所以一个指针的 指向在程序执行中可以改变。指针p 在执行中某时刻指向 变量x,在另一时刻也可以指向变量y

声明并初始化指针变量 数据类型 *指针名; char *ptralpha; float *rate_ptr; double *p, *q; int *ptrnum; 变量声明时,如果变量名前带 *号,表示该变量是个指针变量 ptrnum = NULL; 值为NULL的指针称为空指针,这意味着,指针并不指向任何地址。 在头文件 stdio.h 中,NULL 定义为常量。

取地址符 & 与指针相关的运算符-1 int num, *ptrnum; ptrnum = &num; 指针 内存 ptrnum num 100 num FF7C ptrnum 指针 FF7C

间接运算符 * 与指针相关的运算符-2 int num, *ptrnum; ptrnum = &num; *ptrnum=15; 指针 内存 100 num FF7C ptrnum 指针 15 变量声明时,*p表示定义了一个用来存放变量地址而非数据(数值、字符等)的指针变量。 程序中引用时,*p表示取指针变量p所指变量的值。

&与*组合使用时 若 int a, *p; p=&a; 则 &*p = &a = p; *&a = a = *p

指针的特点 指针变量的命名规则和其他变量的命名规则一样 指针不能与现有变量同名 指针可存放 C 语言中的任何基本数据类型、数组和其他所 有高级数据结构的地址 若指针已声明为指向某种类型数据的地址,则它不能用于 存储其他类型数据的地址 应为指针指定一个地址后,才能在语句中使用指针 实例效果 实例代码6

但指针变量和普通变量不同,只能 进行以下三种运算: 赋值运算 算术运算 指针比较 指针变量能参加运算吗? 指针变量可以在各种表达式中参加 运算。 但指针变量和普通变量不同,只能 进行以下三种运算: 赋值运算 算术运算 指针比较

指针赋值运算 int x,*ptr_x,*ptr_y; ptr_x=&x; ptr_y = ptr_x; int a[5],*pa; 100 x FF7C ptr_x ptr_y FF7C int x,*ptr_x,*ptr_y; ptr_x=&x; ptr_y = ptr_x; FF7C FE60 23 a[0] FE64 在32位机中,sizeof(int)=4,即int型数据占用4个内存单元 43 a[1] int a[5],*pa; pa=a; FE68 11 a[2] pa FE6C 50 a[3] FE60 FE70 46 a[4]

指针算术运算-1 int *ptrnum,arr_num[8]; ptrnum = &arr_num[0]; ptrnum++; 使用递增/递减运算符(++ 和 --)将指针递增或递减 内存 10 arr_num[0] arr_num[1] arr_num[2] arr_num[3] arr_num[4] arr_num[5] arr_num[6] arr_num[7] 23 int *ptrnum,arr_num[8]; ptrnum = &arr_num[0]; ptrnum++; 15 60 41 指针每递增一次,它都会指向下一个元素的内存单元。 指针每递减一次,它都会指向前一个元素的地址。 其他所有指针的增减将取决于它们所指向变量的数据类型长度。 49 13 一个类型为 T 的指针的移动, 以 sizeof(T)为移动单位。 39

41 60 指针算术运算 -2 ptrnum = &arr_num[0]; ptrnum = ptrnum + 4; 将指针加上或者减去某个整数值 内存 arr_num[0] arr_num[1] arr_num[2] arr_num[3] arr_num[4] arr_num[5] arr_num[6] arr_num[7] 10 23 15 60 41 49 13 39 ptrnum = &arr_num[0]; ptrnum = ptrnum + 4; printf(“%d”,*ptrnum); 41 ptrnum = &arr_num[5]; ptrnum = ptrnum - 2 ; printf(“%d”,*ptrnum); 60

指针关系运算 比较两个指针 #include<stdio.h> void main () { int *ptrnum1, *ptrnum2; int value = 1; ptrnum1 = &value; value += 10; ptrnum2 = &value; if (ptrnum1 == ptrnum2) printf("\n 两个指针指向同一个地址\n"); else printf("\n 两个指针指向不同的地址\n"); }

为什么未指向实体的指针是“危险指针”? “危险指针”?不要耸人听闻好不好! 一个指针未指向任何实体就被使用,属于”内存盗用”!因为该指针将随意指向内存中某一单元,轻则误取或破坏其他实体的值,重则破坏操作系统的工作。 “危险指针”?不要耸人听闻好不好! 一个指针变量被声明后,在没有被赋予某个实体地址之前,如果使用它,不仅可能破坏你的程序,而且可能导致计算机操作系统崩溃,出现灾难性的错误。因为它可能指向内存的任何部分。

空指针 空指针: int *p; p=NULL; 内存使用常识: 在stdio.h中,定义 #define NULL 0 所以 p=NULL; 相当于 p=0; 内存使用常识: 任何C程序的变量在内存中的地址均由操作系统自动分配,不能由编程者通过赋值指定。p=NULL 表示p不指向任何变量。 内存的低端只供由操作系统使用(相当于政府机关,普通百姓不能使用)。

使用指针实现字符串比较

使用指针实现字符串比较 下面我们不使用string.h库中定义的strcmp函数,我 们自己实现一个比较字符串的函数,同样也可以对 学生信息进行排序

自定义字符串比较函数 首先我们参考strcmp的原型,定义我们自己的字符 串比较函数和他类似 int mystrcmp(char *str1, char *str2); 因为strcmp的返回值为0,-1, 1,所以我们定义函数的返回类型为int 因为使用strcmp来进行比较的时候需要传递两个字符串作为参数,所以函数原型中的参数定义了两个char*

Mystrcmp功能的实现 Strcmp在比较两个字符串的时候,实际的算法是将 两个字符串的对应字符按照ASCII码进行比较,如果 在比较的时候第一个字符串的对应的字符大,返回1; 如果第一个字符串的对应的字符小,返回-1;如果对 应的字符相等,继续比较下一个,直到两个字符串 同时到达’\0’,并且所有字符都相等,返回-1 我们按照这个思路来实现我们的mystrcmp 效果演示 实例代码7

C语言程序设计枚举类型

枚举类型 假如我们要求的学生信息中包含性别这样一个属性,我们 平时对性别一般使用男或女或者f/m来表示,所以我们在 定义学生结构体的时候会这样定义 struct Stu { int num; char sex; char name[12]; int score; }; 这样我们在输入学生信息的时候性别可以输入f/m(这是可 能的值),但如果输入别的字符,比如k,程序也是可以运 行的,而实际上性别不可能是k。这样给我们的程序处理 带来很多的麻烦。所以C中引入了一种枚举类型的定义方 式。

枚举类型 一个变量只有几种可能的值,可定义成枚举类型。 类型声明形式为: enum 标识符 { 枚举元素表列}; 如:enum weekday {sun,mon,tue,wed,thu,fri,sat}; 定义枚举类型的变量:enum weekday workday,week_end; 说明: 枚举元素是常量,故称枚举常量。 枚举元素是有值的,按定义顺序,它们的值为: 0, 1, 2, … … 枚举常量可以用来作判断比较。 整数不能直接赋给枚举变量;但可先强制类型转换再赋值。 例:口袋中有红、黄、蓝、白、黑5种色的球若干个。每次从口袋取3个球,问有多少种得到不同色球的排列方法。 例 if(workday==mon)…… if(workday>sun)… 例 workday=(enum weekday)2; 等价于: workday=tue;

输出学生信息中包含的性别 示例代码8 实例效果

用typedef定义类型 功能:用自定义名字为已有数据类型命名 类型定义简单形式: typedef type name; 说明: 例 typedef int INTEGER; 例 INTEGER a,b,c; REAL f1,f2; 类型命名语句关键字 已有数据类型名 用户定义的类型名 例 typedef float REAL; int a,b,c; float f1,f2; 类型定义后,与已有类型一样使用 说明: typedef 没有创造新数据类型 typedef 是定义类型,不能定义变量 typedef 与 define 不同 define typedef 预编译时处理 编译时处理 简单字符置换 为已有类型命名

类型定义可嵌套 例 定义结构体类型 typedef struct date { int month; int day; int year; 按定义变量方法先写出定义体 如 int i; 将变量名换成新类型名 如 int INTEGER; 最前面加typedef 如 typedef int INTEGER; 用新类型名定义变量 如 INTEGER i,j; 类型定义可嵌套 例 定义结构体类型 typedef struct date { int month; int day; int year; }DATE; 例 定义结构体类型 DATE birthday, *p; 例 定义结构体类型 struct date { int month; int day; int year; }DATE; 例 定义结构体类型 struct date { int month; int day; int year; }d; 例 typedef struct club { char name[20]; int size; int year; }GROUP; typedef GROUP *PG; PG pclub; 例 定义指针类型 char *str; char *STRING; typedef char *STRING; STRING p,s[10]; 例 定义数组类型 int a[100]; int ARRAY[100]; typedef int ARRAY[100]; ARRAY a,b,c; 例 定义函数指针类型 int (*p)(); int (*POWER)(); typedef int (*POWER)(); POWER p1,p2; GROUP为结构体类型 PG为指向GROUP的指针类型  struct date { int month; int day; int year; }birthday, *p;  GROUP *pclub;  struct club *pclub;  int (*p1)(),(*p2)();  int a[100],b[100],c[100];  char *p; char *s[10];

讨论:typedef 和 #define 说明: (1)用typedef只是给已有类型增加1个别名, 并不能创造1个新的类型。就如同人一样,除 学名外,可以再取一个小名(或雅号),但并 不能创造出另一个人来。 (2)typedef与#define有相似之处,但二者是 不同的:前者是由编译器在编译时处理的;后 者是由编译预处理器在编译预处理时处理的, 而且只能作简单的字符串替换。

大工程文件管理

大工程文件管理 在一个比较大的工程中,包含的代码相对比较多, 这时如果我们将所有的代码都放在一个文件中,及 不利于代码的阅读和维护,也不利于代码的复用, 所以我们一般按照代码的内容将代码分别放在不同 的文件中。 一般的原则是: 定义性的内容,都定义在.h文件中 所有函数的实现,放在一个专门的.c中 主程序放在一个.c中 比如在电子成绩单系统中,我们将结构体、枚举类型的定义放在一个myhead.h中,而函数的实现,放在myhead.c中,主程序放在escore.c中

定义myhead.h 一般情况下,头文件中包括 类型定义 – 用户自定义类型(结构体,枚举…) 类型别名定义 函数原型定义 全局变量定义 实例代码10

实现myhead.c 该文件中实现所有在对应的.h中定义的函数的功能 代码实例

在主文件中包含我们定义的头文件 在主文件中只要包含我们定义的头文件.h,就可以直 接使用头文件中定义的所有内容,如同在本文件实 现的一样 代码实例

编译预处理

当一个工程中包含的文件比较多,并且文件之间的 关系比较复杂的时候,我们前面的简单定义方式就 会发生错误 比如: 在前面的工程中,我们定义两个头文件: 一条 头文件中只定义类型,另外一个头文件中定义函数 和全局变量 Head.h中定义了学生类型,而head1.h中使用了学 生类型,所以head1.h中就需要包含head.h;score.c 就需要包含head.h和head1.h两个文件,这样就出现 了重复定义的错误

错误信息 解决的办法是采用编译预处理语句 实例代码

编译预处理 所谓编译预处理是指,在对源程序进行编译之前,先 对源程序中的编译预处理命令进行处理;然后再将处理的 结果,和源程序一起进行编译,以得到目标代码。 宏定义与符号常量 文件包含 条件编译

在C语言中,“宏”分为无参数的宏(简称无参 宏)和有参数的宏(简称有参宏)两种。 宏定义与符号常量 在C语言中,“宏”分为无参数的宏(简称无参 宏)和有参数的宏(简称有参宏)两种。 .1 无参宏定义 .2 符号常量 .3 有参宏定义

.1 无参宏定义 1.无参宏定义的一般格式 #define 标识符 语言符号字符串 其中:“define”为宏定义命令;“标识符”为所定义的宏名, 通常用大写字母表示,以便于与变量区别;“语言符号字符串”可 以是常数、表达式、格式串等。 2.使用宏定义的优点 (1)可提高源程序的可维护性 (2)可提高源程序的可移植性 (3)减少源程序中重复书写字符串的工作量

[案例 ] 输入圆的半径,求圆的周长、面积和球的体积。要求使用无参宏定义圆 周率。 #define PI 3. 1415926 / [案例 ] 输入圆的半径,求圆的周长、面积和球的体积。要求使用无参宏定义圆 周率。 #define PI 3.1415926 /*PI是宏名,3.1415926用来替换宏名的常数*/ main() { float radius,length,area,volume; printf("Input a radius: "); scanf("%f",&radius); length=2*PI*radius; /*引用无参宏求周长*/ area=PI*radius*radius; /*引用无参宏求面积*/ volume=PI*radius*radius*radius*3/4; /*引用无参宏求体积*/ printf("length=%.2f,area=%.2f,volume=%.2f\n", length, area, volume); }

3.说明 (1)宏名一般用大写字母表示,以示与变量区别。但这并非是规定。 (2)宏定义不是C语句,所以不能在行尾加分号。否则,宏展开时,会将分号作为字符串的1个字符,用于替换宏名。 (3)在宏展开时,预处理程序仅以按宏定义简单替换宏名,而不作任何检查。如果有错误,只能由编译程序在编译宏展开后的源程序时发现。 (4)宏定义命令#define出现在函数的外部,宏名的有效范围是:从定义命令之后, 到本文件结束。通常,宏定义命令放在文件开头处。 (5)在进行宏定义时,可以引用已定义的宏名 。 (6)对双引号括起来的字符串内的字符,即使与宏名同名,也不进行宏展开。

.2 符号常量 在定义无参宏时,如果“语言符号字符串”是一个 常量,则相应的“宏名”就是一个符号常量。 恰当命名的符号常量,除具有宏定义的上述优点外, 还能表达出它所代表常量的实际含义,从而增强程序的 可读性。 #define EOF -1 /*文件尾*/ #define NULL 0 /*空指针*/ #define MIN 1 /*极小值*/ #define MAX 31 /*极大值*/ #define STEP 2 /*步长*/

文件包含 1.文件包含的概念 文件包含是指,一个源文件可以将另一个源文件的全部内容包含进来。 2.文件包含处理命令的格式 #include “包含文件名” 或 #include <包含文件名> 两种格式的区别仅在于: (1)使用双引号:系统首先到当前目录下查找被包含文件,如果没找到,再到系统指定的“包含文件目录”(由用户在配置环境时设置)去查找。 (2)使用尖括号:直接到系统指定的“包含文件目录”去查找。一般地说,使用双引号比较保险。

3.文件包含的优点 一个大程序,通常分为多个模块,并由多个程序员分别编程。有了文件包含处理功能,就可以将多个模块共用的数据(如符号常量和数据结构)或函数,集中到一个单独的文件中。这样,凡是要使用其中数据或调用其中函数的程序员,只要使用文件包含处理功能,将所需文件包含进来即可,不必再重复定义它们,从而减少重复劳动。 4.说明 (1)编译预处理时,预处理程序将查找指定的被包含文件,并将其复制到#include命令出现的位置上。

(2)常用在文件头部的被包含文件,称为“标题文件”或“头部文件”,常以“h”(head)作为后缀,简称头文件。在头文件中,除可包含宏定义外,还可包含外部变量定义、结构类型定义等。 (3)一条包含命令,只能指定一个被包含文件。如果要包含n个文件,则要用n条包含命令。 (4)文件包含可以嵌套,即被包含文件中又包含另一个文件。

条件编译可有效地提高程序的可移植性,并广泛地应用在商业软件中,为一个程序提供各种不同的版本。 .1 #ifdef ~ #endif和#ifndef ~ #endif命令 .2 #if ~ #endif

.1 #ifdef ~ #endif和#ifndef ~ #endif命令 1.一般格式 #ifdef 标识符 程序段1; [#else 程序段2;] #endif 2.功能:当“标识符”已经被#define命令定义过,则编译程序段1,否则编译程序段2。 (1)在不同的系统中,一个int 型数据占用的内存字节数可能是不同的。

(2)利用条件编译,还可使同一源程序即适合于调试(进行程序跟踪、打印较多的状态或错误信息),又适合高效执行要求。 3.关于#ifndef ~ #endif命令 格式与#ifdef ~ #endif命令一样,功能正好与之相反。

.2 #if ~ #endif 1.一般格式 #if 常量表达式 程序段1; [#else 程序段2;] #endif 2.功能:当表达式为非0(“逻辑真”)时,编译程序段1, 否则编译程序段2。

使用编译预处理语句解决重复包含的问题 实例效果 实例代码