C 程序设计实例 1. 问题描述 2. 数据结构 3. 算法分析 4. 参考程序 5. 改进说明
实例 :学生成绩处理 1. 问题描述 进行若干个学生、 若干门课程的成绩处理: (1) 计算每门课程平均分和方差; (2) 计算每个学生总分、 平均分; (3) 按总分对学生由高分到低分排序。
(1) 学生人数假定不超过1000人, 课程门数假定不超过30门,分别用符号常量 N、M 存储 2. 数据结构 (1) 学生人数假定不超过1000人, 课程门数假定不超过30门,分别用符号常量 N、M 存储 (2) 实际学生人数及课程门数分别用整型量 n、m 存储 (3) M 门课程的名称用二维字符数组 sname 存储 (4) 学生信息包括:学号(num)、姓名(name)、M门课程成绩,用结构类型 stt 描述,其中 M 门课的成绩用一维数组 score 存储 (5) N 个学生的信息用结构数组 sta 存储
(6) 每门课程的平均分、方差用一维实型数组avs1、 svs1 保存 2. 数据结构(续) (6) 每门课程的平均分、方差用一维实型数组avs1、 svs1 保存 (7) 每个学生的总分、 平均分用一维实型数组 total、 avs2 保存,学生平均分的方差用实数变量 svs2 保存 (8) 排序结果采用一个序号数组 sort 间接保存 以上变量均是全局变量,用于在函数间传递数据 (9) 数据输入文件、结果输出文件分别用字符指针变量 ps、pt 与文件指针变量 fps、fpt 描述
2. 数据结构(续) (10) 中间变量i、 j、 k:i 用于循环中控制学生, j 用于循环中控制课程,k 对应总分最高的学生序号 (11) 数据输入文件格式:前面存放学生实际人数、 实际课程门数与课程名称 (12) 结果输出文件格式:学生数据及其总分、平均分及名次,课程平均分、方差和学生平均分的方差存放于文件最后
3. 算法分析 (1) 程序结构:由若干函数模块组成 主控模块 main() 输入控制模块 input() 键盘输入模块 kinput() 文件输入模块 finput() 每门课程平均分、方差计算模块 asfun() 每个学生的总分、平均分及其方差计算模块 tasfun() 排序模块 sortfun() 输出模块 output()
3. 算法分析 (2)数据输入: 学生实际人数 n 课程实际门数 m 原始成绩数据 第一次由键盘输入,并写入磁盘文件 SCORE.DAT 以后数据可直接从上述文件读取
3. 算法分析 (3) 方差计算 (4) 总成绩排序 (5) 处理结果 方差 = 数据平方和的平均值减去数据平均值的平方 采用简单选择排序 若方差值大,则表示数据值之间的差别较大;反之,若方差值小,则表示数据值之间的差别较小 (4) 总成绩排序 采用简单选择排序 利用序号数组保存学生名次,无需交换数据 (5) 处理结果 与原始成绩数据合并,写入磁盘文件STUDEN.DAT
#include "stdio.h" /* 标准输入输出 */ #include "math.h" /* 标准数学函数*/ 4. 参考程序 (1) #include "stdio.h" /* 标准输入输出 */ #include "math.h" /* 标准数学函数*/ #define N 1000 /* 最大学生人数 */ #define M 30 /* 最大课程门数*/ void input (); /* 学生数据输入控制 */ void kinput (); /* 键盘输入学生数据 */ void finput (); /* 文件读入学生数据 */ void asfun (); /* 课程平均及方差计算 */ void tasfun (); /* 学生总分、平均分及方差计算 */ void sortfun (); /* 成绩排序 */ void output (); /* 输出学生数据 */
float score[M]; /* 成绩数组 */ } sta[N]; /* 保存学生数据的数组 */ 4. 参考程序 (2) /*** 以下为全局变量声明 ***/ int n, /* 学生实际人数 */ m; /* 课程实际门数 */ /* 学生数据结构体 */ struct stt { int num; /* 学号*/ char *name; /* 姓名 */ float score[M]; /* 成绩数组 */ } sta[N]; /* 保存学生数据的数组 */ char sname[M][16]; /* 课程名称数组,名称长度不超过16个字符 */
float avs1[M], /* 课程平均分数组 */ svs1[M]; /* 课程方差数组 */ 4. 参考程序 (3) /*** 以下为全局变量声明(续) ***/ float avs1[M], /* 课程平均分数组 */ svs1[M]; /* 课程方差数组 */ float total[N], /* 学生总分数组*/ avs2[N], /* 学生平均分数组 */ svs2; /* 学生平均分的方差 */ int sort[N]; /* 排序用的序号数组 */ /* 元素值 = 学生数据在结构体数组 sta 中的下标 */
#include <stdio.h> #include <stdlib.h> 4. 参考程序 (4) /*主函数*/ #include <stdio.h> #include <stdlib.h> #include <string.h> void main () { input( ); /* 输入 */ asfun( ); /* 课程计算 */ tasfun( ); /* 学生计算 */ sortfun( ); /* 排序 */ output( ); /* 输出 */ }
4. 参考程序 (5) void input( ) { /*获取原始数据的子函数*/ char ch; printf("请选择数据源(K-键盘输入 F-磁盘文件读取): \n"); ch=getch( ); if(ch==‘K’||ch=='k') { /* 键盘输入*/ kinput(); else if(ch=='F'||ch=='f')/*从磁盘文件读取数据*/ finput(); else { printf("数据源选择错误!"); } }
4. 参考程序 (6) void kinput( ) { /* 键盘输入原始数据子函数 */ int i, j; char *ps; printf("请输入实际学生人数: "); scanf("%d", &n); printf("请输入实际课程门数: "); scanf("%d", &m); if(n<=0||n>N || m<=0 ||m> M ) { printf("数据无效!"); exit(0); } printf("请输入%d门课程名称: ",m); for(j=0; j<m; j++) scanf("%s", sname[j]);
4. 参考程序 (7) for(i=0; i<n; i++) { printf("请输入第%d个学生学号,姓名,%d门课程成绩:",i+1,m); scanf("%d%s",&sta[i].num,sta[i].name); for(j=0; j<m; j++) scanf("%f", &sta[i].score[j]); } /* 后续代码:将键盘输入数据写入文件 */
4. 参考程序 (8) ps=“SCORE.DAT”; /*输入数据送文件保存*/ if((fps=fopen(ps, “wb”))= =NULL) {/* 二进制写 */ printf("文件建立错误!"); exit(0); } fwrite(&n, 2, 1, fps); fwrite(&m, 2, 1, fps); fwrite(sname, 16, m, fps); fwrite(sta, sizeof(struct stt), n, fps); fclose(fps); } /* end kinput() */
4. 参考程序 (9) void finput( ) { /*从文件读取原始数据子函数*/ char *ps; FILE *fps; printf("请输入数据文件名: "); scanf("%s", ps); if((fps=fopen(ps, "rb"))==NULL){ /* 二进制读 */ printf("文件打开错误!"); exit(0); } fread (&n, 2, 1, fps); fread (&m, 2, 1, fps); fread (sname, 16, m, fps); fread (sta, sizeof(struct stt), n, fps); fclose (fps); }
4. 参考程序 (10) void asfun( ) {/*计算课程平均分、方差子函数*/ int i , j ; float t[M], ts[M]; for(j=0; j<m; j++){ t[j]=0; ts[j]=0; for(i=0; i<n; i++){ t[j]+=sta [i].score[j]; ts[j]+=sta [i].score[j]*sta [i].score[j]; } avs1[j]=t[j]/n; sus1[j]=ts[j]/n- avs1[j]* avs1[j]; }
4. 参考程序 (11) void tasfun( ) {/*计算学生总分、 平均分及其方差子函数*/ int i, j; float ta=0, ts=0; for(i=0; i<n; i++){ total[i]=0; for(j=0; j<m; j++) total[i]+=sta [i].score[j]; avs2[i]=total[i]/n; ta+=avs2[i]; ts+=avs2[i]*avs2[i]; } svs2=ts/n-(ta/n)*(ta/n);
4. 参考程序 (12) void sortfun( ) { /*按总分排序子函数*/ int i, j, k; for(i=0; i<n; i++){ k=i; for ( j = i+1; j<m; j++ ) if ( total[j] > total[k] ) k = j; sort[i]=k+1; }
4. 参考程序 (13) void output( ) {/*输出数据子函数*/ int i, l, j; int is; printf("%d个学生%d门课程成绩数据如下: \n"); printf(" 学号 姓名 "); for(j=0; j<m; j++) printf("%16s", sname[j]); printf(" | 总分 平均分 名次\n"); for(i=0; i<n; i++){ for(l=0; l<n; l++)
if(sort[l]==i+1) is=l; printf("%8d%12s", sta[is].num, sta[is].name); 4. 参考程序 (14) if(sort[l]==i+1) is=l; printf("%8d%12s", sta[is].num, sta[is].name); for(j=0; j<m; j++) printf("%16.2f", sta[is].score[j]); printf("| %8.2f%8.2f%6d\n",total[is],avs2[is],sort[is]); } printf(" 课程平均分 "); for(j=0; j<m; j++) printf("%16.2f", avs1[j]); printf("\n"); printf(" 方差 ");
4. 参考程序 (15) for(j=0; j<m; j++) printf("%16.2f", sus1[j]); printf("%16.2\n", svs2); pt=“STUDENT.DAT”; /*输出数据写入文件 */ if((fpt=fopen(pt, "wb"))==NULL) { printf("文件建立错误!"); exit(0); } fwrite(&n, 2, 1, fpt); fwrite(&m, 2, 1, fpt); fwrite(sname, 16, m, fpt); for(i=0; i<n; i++) {
4. 参考程序 (16) fwrite(&sta[i], sizeof(struct stt), 1, fpt); fwrite(&total[i], 4, 1, fpt); fwrite(&avs2[i], 4, 1, fpt); fwrite(&sort[i], 2, 1, fpt); } fwrite(avs1, 4, m, fpt); fwrite(&svs2, 4, 1, fpt); fclose(fpt); }
5. 改进说明 (1) 数据输入文件可用记事本直接建立 (2) 程序实现可以不用数组,而用链表 (3) 函数之间数据可改用参数传递