实例34:

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

思路:

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

程序代码:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h> #define N 2 //学生数据个数,练习时两三个就可以了。
#define SCORES 5 //成绩个数
#define NUMLEN 10 //允许的学号长度 //学生信息的结构体,包括:学号、姓名、五项成绩
struct std_type{
char no[NUMLEN];
char *name;
int scores[SCORES];
}; struct std_type students[N]; //定义一个学生结构体数组
//用于根据学生成绩对输出学生信息的先后进行排序
int order[N];
int total[N]; //函数读取一个学生的信息
int readastu(struct std_type *spt)
{
int len,j;
char buf[]; //输入学生的学号信息
//根据原书中的意思,是在进行错误输入时会终止,但实际上还是有些问题的
//目前我还没弄清楚是编译器的问题,还是程序的问题
//感觉像是程序的问题
printf("\nNumber : ");
if(scanf("%s",buf)==)
strncpy(spt->no,buf,NUMLEN-);
else
return ; //输入学生的姓名信息
printf("Name : ");
if(scanf("%s",buf)==)
{
len = strlen(buf);//自己不清楚缓冲区是怎么变化的,strncpy好像只是复制,好像没有清除的功能
//那么之前输入的学号(Number)也是放在buf缓冲区中,这个学号信息是被
//清除了吗?是怎么清除的?(有理解上的错误,在文末有补充)
spt->name = (char *)malloc(len+);
strcpy(spt->name,buf);
}
else
return ; //输入学生的成绩信息
printf("Scores(5 Number) : ");
for(j=; j< SCORES; j++)
{
if(scanf("%d",spt->scores+j)!=)
break;
}
if(j==)
{
free((spt->name));
return ;
}
for(;j<SCORES;j++)
spt->scores[j] = ;
return ;
} //函数输出一个学生的信息
int writeastu(struct std_type *spt)
{
int i; printf("Number : %s\n",spt->no);
printf("Name : %s\n",spt->name);
printf("Scores : ");
for(i=; i<SCORES; i++)
printf("%2d",spt->scores[i]);
printf("\n\n");
} int main()
{
int n,i,j,t;
char check_i; for(n=; n<N; n++) readastu(students+n);//此处和原书代码有些区别 //采用冒泡法对学生信息数组排序
for(i=; i<N; i++)
{
order[i] = i; //预置第i个输入的学生
for(t=,j=; j<SCORES; j++) //求第i个学生的总分
t += students[i].scores[j];
total[i] = t;
} //冒泡排序
for(i=; i<n-; i++) //共扫视n-1遍
{
for(j=; j<n--i; j++)
if(total[order[j]] < total[order[j+]])
{
t = order[j];
order[j] = order[j+];
order[j+] = t;
}
} printf("\n\nDo you want to check if your inputs are correct?(Y/N):");
scanf("%s",&check_i);
if(check_i=='y' || check_i=='Y')
for(j=; j<n; j++)
writeastu(students+order[j]);
else
return ; return ;
}

  上述代码基本上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)来清空缓冲区以避免这种情况,下图是改正后的结果。

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

C语言实例解析精粹学习笔记——34(用“结构”统计学生成绩)的更多相关文章

  1. C语言实例解析精粹学习笔记——18

    <C语言实例解析精粹>中编译环境采用的是Turbo C 2.0.但是这个编译器年代久远,较新的编译器对书中的某些例子支持不好,在学习的时候同时做一些笔记. 实例18:将一个无符号整数转换为 ...

  2. C语言实例解析精粹学习笔记——35(报数游戏)

    实例35: 设由n个人站成一圈,分别被编号1,2,3,4,……,n.第一个人从1开始报数,每报数位m的人被从圈中推测,其后的人再次从1开始报数,重复上述过程,直至所有人都从圈中退出. 实例解析: 用链 ...

  3. C语言实例解析精粹学习笔记——42(插入排序)

    实例说明: 将一个整数数组按从小到大的顺序进行排序.(主要学习基本的插入排序和改进的冒泡排序的算法和应用) 思路1: 从第一个数据开始,分别比较其后的数据,若比它小,则将这两个数的位置交换:从第一个数 ...

  4. C语言实例解析精粹学习笔记——36(模拟社会关系)

    实例: 设计一个模拟社会关系的数据结构,每个人的信息用结构表示,包含名字.性别和指向父亲.母亲.配偶.子女的指针(只限两个子女).要求编写以下函数: (1)增加一个新人的函数 (2)建立人与人之间关系 ...

  5. C语言实例解析精粹学习笔记——32

    实例32: 编制一个包含姓名.地址.邮编和电话的通讯录输入和输出函数. 思路解析: 1.用结构体来完成姓名.地址.邮编和电话的组合. 2.结构体指针的使用. 3.malloc的使用 4.scanf函数 ...

  6. C语言实例解析精粹学习笔记——31

    实例31: 判断字符串是否是回文 思路解析: 引入两个指针变量(head和tail),开始时,两指针分别指向字符串的首末字符,当两指针所指字符相等时,两指针分别向后和向前移动一个字符位置,并继续比较, ...

  7. C语言实例解析精粹学习笔记——30

    实例30: 用已知字符串s中的字符,生成由其中n个字符组成的所有字符排列.设n小于字符串s的字符个数,其中s中的字符在每个排列中最多出现一次.例如,对于s[]="abc",n=2, ...

  8. C语言实例解析精粹学习笔记——28

    实例28:从键盘读入实数 题目要求: 编制一个从键盘读入实数的函数readreal(double *rp).函数将读入的实数字符列转换成实数后,利用指针参数rp,将实数存于指针所指向的变量*rp. 思 ...

  9. C语言实例解析精粹学习笔记——19

    实例19:判断正整数n的d进制表示形式是否是回文数(顺着看和倒着看相同的数). 主要思路: 一种方法:将正整数n数转换成d进制的数,逐个比较首尾对应数字,判断是否为回文数. 另一种方法:将正整数n数转 ...

随机推荐

  1. SharePoint中遇到Timeout

    使用SharePoint时会遇到不止一种的timeout(即超时)错误. 如果遇到了timeout, 该怎么区分呢? 大致上SharePoint可以控制和影响的timeout地方如下: 1. Shar ...

  2. AOP的实现

    AOP基于xml配置方式实现 Spring基于xml开发AOP 定义目标类(接口及实现类) /** * 目标类 */ public interface UserService { //业务方法 pub ...

  3. js:JSON对象与JSON字符串转换

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,是理想的数据交换格式. 同时,JSON是 JavaScript 原生格式,这 ...

  4. python 02/100例

    题目 输入某年某月某日,判断这一天是这一年的第几天? 分析 例如:2018年6月19日 天数 = 19天 + 一月天数 + 2月天数 + ... + 6月天数 注意 闰年的2月是29天,如果年份是闰年 ...

  5. Asterisk 对wav格式的支持

    经过测试wav格式文件仅支持PCM 8000kHz 16bit 单声道,非常蛋疼的一个原因,排查了好久! 关于C#支持的一些格式(Mono 单声道 .Stereo 立体声道) // Standard ...

  6. 基于k8s的ES集群定期删除索引

    apiVersion: batch/v1beta1 kind: CronJob metadata: name: elasticsearch namespace: elasticsearch label ...

  7. Intel® Manager for Lustre* software(一)

    Intel® Manager for Lustre* software Installation 软件安装指导目录: 安装IML(Intel® Manager for Lustre* software ...

  8. Smokeping配置调整

    smokeping两种邮件报警方式 一 .自带sendmail报警 修改这两句话to = 收件邮箱,多个逗号分隔from = smokealert@本机IP /usr/local/smokeping/ ...

  9. Linux 进程状态标识 Process State Definition

    From : http://www.linfo.org/process_state.html 译者:李秋豪 进程状态标识是指在进程描述符中状态位的值. 进程,也可被称为任务,是指一个程序运行的实例. ...

  10. VS2012 Getting Started with Owin and Katana

    参考地址:http://www.asp.net/aspnet/overview/owin-and-katana/getting-started-with-owin-and-katana 小提示: 该示 ...