精品案例-用C语言实现成绩与等级相互转换
题目要求:
用C语言编写代码,完成成绩与等级,等级与成绩范围的转换,具体要求如下:
- 设计和实现函数,输入成绩,给出成绩对应的等级
 - 设计和实现函数,输入等级,给出等级对应的成绩范围
 - 编写测试代码,完成测试
 
成绩与等级的对应关系如下表:
成绩范围  | 对应的等级  | 
90 <= 成绩 <=100  | A  | 
80 <= 成绩 < 90  | B  | 
70 <= 成绩 < 80  | C  | 
60 <= 成绩 < 70  | D  | 
成绩 <60  | E  | 
补充说明:
假设成绩是整数,不考虑成绩带小数的情况。
实现
入门级实现
咋一看这个题目,太简单了,if-else或switch-case直接就能解决问题,放到《企业级C语言精品案例》中这也太搞笑了吧。于是乎有了如下代码实现:
- 成绩转等级
 
int main()
{
    int score;
    
    printf("成绩转等级,请输入成绩(0~100)\n");
    scanf("%d", &score);
    if (score < 60) {
        printf("成绩%d对应的等级为E\n", score);
    }
    else if (score < 70) {
        printf("成绩%d对应的等级为D\n", score);
    }
    else if (score < 80) {
        printf("成绩%d对应的等级为C\n", score);
    }
    else if (score < 90) {
        printf("成绩%d对应的等级为B\n", score);
    }
    else if (score < 101) {
        printf("成绩%d对应的等级为A\n", score);
    }
    else {
        printf("成绩%不在合理的范围\n");
    }
    
    return 0;
}- 等级转成绩区间
 
int main()
{
    char grade;
    
    printf("等级转成绩区间,请输入等级(A~E):\n");
    scanf("%c", &grade);
    switch(grade) {
        case 'A':
        case 'a':
            printf("等级%c对应的成绩区间为:90 ~ 100", grade);
            break;
        case 'B':
        case 'b':
            printf("等级%c对应的成绩区间为:80 ~ 89", grade);
            break;
        case 'C':
        case 'c':
            printf("等级%c对应的成绩区间为:70 ~ 79", grade);
            break;
        case 'D':
        case 'd':
            printf("等级%c对应的成绩区间为:60 ~ 69", grade);
            break;
        case 'E':
        case 'e':
            printf("等级%c对应的成绩区间为:0 ~ 59", grade);
            break;
        default:
            printf("输入不合法:%c", grade);
            break;
    }
    
    return 0;
}中级实现
初级实现,实现了功能但不易复用,代码全写在main()函数中在本项目或其他需要该算法的项目中无法直接使用;另外,如果A项目与用户交互的界面是命令行,B项目与用户交互通过GUI界面,这段代码做不到在2个项目中通用。
代码片段要做到易复用,需要与输入函数和输出函数解耦,简单讲就是其中不要调用类似printf和scanf之类的函数,可以通过参数和返回值来做数据传递,参数从哪里来,返回值怎么使用,完全由函数调用方决定,这样就可以实现代码的高复用。第二版代码:
- 成绩转等级
 
char score_to_grade(uint8_t score, char *grade)
{
    char grade;
    if (score < 60) {
        grade = 'E';
    }
    else if (score < 70) {
        grade = 'D';
    }
    else if (score < 80) {
        grade = 'C';
    }
    else if (score < 90) {
        grade = 'B';
    }
    else if (score < 101) {
        grade = 'A';
    }
    else {
    }
    return grade;
}- 等级转成绩区间
 
由于等级对应的成绩区间包括开始分数和结束分数,但一个函数只能有1个返回值,因此考虑使用指针做函数参数,返回值通过指针传递给函数调用方,代码如下:
void grade_to_score(char grade, uint8_t *score_start, uint8_t *score_end)
{
    switch(grade) {
        case 'A':
        case 'a':
            *score_start = 90;
            *score_end = 100;
            break;
        case 'B':
        case 'b':
            *score_start = 80;
            *score_end = 89;
            break;
        case 'C':
        case 'c':
            *score_start = 70;
            *score_end = 79;
            break;
        case 'D':
        case 'd':
            *score_start = 60;
            *score_end = 69;
            break;
        case 'E':
        case 'e':
            *score_start = 0;
            *score_end = 59;
            break;
        default:
            break;
    }
}企业级实现
中级实现,同样完成了功能,但还存在一些考虑不周到的地方,还可以继续“进化”:
- 输出参数超范围怎么办,转换函数调用方无法得知
 - 如果等级与分数的对应关系发生变化,需要改2个函数,漏改一处就产生一个缺陷
 
针对上述2个问题,我们给出解决方案:
- 转换函数的输入,通过参数传入,转换函数的输出通过指针传出,函数的返回值用来表示转换是否成功
 - 我们抽象地思考一下这个问题,等级与成绩区间存在对应关系,我们能否通过一个结构体来描述这种对应关系呢?结构体配合算法完成相互转换的逻辑
 
企业级实现是这样的:
- 头文件:
 
/******************************************************************************
 *  Copyright 2022
 *
 *  @file    grade_score.h
 *
 *  @brief   
 *
 *=============================================================================
 *  Revision History
 *  Version     Date        Author      Content
 *  -------     ----------  ---------   ---------------------------------------
 *  V1.00       2022/09/16  yangyf      Create.
 *
 *****************************************************************************/
#ifndef __GRADE_SCORE_H__
#define __GRADE_SCORE_H__
#include <stdint.h>
extern int32_t score_to_grade(uint8_t score, char *grade);
extern int32_t grade_to_score(char grade, uint8_t *score_start, uint8_t *score_end);
#endif /* __GRADE_SCORE_H__ */- 源文件
 
/******************************************************************************
 *  Copyright 2015-2022
 *
 *  @file    grade_score.c
 *
 *  @brief   
 *
 *=============================================================================
 *  Revision History
 *  Version     Date        Author      Content
 *  -------     ----------  ---------   ---------------------------------------
 *  V1.00       2022/09/16  yangyf      Create.
 *
 *****************************************************************************/
/* 定义结构体,描述等级与成绩区间的对应关系 */
typedef struct {
    char grade;
    uint8_t score_start;
    uint8_t score_end;
} grade_score_item_t;
/* 定义结构体数组,描述具体等级与具体成绩区间的对应关系 */
/* 这里注意static和const的使用 */
static const grade_score_item_t grade_score_map[] = {
    {'E', 0, 59},
    {'D', 60, 69},
    {'C', 70, 79},
    {'B', 80, 89},
    {'A', 90, 100}
};
/* 为方便扩展,定义一个自动计算数组元素数量的宏 */
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
/******************************************************************************
 *
 * FUNCTIONS
 *
 *****************************************************************************/
/******************************************************************************
 *  @fn      int32_t score_to_grade(uint8_t score, char *grade)
 *
 *  @brief   成绩转等级
 *
 *  @param   uint8_t score [I/] 成绩
 *           char *grade   [/O] 成绩对应的等级
 *
 *  @return  0: 转换成功; 非零值:转换失败
 */
int32_t score_to_grade(uint8_t score, char *grade)
{
    int32_t ret = -1;
    for (int i = 0; i < ARRAY_SIZE(grade_score_map); ++i) {
        if ((grade_score_map[i].score_start <= score)
                && (score <= grade_score_map[i].score_end)) {
            *grade = grade_score_map[i].grade;
            ret = 0;
            break;
        }
    }
    return ret;
}
/******************************************************************************
 *  @fn      int32_t grade_to_score(char grade, uint8_t *score_start, uint8_t *score_end)
 *
 *  @brief   等级转成绩区间
 *
 *  @param   char grade [I/] 等级
 *           uint8_t *score_start [/O] 成绩区间开始值
 *           uint8_t *score_end   [/O] 成绩区间结束值
 *
 *  @return  0: 转换成功; 非零值:转换失败
 */
int32_t grade_to_score(char grade, uint8_t *score_start, uint8_t *score_end)
{
    int32_t ret = -1;
    if (('a' <= grade) && (grade <= 'z')) {
        grade = grade - 0x20;   /* a=>A, b=>B, ..., z=>Z */
    }
    for (int i = 0; i < ARRAY_SIZE(grade_score_map); ++i) {
        if (grade == grade_score_map[i].grade) {
            *score_start = grade_score_map[i].score_start;
            *score_end = grade_score_map[i].score_end;
            ret = 0;
            break;
        }
    }
    return ret;
}
/* - End Of File - */
企业级实现的代码,严格遵守了《企业级C语言精品案例》中“C语言编码规范”章节中的各项规则;做到了输入函数输出函数与主体算法的分离;体现了“程序 = 数据结构 + 算法”的思想,做到了易复用,易维护。
- 算法测试代码
 
/******************************************************************************
 *  Copyright 2015-2022
 *
 *  @file    grade_score_test.c
 *
 *  @brief   
 *
 *=============================================================================
 *  Revision History
 *  Version     Date        Author      Content
 *  -------     ----------  ---------   ---------------------------------------
 *  V1.00       2022/09/16  yangyf      Create.
 *
 *****************************************************************************/
#include "grade_score.h"
/******************************************************************************
 *
 * FUNCTIONS
 *
 *****************************************************************************/
int main()
{
    int32_t ret;
    uint8_t score;
    char grade;
    printf("Please input score(0 ~ 100):");
    scanf("%d", &score);
    getchar();
    ret = score_to_grade(score, &grade);
    if (0 == ret) {
        printf("score: %d, grade: %c\n", score, grade);
    }
    else {
        printf("score %d not between 0 and 100\n");
    }
    uint8_t score_start, score_end;
    printf("Please input grade(A ~ E):");
    scanf("%c", &grade);
    getchar();
    ret = grade_to_score(grade, &score_start, &score_end);
    if (0 == ret) {
        printf("grade: %c, score: from %d to %d\n", grade, score_start, score_end);
    }
    else {
        printf("grade %c not between A and E\n");
    }
    return 0;
}
/* - End Of File - */~ END ~
相关文章
- Spring Boot中对接Twilio以实现发送验证码和验证短信码
 - Spring Boot 3.5:这次更新让你连配置都不用写了,惊不惊喜?
 - Spring Boot+Pinot实战:毫秒级实时竞价系统构建
 - SpringBoot敏感配置项加密与解密实战
 - SpringBoot 注解最全详解,建议收藏!
 - Spring Boot 常用注解大全:从入门到进阶
 - SpringBoot启动之谜:@SpringBootApplication如何让配置化繁为简
 - Springboot集成Kafka原理_spring集成kafka的原理
 - Spring Boot中@Data注解的深度解析与实战应用
 - 大佬用1000字就把SpringBoot的配置文件讲的明明白白!
 
