海南工商职业学院
《程序设计基础I》课程
实
训
指
导
书
编者:信息工程学院 陈俊
2020年4月
目 录
1、 实训目的与要求
以 “学生成绩管理系统”项目为任务驱动,通过上机实践使学生能够比较熟练地编写、输入和调试基本C应用程序模块,掌握C语言结构化程序设计的基本方法和技巧,具有运用C函数库常用函数分析解决实际问题的初步应用能力。同时,注重培养程序设计逻辑思维方式,提高学生自主探索学习和分析解决实际问题的意识。
2、 实训内容与学时分配
表1:实训内容列表
实训编号 |
实训项目名称 |
学时 |
实训一 |
学生成绩的总分与平均分计算 |
2 |
实训二 |
输入学生成绩转化为等级 |
2 |
实训三 |
学生成绩的分组汇总 |
4 |
实训四 |
多个学生多门课的成绩排序 |
4 |
实训五 |
学生成绩菜单式汇总 |
4 |
实训六 |
指针优化学生成绩排名 |
4 |
实训七 |
制作学生成绩单 |
4 |
3、 实训保障
1) 参考教材:
《C语言程序设计实用教程》,周雅静等编,清华大学出版社,2010年出版
《全国计算机等级考试二级教程——C语言程序设计(2013年版)》,教育部考试中心编著,高等教育出版——2013年出版
2) 硬件要求:
实训中心普通机房。
实训平台配置要求:40-50台PC机,Windows操作系统和VC 编程软件或其它C语言集成开发软件。
实训目的:
1、 熟悉 C语言程序基本结构
2、 掌握变量赋值运算、算术运算及输入输出方法
3、 初步掌握VC6.0中C程序的开发过程
实训内容:
编程:输入某学生语数外三科成绩,求该学生的总分及平均分并输出。
实训指导:
1、VC下开发一个C程序必须要经过创建、编辑、编译和连接的过程。
2、问题涉及的C语言知识点分析
(1)在程序中如何计算总分和平均分——涉及变量的算术运算和算术表达式;
(2)计算的总分和平均分如何保存到相应变量中——涉及对变量的赋值运算和赋值表达式;
(3)表达式混合运算还涉及到计算顺序和数据类型转换问题。
3、核心代码:
int chinese,math,english;//定义三个变量保存三科成绩
float sum, avg; //增加总分及平均分实数变量
sum=chinese+math+english; //计算总分
avg=sum/3; //计算平均分
4、参考源代码:
#include"stdio.h"
void main()
{
int chinese,math,english;
float sum,avg;//总分及平均分实数变量
printf("请输入一学生语数外三科成绩:");
scanf("%d%d%d",&chinese,&math,&english);
sum=chinese+math+english;//计算总分
avg=sum/3;//计算平均分
printf("该学生的总成绩及平均分为:");
printf("%.2f, %.2f\n",sum,avg);
}
5、思考题:(float)7/2和(float)(7/2)的值是多少?
实训目的:
1、 熟悉if和switch两种选择语句用法
2、 初步掌握选择结构的设计方法与技巧
3、 训练运用选择语句解决实际问题的应用能力
实训内容:
一个班进行了一次考试,教师打的是百分制成绩,现在学校要求打五级制,即90~100 分的转变为A,80~89 的转变为 B,70~79的转变为C,60~69的转变为D,60以下的转变为E。现编程实现输入学生成绩转化为等级。
实训指导:
程序实现方法一:if单分支结构
方法一流程图
说明:首先判断输入的成绩是否合法,不合法的话,输出“输入的成绩不合法”的提示信息;
合法的话再判断成绩是否在90分到100分之间,是的话,将变量y赋好相应的值;
同样再判断成绩是否在80分到90分之间,是的话,将变量y赋好相应的值等等。
法一核心代码样式:
float x;//百分制成绩
char y; //等级制成绩
if(x>=90&&x<=100) y='A'; //x在90到100之间,输出A
if(x>=80&&x<90) y='B';
if(x>=70&&x<80) y='C';
if(x>=60&&x<70) y='D';
if(x>=0&&x<60) y='E';
printf("该学生的等级为%c\n",y);
程序实现方法二:if多分支结构
流程图
说明:首先判断输入的成绩是否合法,不合法的话,输出“输入的成绩不合法”的提示信息;
合法的话再判断成绩是否大于等于90分,若是的话,将变量y赋好相应的值;
否则在前基础上再判断成绩是否大于等于80分,是的话,将变量y赋好相应的值;
否则在前基础上再判断成绩是否大于等于70分,是的话,将变量y赋好相应的值等等。
法二核心代码样式
float x;//百分制成绩
char y; //等级制成绩
if(x>=90) y='A';
else if (x>=80) y=‘B’; //此时x<90
else if (x>=70) y='C';
else if (x>=60) y='D';
else y='E';
printf("该学生的等级为%c\n",y);
思考:程序实现方法三:switch多分支结构
任务拓展:从键盘输入两个整数及一个运算符(加、减、乘、除), 求其结果并输出。(分别用if…else if语句和switch语句)
实训目的:
1、掌握循环语句的嵌套用法
2、辨识for、while与do…while三种循环语句的异同
3、训练运用循环语句解决实际问题的应用能力
实训内容:
编程:一个班中有四个小组,求本学期期中考试中每个小组数学成绩的总分及平均分。
实训指导:
1、程序循环实现分析
(1)在前面任务中,利用单层循环已解决求一个十人小组学生成绩的总分及平均分的问题。
(2)现在一个班有四个小组,求每个小组的学生成绩的总分及平均分。
(3)也就是将前面任务重复进行四次,显然重复写四段程序是不科学的,而科学的方法是再嵌套一个循环。
基本思路:采用二重循环,其关键:
外层循环每次完成一个小组的成绩汇总,用循环控制变量j控制小组数, j:1-> 4
内层循环每次输入某一小组一个学生成绩并加到总分上,用循环控制变量i控制当前小组内学生, i:1-> 10。
2、流程图
定义变量及赋初值score,i,sum |
||
定义平均分float avg; |
||
定义变量j 并赋初值1 ,先从第一小组开始 |
||
j<=4 //j控制小组数 |
||
|
赋初值i=1,sum=0 //每个小组刚开始总分为零 |
|
提示请输入本小组10个学生的成绩: |
||
i的初值为1 |
||
i<=10 //i控制当前小组内学生数 |
||
|
输入成绩score sum=sum+score; //将成绩累加到总分sum中 i++; //学生人数增加1 |
|
计算平均分 |
||
输出总分及平均分 |
||
j++; |
3、参考源代码:
#include"stdio.h"
void main()
{
int score; //一个学生成绩
int sum=0; //总成绩累加和
float avg; //平均成绩
int i; //i控制小组内学生数
int j=1; //j是控制小组数并赋初值1。
while(j<=4) //外循环
{
sum=0;
i=1; //本小组内学生数初值设为1。
printf("请输入第%d小组学生成绩:",j);
while(i<=10)//内循环
{
scanf("%d",&score);
sum=sum+score;
i=i+1; //本小组学生数增加1
}
avg=sum/10.0;
printf("本小组10个学生的总分为:%d\n",sum);
printf("本小组10个学生的平均分为:%.2f\n\n",avg);
j++; //下一个小组
}
}
任务拓展:编程输出三角九九乘法表。
实训目的:
1. 掌握二维数组的声明、引用和初始化
2. 掌握冒泡排序算法和比较排序算法
3. 初步掌握多个学生成绩排序的应用
实训内容:
一个班40个同学参加了三门课的考试,现要求编程输出按总成绩的高低排序的成绩单。成绩单的格式如下:
排序 姓名 课1 课2 课3 总分 平均分
1 张三 98 87 88 273 91
2 李四 96 86 88 270 90
实训指导:
1、项目任务与知识分解
【项目分析】涉及对学生成绩二维数组表示、计算与排序,还有姓名字符数组排序交换所需的字符串比较和复制函数。
首先,需要输入和存储多个学生姓名及三门课的成绩;
第二,计算每个同学的总分及平均分;
第三,对成绩总分由高到低排序,并输出排序结果。
从先简单后复杂的原则出发,已将这一项目分解成四个任务。具体如下:
【项目任务分解】
任务1 :多个学生一门课成绩的输入输出—〉一维数组
任务2 :多个学生一门课成绩的排序—〉冒泡和比较算法
任务3 :学生姓名的输入/输出—〉一、二维字符数组
任务4 :多个学生多门成绩的排序—〉二维数组
2、项目任务4程序实现分析说明
【项目程序实现分析】
(1)输入/输出40个同学三门课的成绩,并进行相应的总分及平均分的计算。使用整型或浮点型二维数组。
(2)本问题同时也涉及姓名的输入/输出,使用一、二维字符数组。
(3)最后按总分的高低进行排序。可选择比较和冒泡排序算法。
【项目程序实现要点】
1)相关数组定义:在前面分析的基础上,还需定义二个一维字符数组保存每个同学的总分和平均。具体数组定义如下:
#define N 5;
int score [N][3]; //score表示N个同学3门课成绩的二维整型数组
char name[N][10],nn[10]; //name表示N个同学姓名的二维字符数组,nn是交换临时一个学生姓名数组
float sum[N]={0},avg[N]; //N个同学的总分及平均分。
2)多个学生多门成绩总分及平均分的计算和输出。以五个同学三门课的成绩为例,程序实现流程分六步:
[1]涉及三个数组
int score [N][3]; //表示N个同学三门课成绩
int sum[3]={0},avg[3];//总分及平均分一维数组
[2]循环输入五同学三门课的成绩
[3]循环计算每门课的总分及平均分
[4]循环输出五同学三门课的成绩
[5]单循环输出总分
[6]单循环输出平均分
3)用冒泡排序法按总分的高低进行排序。
int sum[N],s;
//大到小冒泡排序算法
for(i=0;i
for(j=0;j
if(sum[j]<sum[j+1])//相邻比较:若前面小,交换大的上前,小的下沉。
{
s=sum[j];
sum [j]=sum[j+1]);
sum[j+1]=s;
}
记住本项目当两个同学的总分进行交换时,还应将该同学的姓名、各科成绩和平均分一同交换。
3、参考源代码:略
4、思考:如何理解冒泡排序算法中循环控制变量i,j的变化范围的设置?
实训目的:
1. 掌握函数数组参数的定义与调用
2. 初步掌握函数数组参数的应用
3. 初步掌握模块化程序设计方法
实训内容:
一个班有40位学生(分成五个组,但每个组的人数不一样)参加了期终考试(考了三门课,分别是数学、语文、英语),老师想分以下几个方面统计信息:
1、统计小组一门课程的总分及平均分;
2、统计小组若干门课程的总分及平均分;
3、输出排序后小组三门课成绩单。
请设计一个菜单完成任务选择。
实训指导:
1、任务三功能分解
本任务要完成的功能相对比较多,为了使程序的结构清晰,我们可以采用模块化设计思想,将任务分解为A~D四个函数功能模块:
A:完成三门课成绩的输入;B:计算每个同学的总分与平均分;C:对三门课的成绩进行排序;D:输出函数。
E:总负责,调用A、B、C、D即可。
2、程序实现要点
(1)该任务主函数需定义如下数组:
int score[N][3]; //N个同学3门课成绩
char name[N][10]; //N个同学姓名二维数组,每个姓名长度不超过10个字符
float sum3[N]={0},avg3[N]; //N个同学三门课程的总分及平均分一维数组
(2)四个函数功能模块
A:输入函数,传递N个同学姓名和三门成绩二个数组,声明如下:
void input(int score[N][3],char name[N][10]);
B:计算每个同学的总分与平均分,传递N个同学的姓名、总分和平均分三个数组,声明如下:
void sumavg(int score[N][3],float sum[],float avg[]);
C:排序函数,传递N个同学的姓名、三科成绩、总分和平均分四个数组,声明如下:
void sort(int score[][3],float sum[],float avg[],char name[][10]);
D:输出函数,参数同上,声明如下:
void print(int score[ ][3],float sum3[ ],float avg3[ ],char name[ ][10]);
3、参考源代码(略)
任务拓展:
设计一个程序,随机输入10个整数到数组,输出其中最小数的位置。要求编写一个函数 int GetMinValuePosition(int[] x, int n); 计算返回n个整数数组的最小元素下标来实现。
实训目的:
1、掌握指针的加减运算、关系运算和赋值运算
2、理解指针和数组的关系,掌握访问数组元素的三种方法
3、初步应用指针解决实际问题
实训内容:
一个班有40位学生参加了期终考试(考了三门课),请用指针编程优化学生成绩排名。即用指针实现数组的输入输出以及数组的排序(在函数中进行)。
实训指导:
1、相关指针知识点
(1)指针概念三层含义
指针是一种数据类型;
指针类型的内存单元存储的是一种特殊数据,即地址量;
该地址指向某种数据类型的数据(变量)
引入的目的是通过地址直接访问指向的对象内存单元。
(2)指针变量及运算
指针变量的声明、初始化与引用,需要使用两个特殊运算符:*引用运算符和&取地址运算符。
指针类型变量还有自己的运算:指针的加减运算、关系运算和赋值运算
指针和数组的关系极为密切,通常指针和数组可以互换。
(3)指针和数组关系
对于 int a[10], *pa;有 pa=&a[0]; 或 pa=a;
a) 一般地,指针和同类型数组初始化或赋值,其实质是指向同一个对象。
b)一般地,数组元素的下标访问 a[i]等价于地址访问 *(a+i),等价于对应的指针访问 *(pa+i)
c)数组名和指针(变量)是有区别的,数组名是指针常量,而后者是指针变量。
可以写pa=a; 但不能写 a=pa;或a++; //不能改变常量a的值。
不能写 pa = &a; //不能取常量a的地址。
d)指针比数组运算速度快,传递效率高;但数组可读性好。
e)一维字符数组与字符指针的差异
例如:
char word[20]=“you can do this!”;//字符数组
word=“you can’t do this!”;//错误,数组名word是常量,不能改变常量word的值。
char * p=“point to string.”; //字符指针
p=word;//允许
p=“point to me again.”;//允许,把字符串常量的第一个字符指针赋给字符指针变量p
(4)访问数组的三种方法:
–下标法:使用数组名和下标 a [ i ]
–地址法:使用数组名和指针运算*(a+i)
–指针法:使用指针变量 p=a; *p++
2、项目分析
要用指针优化学生成绩排名,第一必须要了解指针的概念、引用;第二必须会用指针实现数组的输入输出;第三在函数中用指针实现数组的排序,然后调用此函数。为此分解成4个任务。
任务1:指针优化全班同学一门课成绩的输入输出
任务2:指针优化一个班同学三门课成绩的输入输出
任务3:指针实现输出最高分的记录
任务4:指针优化学生姓名的排序
3、任务2三种具体实现方法:
方法一:下标法(常用,很直观)
#include
main()
{int score[10],i;
printf("请输入10个学生的成绩\n");
for(i=0;i<10;i++)
scanf("%d",&score [i]);
printf("输出的10个学生的成绩为\n");
for(i=0;i<10;i++)
printf("%3d", score [i]);
printf("\n");
}
方法二:用数组名访问(效率与下标法相同,不常用)
#include
main()
{int score[10],i;
printf("请输入10个学生的成绩\n");
for(i=0;i<10;i++)
scanf("%d",& score [i]);
printf("输出的10个学生的成绩为\n");
for(i=0;i<10;i++)
printf("%3d", *(score+i));
printf("\n");
}
方法三:用指针变量访问(常用,效率高)
#include
main()
{int score[10],*p,i;
printf("请输入10个学生的成绩\n");
for(i=0;i<10;i++)
scanf("%d",& score [i]);
printf("输出的10个学生的成绩为\n");
for(p=score;p
printf("%3d", *p);
printf("\n");}
任务拓展:输入a、b、c 3个整数,按从大到小顺序输出。
实训目的:
1、掌握结构体类型及结构体数组使用方法
2、初步应用结构体数组解决实际问题
实训内容:
编程:在键盘中读入一个班学生的相关数据(学号,姓名,三门课的成绩),输出按照平均分数从高到低进行排序后的成绩单。(程序运行时为了方便,只输入五个学生记录)
实训指导:
1、结构体类型相关知识点
(1)结构体类型的定义
如果有一个数据包含下列属性:学号(id)、姓名(name)、性别(sex)、功课1(m1)、功课2(m1)、功课3(m1)、平均分(avg) 。
在C中我们可以用结构体类型将这些不同类型的数据组合成一个有机的整体,以便引用。为此,定义了一个叫stu的结构体类型如下:
struct stu
{
char id[6];
char name[10];
char sex[4];
int m1,m2,m3;
float avg;
}
它包括id、name、sex、m1,m2,m3,avg等不同类型的数据项。
(2)结构体数组
(3)结构体变量和数组的引用和初始化。
2、项目分析
要完成学生成绩单的制作,可以用数组解决,但是如果用结构体数组会显得更科学合理。所以在本项目中将采用结构体数组进行编程设计。
具体步骤是:首先进行学生信息的输入输出,第二是计算每个同学的三门课的平均分,第三是按平均分的高低排序后输出成绩单。所以这一项目分解为三个任务:
任务1是用结构体数组进行学生信息的输入输出;
任务2是求平均分最高学生的学号、姓名;
任务3是输出学生排序后的成绩单。
3、任务3实现要点提示:
(1)首先要定义一个能存放40个学生学号、姓名、数学、英语、语文、总分、平均分的结构体数组;
(2)然后从键盘上输入40个同学的学号、姓名、数学、英语、语文信息;
(3)第三求每个同学的总分、平均分;
(4)接下来就是求对总分进行排序;
(5)最后输出排序后的成绩单。
4、任务3程序源代码
#include "stdio.h"
#define N 5/* 假设只有5个同学*/
main()
{struct
{char id[6],name[10];
int m1,m2,m3;
float sum,avg;}stu1[N],t;
int i,j;
printf("请输入学生的信息\n");
for(i=0;i
scanf("%s%s%d%d%d",stu1[i].id,stu1[i].name,&stu1[i].m1,&stu1[i].m2,&stu1[i].m3);
for(i=0;i
{stu1[i].sum=stu1[i].m1+stu1[i].m2+stu1[i].m3;
stu1[i].avg=stu1[i].sum/3.0;}
for(i=0;i
for(j=0;j
if(stu1[j].sum
{t=stu1[j];stu1[j]=stu1[j+1];stu1[j+1]=t;}
printf("排序后的成绩单为:\n");
printf("学号\t姓名\t数学\t语文\t英语\t总分\t平均分\n");
for(i=0;i
printf("%s\t%s\t%d\t%d\t%d\t%.1f\t%.1f\n",stu1[i].id,stu1[i].name,stu1[i].m1,
stu1[i].m2,stu1[i].m3,stu1[i].sum,stu1[i].avg);
}
任务拓展:
某公司有5个职员,包括职员工号、姓名、性别和工资,编程要求如下:
1、 以工资的高低进行排序并输出。
2、 输出工资最高和最低的员工姓名。
3、 下表为原始数据,进行调试运行,记录其结果。
num |
name |
sex |
salary. |
98160101 |
杨红霞 |
女 |
2292 |
98160102 |
郑斌华 |
男 |
2312 |
98160103 |
方智慧 |
女 |
2567 |
98160104 |
刘松树 |
男 |
2876 |
98160105 |
李小明 |
男 |
3563 |