• C语言实例解析精粹学习笔记——34(用“结构”统计学生成绩)


    实例34:

      设学生信息包括学号、姓名和五门功课的成绩,要求编写输入输出学生信息的函数。在输入学生信息后,以学生成绩的总分从高到低顺序输出学生信息。

    思路:

      程序引入一个结构数组依次存储输入的学生信息,为了在一组学生信息排序时避免交换整个学生结构,另外引入一个存储下标的数组。排序过程中改变学生结构下标的顺序而不是交换整个结构。

    程序代码:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <string.h>
      4 
      5 #define N 2          //学生数据个数,练习时两三个就可以了。
      6 #define SCORES 5     //成绩个数
      7 #define NUMLEN 10    //允许的学号长度
      8 
      9 //学生信息的结构体,包括:学号、姓名、五项成绩
     10 struct std_type{
     11     char no[NUMLEN];
     12     char *name;
     13     int  scores[SCORES];
     14 };
     15 
     16 struct std_type students[N]; //定义一个学生结构体数组
     17 //用于根据学生成绩对输出学生信息的先后进行排序
     18 int    order[N];
     19 int    total[N];
     20 
     21 //函数读取一个学生的信息
     22 int readastu(struct std_type *spt)
     23 {
     24     int len,j;
     25     char buf[120];
     26 
     27     //输入学生的学号信息
     28     //根据原书中的意思,是在进行错误输入时会终止,但实际上还是有些问题的
     29     //目前我还没弄清楚是编译器的问题,还是程序的问题
     30     //感觉像是程序的问题
     31     printf("
    Number              :  ");
     32     if(scanf("%s",buf)==1)
     33         strncpy(spt->no,buf,NUMLEN-1);
     34     else
     35         return 0;
     36 
     37     //输入学生的姓名信息
     38     printf("Name                :  ");
     39     if(scanf("%s",buf)==1)
     40     {
     41         len = strlen(buf);//自己不清楚缓冲区是怎么变化的,strncpy好像只是复制,好像没有清除的功能
     42                           //那么之前输入的学号(Number)也是放在buf缓冲区中,这个学号信息是被
     43                           //清除了吗?是怎么清除的?(有理解上的错误,在文末有补充)
     44         spt->name = (char *)malloc(len+1);
     45         strcpy(spt->name,buf);
     46     }
     47     else
     48         return 0;
     49 
     50     //输入学生的成绩信息
     51     printf("Scores(5 Number)    :  ");
     52     for(j=0; j< SCORES; j++)
     53     {
     54         if(scanf("%d",spt->scores+j)!=1)
     55             break;
     56     }
     57     if(j==0)
     58     {
     59         free((spt->name));
     60         return 0;
     61     }
     62     for(;j<SCORES;j++)
     63         spt->scores[j] = 0;
     64     return 1;
     65 }
     66 
     67 //函数输出一个学生的信息
     68 int writeastu(struct std_type *spt)
     69 {
     70     int i;
     71 
     72     printf("Number    :  %s
    ",spt->no);
     73     printf("Name      :  %s
    ",spt->name);
     74     printf("Scores    :  ");
     75     for(i=0; i<SCORES; i++)
     76         printf("%2d",spt->scores[i]);
     77     printf("
    
    ");
     78 }
     79 
     80 int main()
     81 {
     82     int n,i,j,t;
     83     char check_i;
     84 
     85     for(n=0; n<N; n++) readastu(students+n);//此处和原书代码有些区别
     86 
     87     //采用冒泡法对学生信息数组排序
     88     for(i=0; i<N; i++)
     89     {
     90         order[i] = i;  //预置第i个输入的学生
     91         for(t=0,j=0; j<SCORES; j++) //求第i个学生的总分
     92             t += students[i].scores[j];
     93         total[i] = t;
     94     }
     95 
     96     //冒泡排序
     97     for(i=0; i<n-1; i++) //共扫视n-1遍
     98     {
     99         for(j=0; j<n-1-i; j++)
    100             if(total[order[j]] < total[order[j+1]])
    101             {
    102                 t = order[j];
    103                 order[j] = order[j+1];
    104                 order[j+1] = t;
    105             }
    106     }
    107 
    108     printf("
    
    Do you want to check if your inputs are correct?(Y/N):");
    109     scanf("%s",&check_i);
    110     if(check_i=='y' || check_i=='Y')
    111     for(j=0; j<n; j++)
    112         writeastu(students+order[j]);
    113     else
    114         return 0;
    115 
    116     return 0;
    117 }

      上述代码基本上99%是原书中的源代码,但是发现对于现在的编译器来说是有问题的(WIN7+CodeBlocks16.01),其中一些不解在注释中已标注。

    一、对于学生的学号来说,并不能限制错误输入。

      程序中设置的学号长度为10(NUMLEN),但实际上输入超过10个数字也是可以的,虽然输出结果会截止到10个数字。

      第32行将输入的学号放入buf中,第33行将buf中前10个字符复制到结构体的no中

    二、关于缓冲区的问题

      41行中的注释是我的理解有点问题,

      第39行的代码将我们输入的字符(学生的姓名)放入到buf中,(自己理解的)会覆盖之前输入的学号,所以缓冲区其实是没什么问题的。

    三、对于输入成绩来说,也不能限制输入为5

      当输入多于5个成绩时,输出会出现错误:

    程序多于5个的数值会停留在缓冲区中,影响下一个学生的信息的输入,可以看下图中的例子

    多于五个的成绩,02会被认为是下一个学生的学号,Ed会被认为是下一个学生的姓名;可以在第56后加一句fflush(stdin)来清空缓冲区以避免这种情况,下图是改正后的结果。

    总结:程序吗,总是有可以改进的地方

  • 相关阅读:
    233
    膝为筋之府
    AES 可逆性加密算法
    DES 可逆性加密算法
    Java Swing如何让窗体居中显示
    eclipse 安装插件
    eclipse 搭建Swt 环境
    Java Set元素比较
    Greenplum数据库中系统表gp_ distribution_ policy详解
    Greenplum数据库中系统表pg_class详解
  • 原文地址:https://www.cnblogs.com/llccbb1/p/9757629.html
Copyright © 2020-2023  润新知