语言基础程序 3_第1页
语言基础程序 3_第2页
语言基础程序 3_第3页
语言基础程序 3_第4页
语言基础程序 3_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

C语言程序设计项目化教程(AI助学)(微课版)项目5

学生考勤与成绩关联管理系统情景导入“无规矩不成方圆。”2000多年前儒家先贤的治理思想,让小辰在校园里产生了思考:课堂考勤该不该影响成绩,一次迟到该扣多少分才公平,不同课程是否应该有不同的考评标准?这些日常的管理问题,恰恰蕴含着程序设计的智慧。作为计算机专业学生,小辰决定继承古人“立规明矩”的治理思想,开发一个既能体现规则刚性,又具备灵活适配性的学生考勤与成绩关联管理系统,设定公平的考勤规则,实现成绩的智能计算。知识图谱学习要点(含素养要点)理解无参宏定义和带参宏定义的语法格式与作用掌握文件包含指令的两种格式、差异、作用及嵌套使用方法掌握条件编译的形式、作用及预处理阶段代码优化的基本思路能独立定义考勤扣分规则宏,通过条件编译控制考勤与成绩的联动模式能利用条件编译实现考勤-成绩联动模式和独立模式的切换培养宏定义规范与代码可维护性素养实现考勤扣分计算功能任务5-1任务5-1实现考勤扣分计算功能利用无参宏实现考勤扣分规则的集中配置,通过宏定义统一管理考勤扣分标准。同时,使用带参宏CALCULATE_PENALTY封装考勤扣分计算逻辑,实现根据学生缺勤和迟到次数自动计算考勤扣分的功能。系统支持考勤信息的输入、扣分计算和结果展示,并具备完整的考勤扣分计算流程,效果如图5-1所示。任务描述图5-1考勤扣分计算流程效果图#define标识符字符串5.1.1无参宏定义知识准备无参宏定义格式如下:#表示预处理指令,define为宏定义指令关键字。标识符称为“宏名”,遵循标识符命名规则,即由字母、数字、下画线组成,不能以数字开头,通常用全大写字母表示,以与变量和函数名进行区分。字符串称为“宏体”,可以是数字、字符、字符串、表达式,甚至是空,在预处理阶段,源代码中出现的所有宏名都会被原封不动地替换成字符串的文本。无参宏定义的格式5.1.1无参宏定义知识准备无参宏定义的格式【例5-1】编写程序,定义圆的半径为5,求圆的面积。无参宏定义通常用来将指定标识符替换为一个较复杂的字符串,例如使用PI表示圆周率比直接写3.14159更清晰、更容易修改。

1.#include

2.#definePI3.141593.#defineRADIUS5.04.#defineAREA(PI*RADIUS*RADIUS)5.6.intmain()

{7.printf("RADIUS=%.2fAREA=%.2f\n",RADIUS,AREA);8.return

0;9.}运行程序结果如下:RADIUS=5.00AREA=78.54程序定义了无参宏PI,其代表圆周率常数3.14159,然后定义了无参宏RADIUS,其代表圆的半径,最后定义了无参宏AREA,其代表圆的面积,RADIUS和AREA在预处理阶段会被替换为对应的值。5.1.1无参宏定义知识准备无参宏定义的格式【温馨提示】(1)宏替换发生在编译之前,是纯粹的文本替换,编译器看到的是替换后的值。(2)宏定义从#define指令出现的位置开始生效,到#undef命令终止,若无#undef命令,则有效范围直到文件结束。(3)#define指令末尾不要加分号。如果加了分号,这个分号会成为替换文本的一部分,可能导致语法错误。#define标识符(形参表)字符串5.1.2带参宏定义知识准备带参宏定义类似于函数,它可以接受参数,在宏展开时将参数代入替换文本,格式如下:形参表由一个或多个参数组成,参数之间用逗号分隔,参数名不需要指定类型。在字符串中可以使用形参表中的参数,实现参数化替换。带参宏定义的格式5.1.2带参宏定义知识准备带参宏定义的格式【例5-2】使用带参宏定义计算不同半径的圆面积。带参宏定义通常用在宏替换时以实参替代形参。运行程序结如下:radius1=5.00AREA=78.54radius2=3.50AREA=38.48程序首先定义了一个名为AREA的带参宏,参数r表示圆的半径,宏的功能是计算圆的面积,然后定义了两个实型变量,表示不同的圆半径,使用带参宏计算不同半径的圆面积。1.#include

<stdio.h>2.#defineAREA(r)

(3.14159

*

(r)

*

(r))3.intmain()

{4.floatradius1=

5.0;5.floatradius2=

3.5;6.printf("radius1=%.2fAREA=%.2f\n",

7.radius1,AREA(radius1));8.printf("radius2=%.2fAREA=%.2f\n",

9.radius2,AREA(radius2));10.return

0;11.}5.1.1无参宏定义知识准备带参宏定义的格式【温馨提示】(1)带参宏的宏名与左括号之间不能有空格,否则预处理器会将其解释为无参宏。(2)宏不存在类型问题,宏名及其参数无类型,编译器不会检查传递给宏的参数类型是否匹配。任务5-1实现考勤扣分计算功能(1)定义考勤扣分规则宏,包括每次缺勤扣分(ABSENCE_PENALTY)、每次迟到扣分(LATE_PENALTY)和考勤扣分上限(MAX_PENALTY)等关键参数。(2)使用带参宏CALCULATE_PENALTY,根据每个学生的缺勤和迟到次数,计算扣分并确保扣分不超过上限。(3)实现考勤管理函数,包括考勤信息输入函数input_attendance_info(),提示用户输入缺勤次数和迟到次数,考勤结果展示函数display_attendance_result(),显示实际计算的考勤扣分。任务实施:任务要求任务5-1实现考勤扣分计算功能任务实施:代码实现1.#include

<stdio.h>2.//无参宏定义:考勤扣分规则

3.#defineABSENCE_PENALTY2.0f

//每次缺勤扣分

4.#defineLATE_PENALTY1.0f

//每次迟到扣分

5.#defineMAX_PENALTY20.0f

//考勤扣分上限

6.//有参宏定义:计算考勤扣分

7.#defineCALCULATE_PENALTY(absence,late)\8.((absence)

*ABSENCE_PENALTY+

(late)

*LATE_PENALTY>MAX_PENALTY?\9.MAX_PENALTY:

(absence)

*ABSENCE_PENALTY+

(late)

*LATE_PENALTY)10.//函数声明11.floatinput_attendance_info();12.voiddisplay_attendance_result(floatpenalty);13.intmain()

{14.printf("===学生考勤扣分计算功能===\n\n");15.//输入考勤信息并计算扣分16.

floatpenalty=input_attendance_info();17.//显示计算结果18.

display_attendance_result(penalty);19.return

0;20.}21.//输入考勤信息22.floatinput_attendance_info()

{23.intabsence,late;24.printf("请输入学生考勤信息:\n");25.printf("缺勤次数:");26.

scanf("%d",

&absence);27.printf("迟到次数:");28.

scanf("%d",

&late);29.//使用有参宏计算扣分30.

floatpenalty=CALCULATE_PENALTY(absence,late);31.returnpenalty;32.}33.//显示考勤结果34.voiddisplay_attendance_result(floatpenalty)

{35.printf("\n===考勤扣分计算完成===\n");36.printf("系统配置:\n");37.printf("-缺勤扣分:%.1f分/次\n",ABSENCE_PENALTY);38.printf("-迟到扣分:%.1f分/次\n",LATE_PENALTY);39.printf("-扣分上限:%.1f分\n",MAX_PENALTY);40.printf("计算结果:\n");41.printf("-考勤扣分:%.1f分\n",penalty);42.}实现考勤与成绩关联计算功能任务5-2任务5-2实现考勤与成绩关联计算功能任务描述在获取学生考勤情况后,需要在平时分数中扣除考勤扣分,再按照成绩计算规则计算学生最终成绩。本任务实现考勤数据与成绩数据的关联处理机制,利用条件编译语句实现不同模式下的差异化计算逻辑和输出格式,通过ATTENDANCE_EFFECT条件编译宏控制两种运行模式:1.关联模式:考勤扣分影响平时成绩2.独立模式:考勤记录仅作统计不影响成绩图5-2关联模式实现效果图5-3独立模式实现效果5.2.1文件包含知识准备1.语法格式文件包含是C语言预处理机制的重要组成部分,由#include指令实现。该指令在编译预处理阶段将指定文件的内容完整地插入指令所在位置,形成单一的翻译单元供编译器处理。使用文件包含指令主要有两种语法格式,它们的主要区别在于编译器查找被包含文件的路径顺序。#include"stdio.h"#include<stdio.h>使用#include<stdio.h>指令时,编译器会直接到系统标准的头文件存放路径下去查找指定的文件。使用#include"stdio.h"指令时,编译器会首先在当前源文件所在的目录下查找指定的文件,如果没找到,再去系统标准路径和编译器指定的其他路径中查找。知识准备2.作用文件包含指令的主要作用是代码复用与模块化,可将一些常用的常量、宏定义、函数声明、结构体定义等写在一个头文件里。当多个源文件都需要用到这些内容时,只需用#include包含这个头文件即可,不需要在每个.c文件里重复编写相同的代码。5.2.1文件包含知识准备3.#include指令的嵌套使用文件包含指令允许嵌套,一个被包含的文件内部可以再包含其他的文件。【例5-3】通过#include命令的嵌套计算圆面积,my_math.h、my_math.c和main.c3个源文件的代码分别如下。1.#ifndefMY_MATH_H2.#defineMY_MATH_H3.#definePI3.141594.doublecircle_area(doubleradius);5.#endif1.#include

"my_math.h"2.doublecircle_area(doubleradius)

{3.returnPI*radius*radius;4.}1.#include

<stdio.h>

2.#include

"my_math.c"

3.intmain()

{4.doublearea=circle_area(2.5);5.printf("Radius=2.5,Area=%.2f\n",area);6.printf("PI=%.5f\n",PI);

7.return

0;8.}文件my_math.h的代码:文件my_math.c的代码:文件main.c的代码:5.2.1文件包含知识准备3.#include指令的嵌套使用【例5-3】通过#include命令的嵌套计算圆面积。运行程序效果如下:Radius=2.5,Area=19.63PI=3.14159上面的程序中,文件my_math.h提供接口声明,包括宏PI,以及函数circle_area()的声明。文件my_math.c包含my_math.h文件,实现my_math.h中声明的circle_area()函数。文件main.c作为程序入口,通过文件包含指令复用my_math.c,实现计算半径为2.5的圆的面积。5.2.1文件包含知识准备3.#include指令的嵌套使用【温馨提示】应避免头文件重复包含,即在嵌套包含时,可能出现一个头文件被间接地包含多次的情况。这会导致其中的变量、函数等被重复定义,引发编译错误。5.2.1文件包含条件编译的分类

条件编译是C语言预处理器提供的强大工具,它允许程序员在编译前根据特定条件选择性地包含或排除代码片段。这些条件主要分为两类,即使用宏定义的标识符作为编译条件和使用常量表达式的值作为编译条件,分别用于检查宏是否被定义和检查宏或常量表达式的值。5.2.2条件编译知识准备5.2.2条件编译知识准备1.使用宏定义的标识符作为编译条件(1)形式一:基本判断基本判断是最简单的条件编译形式,其逻辑为“若宏已定义,则编译此段代码”。语法如下:#ifdef标识符程序段1#endif如果指定的标识符已通过#define定义,则编译#ifdef标识符与#endif之间的程序段。5.2.2条件编译知识准备1.使用宏定义的标识符作为编译条件【例5-4】使用宏定义的标识符DEBUG作为编译条件,输出两个整数的值与和。运行程序结如下:计算5+10的结果变量a的值:5变量b的值:10结果是:15计算5+10的结果结果是:15如果将宏定义语句#defineDEBUG去掉,则运行结果为:1.#include

<stdio.h>2.#defineDEBUG3.intmain()

{4.inta=

5;5.intb=

10;6.intsum=a+b;7.printf("计算%d+%d的结果\n",a,b);8.#ifdefDEBUG9.printf("变量a的值:%d\n",a);10.printf("变量b的值:%d\n",b);11.#endif12.printf("结果是:%d\n",sum);13.return

0;14.}5.2.2条件编译知识准备1.使用宏定义的标识符作为编译条件(2)形式二:二选一此形式在“基本判断”基础上增加了#else分支,实现了“二者择一”的互斥选择,语法如下:#ifdef标识符程序段1#else

程序段2#endif作用:如果标识符已被定义,则编译程序段1,忽略程序段2;如果标识符未被定义,则忽略程序段1,编译程序段2。5.2.2条件编译知识准备1.使用宏定义的标识符作为编译条件【例5-5】使用宏定义标识符HARD作为编译条件,区分困难模式和普通模式。运行程序结如下:困难模式普通模式如果将宏定义语句#defineHARD去掉,则运行结果为:开发者可以通过定义或取消定义HARD来控制程序的行为,而无须修改代码逻辑。1.#include

<stdio.h>2.#defineHARD3.intmain()

{4.#ifdefHARD5.printf("困难模式\n");6.#else7.printf("普通模式\n");8.#endif9.return

0;10.}5.2.2条件编译知识准备1.使用宏定义的标识符作为编译条件(3)形式三:取反判断#ifndef是#ifdef的逻辑反面,其逻辑为“若宏未定义,则编译此段代码”。语法如下:#ifndef标识符程序段1#else

程序段2#endif作用:如果标识符未被定义,则编译程序段1,忽略程序段2;如果标识符已被定义,则忽略程序段1,编译程序段2。ifndef是ifnotdefined的缩写。5.2.2条件编译知识准备1.使用宏定义的标识符作为编译条件【例5-6】使用宏定义的标识符LOGIN_SUCCESS作为编译条件,判断是否登录成功,并输出登录信息。运行程序结如下:请先登录系统!正在跳转到登录页面……欢迎回来,用户!正在加载您的个人资料……如果将宏定义语句#defineLOGIN_SUCCESS前面的注释符号//去掉,则运行结果为:通过注释或取消注释#defineLOGIN_SUCCESS这一语句,可以轻松切换程序的两种状态。1.#include

<stdio.h>2.//#defineLOGIN_SUCCESS3.intmain()

{4.#ifndefLOGIN_SUCCESS5.printf("请先登录系统!\n");6.printf("正在跳转到登录页面...\n");7.#else8.printf("欢迎回来,用户!\n");9.printf("正在加载您的个人资料...\n");10.#endif11.return

0;12.}5.2.2条件编译知识准备1.使用宏定义的标识符作为编译条件【温馨提示】#ifdef仅会判断宏是否被定义,与宏的值无关;所有条件编译指令必须以#endif结尾,否则会导致编译错误。5.2.2条件编译知识准备2.使用常量表达式的值作为编译条件(1)形式一:基本判断#if指令根据常量表达式的计算结果进行条件编译,这比仅检查定义与否的#ifdef指令更为灵活,语法如下:#if常量表达式程序段1#endif作用:预处理器计算常量表达式的值,如果表达式的结果为真,则编译程序段1,如果表达式的结果为假,则跳过程序段1(不参与编译)。5.2.2条件编译知识准备2.使用常量表达式的值作为编译条件【例5-7】使用常量表达式VERSION的值作为编译条件,判断系统版本号,并输出提示信息。运行程序结如下:高级功能已解锁!您现在可以使用AI助手和云存储功能欢迎使用我们的软件!欢迎使用我们的软件!如果将版本号改为1,即将宏定义语句#defineVERSION2改为#defineVERSION1,则运行结果如下。1.#include

<stdio.h>2.#defineVERSION2

//定义版本号3.intmain()

{4.#ifVERSION>=25.printf("高级功能已解锁!\n");6.printf("您现在可以使用AI助手和云存储功能\n");7.#endif8.printf("欢迎使用我们的软件!\n");9.return

0;10.}5.2.2条件编译知识准备2.使用常量表达式的值作为编译条件(2)形式二:二选一此形式在基本判断的基础上扩展了#else分支,实现了基于表达式结果的互斥选择。语法如下:#if表达式程序段1#else

程序段2#endif作用:预处理器计算常量表达式的值;如果表达式结果为真,则编译程序段1,跳过程序段2;如果表达式结果为假,则跳过程序段1,编译程序段2。5.2.2条件编译知识准备2.使用常量表达式的值作为编译条件【例5-8】使用常量表达式COMPILE_MODE的值作为编译条件,创建程序的精简版和完整版功能。12.#else13.//程序段2:精简版功能14.printf("精简版功能已启用\n");15.printf("正在进行基础计算...\n");16.intresult=

10

*

2;17.printf("计算结果:%d\n",result);18.#endif19.printf("程序执行完毕\n");20.return

0;21.}1.#include

<stdio.h>2.//定义编译模式(0=精简版,1=完整版)3.#defineCOMPILE_MODE14.intmain()

{5.printf("欢迎使用我的程序\n");6.#ifCOMPILE_MODE==17.//程序段1:完整版功能8.printf("完整版功能已启用\n");9.printf("正在进行高级计算...\n");10.intresult=

100

*

2;11.printf("计算结果:%d\n",result);5.2.2条件编译知识准备2.使用常量表达式的值作为编译条件运行程序结果如下:欢迎使用我的程序完整版功能已启用正在进行高级计算……计算结果:200程序执行完毕欢迎使用我的程序精简版功能已启用正在进行基础计算……计算结果:20程序执行完毕如果将#defineCOMPILE_MODE1改为#defineCOMPILE_MODE0,则运行结果如下。【例5-8】使用常量表达式COMPILE_MODE的值作为编译条件,创建程序的精简版和完整版功能。上述程序使用条件编译来创建程序的不同版本,通过令常量表达式COMPILE_MODE的值为1或0,程序会在编译时选择不同的执行路径,当为1时启用完整版功能,当为0时则启用精简版功能,最后均显示“程序执行完毕”的结束信息。5.2.2条件编译知识准备2.使用常量表达式的值作为编译条件【温馨提示】#if后的表达式必须是常量表达式,即表达式的值在预处理阶段即可确定,不能包含变量;若表达式中引用了未定义的宏,预处理程序会将其视为0。任务实施:任务要求任务实施:任务要求(1)定义条件编译宏ATTENDANCE_EFFECT,当该宏的值为1时启用考勤-成绩联动模式,为0时启用成绩独立计算模式。(2)定义成绩计算规则宏,包括平时成绩权重(USUAL_WEIGHT)和期末成绩权重(FINAL_WEIGHT),用于规范成绩计算标准。(3)利用条件编译语句实现不同模式下的差异化成绩计算逻辑。总成绩=平时成绩×30%+期末成绩×70%,联动模式下从平时成绩中扣除考勤扣分,独立模式下考勤扣分不影响最终成绩计算。任务实施:代码实现任务实施:代码实现1.#ifndefATTENDANCE_H2.#defineATTENDANCE_H3.#include

<stdio.h>4.//无参宏定义:考勤扣分规则

5.#defineABSENCE_PENALTY2.0f

//每次缺勤扣分

6.#defineLATE_PENALTY1.0f

//每次迟到扣分

7.#defineMAX_PENALTY20.0f

//考勤扣分上限

8.//有参宏定义:计算考勤扣分

9.#defineCALCULATE_PENALTY(absence,late)\10.((absence)

*ABSENCE_PENALTY+

(late)

*LATE_PENALTY>MAX_PENALTY?\11.MAX_PENALTY:

(absence)

*ABSENCE_PENALTY+

(late)

*LATE_PENALTY)12.//函数声明13.floatcalculate_attendance_penalty();14.voiddisplay_attendance_info(floatpenalty);15.#endifattendance.h代码如下:任务实施:代码实现任务实施:代码实现attendance.c代码如下:

1.#include

"attendance.h"2.floatcalculate_attendance_penalty()

{3.intabsence,late;

4.printf("===考勤信息输入===\n");5.printf("请输入缺勤次数:");

6.

scanf("%d",

&absence);7.printf("请输入迟到次数:");

8.

scanf("%d",

&late);

9.//使用有参宏计算扣分10.

floatpenalty=CALCULATE_PENALTY(absence,late);11.returnpenalty;12.}13.voiddisplay_attendance_info(floatpenalty)

{14.printf("\n===考勤扣分详情===\n");15.printf("缺勤扣分:%.1f分/次\n",ABSENCE_PENALTY);16.printf("迟到扣分:%.1f分/次\n",LATE_PENALTY);17.printf("扣分上限:%.1f分\n",MAX_PENALTY);18.printf("实际扣分:%.1f分\n",penalty);19.}任务实施:代码实现任务实施:代码实现attendance.c代码如下:

1.#include

"attendance.h"2.floatcalculate_attendance_penalty()

{3.intabsence,late;

4.printf("===考勤信息输入===\n");5.printf("请输入缺勤次数:");

6.

scanf("%d",

&absence);7.printf("请输入迟到次数:");

8.

scanf("%d",

&late);

9.//使用有参宏计算扣分10.

floatpenalty=CALCULATE_PENALTY(absence,late);11.returnpenalty;12.}13.voiddisplay_attendance_info(floatpenalty)

{14.printf("\n===考勤扣分详情===\n");15.printf("缺勤扣分:%.1f分/次\n",ABSENCE_PENALTY);16.printf("迟到扣分:%.1f分/次\n",LATE_PENALTY);17.printf("扣分上限:%.1f分\n",MAX_PENALTY);18.printf("实际扣分:%.1f分\n",penalty);19.}任务实施:代码实现任务实施:代码实现1.#ifndefGRADE_H2.#defineGRADE_H3.#include

<stdio.h>4.//条件编译控制:是否启用考勤-成绩关联

5.#defineATTENDANCE_EFFECT1

//1-启用关联,0-禁用关联

6.//宏定义:成绩计算规则

7.#defineUSUAL_WEIGHT0.3f

//平时成绩权重

8.#defineFINAL_WEIGHT0.7f

//期末成绩权重

9.//函数声明10.voidcalculate_final_grade(floatattendance_penalty);11.#endifgrade.h代码如下:任务实施:代码实现任务实施:代码实现grade.c代码如下:1.#include

"grade.h"2.voidcalculate_final_grade(floatattendance_penalty)

{3.floatusual_score,final_score;4.printf("\n===成绩信息输入===\n");5.printf("请输入平时成绩:");

6.

scanf("%f",

&usual_score);7.printf("请输入期末成绩:");

8.

scanf("%f",

&final_score);9.floattotal_score;10.//条件编译:考勤是否影响成绩11.

#ifATTENDANCE_EFFECT==112.//启用联动:考勤扣分影响平时成绩13.

floatadjusted_usual=usual_score-attendance_penalty;14.if

(adjusted_usual<

0)adjusted_usual=

0;15.total_score=adjusted_usual*USUAL_WEIGHT+final_score*FINAL_WEIGHT;16.printf("\n===成绩计算结果(考勤关联模式)===\n");17.printf("平时成绩:%.1f分\n",usual_score);18.printf("考勤扣分:%.1f分\n",attendance_penalty);19.printf("调整后平时成绩:%.1f分\n",adjusted_usual);20.printf("期末成绩:%.1f分\n",final_score);21.printf("最终成绩:%.1f分\n",total_score);22.#else23.//禁用联动:考勤不影响成绩24.

total_score=usual_score*USUAL_WEI

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论