大四重写大一的C语言大作业是一种怎样的体验

序言

在整理文件时偶然发现大一时的C语言大作业,故突然心血来潮想看看曾经花费一个星期的成果。

它虽然只有一个文件,却足足有829行,可见当时我下了多大功夫。回忆起当时作业的要求,大致也不过是实现一个可以增删改记录的学生成绩管理系统,何至于要写829行呢?找到源码配备的文档,想起那些我绞尽脑汁想出来的诸多花哨的功能,我不禁感慨:年轻就是能折腾啊!

而在我准备仔细拜读时,我却高兴不起来了——我根本看不懂也不想看懂我的代码!尽管我读过很多很烂的代码,但当发现自己曾经的骄傲之作其实是一片垃圾不堪入目时,我还是十分难受。

记得老师布置大作业的时候鼓励我们多写代码,多添加功能,于是我就认为代码越多越好,并添加了很多古怪的功能。而现在我很清楚:代码不是拼数量的,而是拼质量的,功能设计也不是越丰富越好,为意义不大的功能耗费精力是不值得的。

好的代码?

回顾我学习C的一点点经历,感慨曾经有太多对编程语言的误解:

  1. 狂热于语言技巧 死记运算符优先级,死钻语言特性的行为就是走火入魔,语言是为我们服务的,好用的特性就用,不好用的特性应当避免。以前以为一个人知道越多的语言特性就越懂一门语言,现在才明白懂如何用一门语言比探究语言本身更重要。
  2. 误以为代码越难懂越好 曾以为只有自己能看懂的程序才算高大上,肆无忌惮地使用“#”、“##”、“#@”预处理运算符,滥用那些鲜为人知的宏替换的技巧。不仅降低了自己写代码的效率,还增加了别人阅读的时间,到最后写出的代码连自己也看不懂。
  3. 盲目追求运行效率 曾参加智能车比赛,为了提高车速,误以为变量名改短,数组展开成简单变量,循环展开…等就能提高程序运行速度,简直愚蠢之极。(想象力太丰富不一定是好事,要多看书,少瞎想)
  4. 不愿分享代码 曾以为代码是自己辛勤劳动所得,如果给了别人就没有价值了。现在才明白代码就像一件艺术品,没有人看它,它也就没有价值了。

我想,写代码应当努力达到作诗般简练优雅:

  • 不追求平仄交替,只求抒发情感,表达思想
  • 不追求辞藻华丽,只求通俗易懂,老妪能解

这样的好代码才能被人们clone、star、传诵。

重写代码!

万千的感慨令我不禁神游了一阵子,回过神,想起大四没有课,也算是有点闲时间,于是想改改这份代码。可当我发现几乎所有地方都有毛病时且不想再看逻辑混乱的代码时,我又改了主意,哎,还是重写吧!

总算是把800多行改成200多行了,程序讲解见我的Github博客,希望对刚学完C语言的同学们有所帮助。本人能力有限,如有前辈愿意点拨,敬请在本文后评论,不胜感激!

最后附上代码:

/*
 * Student Information Manager
 * https://baidut.github.io/ | Released under MIT license
 * Copyright (c) 2015 Zhenqiang.Ying <[email protected]>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX      100
#define NAME_LEN 10

typedef struct {
    char name[NAME_LEN];
    unsigned int score[3];
    unsigned int sum;
} Stu_t;

Stu_t   stu[MAX];
int     num;

Stu_t   input_stu(void);                    // 通过提示引导用户正确地输入一条学生记录,并返回这条记录
void    output_stu(int i);                  // 根据数组索引打印出对应的学生信息
int     find_stu(void);                     // 通过提示引导用户查找记录,如果找到则显示查找到的记录,并返回数组索引,否则返回-1

void    read_stu(const char *filename);     // 根据文件名读入文件中的学生数据
void    write_stu(const char *filename);    // 将学生数据写入到指定的文件中

int     confirm(const char *words);         // 请求用户确认,输入y或Y返回1,输入n或N返回0,其他情况提示用户重新输入
void    safe_flush(FILE *fp);               // safe_flush(stdin)清理多余的输入,防止影响下次获取输入

int main(void) {
    const char *filename = "stud_info.txt";

    read_stu(filename); // 导入数据
    printf("欢迎使用学生成绩管理系统\n"
           "-当前已有%d条记录,本程序限制%d条记录\n",
           num, MAX);

    for (;;) {
    char choice;
    int i, j;

        printf( "-菜单:\t"
                "1.查找\t"
                "2.追加\t"
                "3.删除\t"
                "4.修改\t"
                "5.排序\t"
                "6.显示\t"
                "7.保存\t"
                "0.退出\n"
                "输入序号:");

        choice = getchar();
        safe_flush(stdin);

        switch (choice) {
        case ‘1‘: // 查找
            find_stu();
            break;
        case ‘2‘: // 追加
            if (num < MAX) {
                stu[num] = input_stu();
                output_stu(num);
                num++;
                puts("追加成功!");
            }
            else puts("记录已满,无法追加!");
            break;
        case ‘3‘: // 删除
            i = find_stu();
            if (-1 != i) {
                if (confirm("确认删除?")) {
                    while (i++ != num) {
                        stu[i-1] = stu[i];
                    }
                    num--;
                    puts("删除成功!");
                }
            }
            break;
        case ‘4‘: // 修改
            i = find_stu();
            if (-1 != i) {
                stu[i] = input_stu();
                output_stu(i);
                puts("修改成功!");
            }
            break;
        case ‘5‘: // 按照总分排序
            for (i = 0; i < num-1; i++)     // 冒泡排序中已经排好的
                for (j=0; j < num-1-i; j++) // 遍历没排好的
                    if ( stu[j].sum < stu[j+1].sum ) {
                        Stu_t t = stu[j];
                        stu[j] = stu[j+1];
                        stu[j+1] = t;
                    }
            puts("排序成功!");
            /* fall through */     // 完成排序后自动显示
        case ‘6‘: // 显示
            for (i = 0; i < num; i++) {
                printf("%4d:\t", i+1);
                output_stu(i);
            }
            break;
        case ‘7‘: // 保存
            write_stu(filename);
            break;
        case ‘0‘: // 退出
            if (confirm("推出前保存?(Y/N)")) {
                write_stu(filename);
            }
            exit(0);
        default:
            puts("没有该序号!请重新输入");
            break;
        }
    } // END for

    return 0;
}

void safe_flush(FILE *fp){
    int ch;
    while ( ch = fgetc(fp), ch != EOF && ch != ‘\n‘);
}

int confirm(const char *words) {
    char choice;
    puts(words);
    for (;;) {
        choice = getchar();
        safe_flush(stdin);

        switch (choice) {
        default:
            puts("输入非法,重新输入!");
            continue;
        case ‘Y‘:
        case ‘y‘:
            puts("已确认!");
            return 1;
        case ‘N‘:
        case ‘n‘:
            puts("已取消!");
            return 0;
        }
    }
}

Stu_t input_stu(void) {
    Stu_t ret;
    puts("依次输入姓名、语文、数学、外语成绩,空格分隔,成绩要求是整数:");
    while ( 4 != scanf("%s%d%d%d", ret.name,
                                  &ret.score[0],
                                  &ret.score[1],
                                  &ret.score[2])) {
        safe_flush(stdin);
        puts("输入有误,请重新输入!");
    }
    safe_flush(stdin);
    ret.sum = ret.score[0] + ret.score[1] + ret.score[2];
    return ret;
}

void output_stu(int i) {
    if (i < 0 || i > MAX) return;
    printf("%s\t语:%d\t数:%d\t外:%d\t总分:%d\n",
                                stu[i].name,
                                stu[i].score[0],
                                stu[i].score[1],
                                stu[i].score[2],
                                stu[i].sum);
}

int find_stu(void) {
    char name[NAME_LEN];
    int i;
    printf("输入姓名(限%d个字符):", NAME_LEN);
    scanf("%s", name);
    safe_flush(stdin);
    for (i = 0; i < num; i++) {
        if (0 == strcmp(stu[i].name, name)) {
            output_stu(i);
            return i;
        }
    }
    puts("没有找到记录!");
    return -1;
}

void read_stu(const char *filename) {
    FILE *fp = fopen(filename, "rt");
    if (NULL != fp) {
        fread(&num, sizeof(int), 1, fp);
        fread(stu, sizeof(Stu_t), num, fp);
    }
    fclose(fp);
}

void write_stu(const char* filename) {
    FILE *fp = fopen(filename, "wt");
    if (NULL != fp) {
        fwrite(&num, sizeof(int), 1, fp);
        fwrite(stu, sizeof(Stu_t), num, fp);
        fclose(fp);
        puts("保存成功!");
    }
    else puts("打开文件失败!");
}

时间: 2024-10-17 20:08:50

大四重写大一的C语言大作业是一种怎样的体验的相关文章

不是所有的大作业都叫微信抢票大作业

为时四周的微信抢票大作业终于接近尾声,回首这段时间,真是感慨万千.不是所有的大作业都是微信抢票大作业,能够让人同时体验产品经理.开发工程师.测试工程师.运维工程师四个角色.经过了微信抢票大作业的洗礼,才知道之前对老师上课讲的内容只是一知半解,只有实践才能出真知. 一.搞开发 讲道理,这次大作业的开发工作其实不是很多.因为框架设计的很好,接口也介绍的很详细,只需要按部就班填坑就可以达到基本要求了. 但是既然助教上课都提到了几个优化方案,比如内存型数据库,异步队列等,好奇如我怎能不试呢.于是就开始给

大一上C语言期末大作业-成绩管理系统

都过了半年的作业了,觉得做过去得留下点什么,所以整理了代码发一下博客. 声明:程序在DevC++下用c文件模式可以正常编译使用.(控制台程序) 程序结构: 下载链接:http://www.selflink.cn/download/C语言期末作业-吕青松-成绩管理系统.zip 程序有些粗糙,不过还是有一些控制台C程序比较实用的函数可以使用.比如欢迎界面动态打印字符函数,带提示读入函数,文件写入函数,登录函数.还有当时为了做的酷炫一点,搜集了很多资料写好的控制台窗口的控制函数,比如窗口标题设置,改变

《Java语言程序设计》大作业报告 九宫格游戏

    <Java语言程序设计>大作业报告     中国石油大学(北京)2015 - 2016 学年第二学期     班级:_____计算机14-1_______ 姓名:_____  许 恺_________________ 学号:______2014011329___________     题意分析 程序首先需要九个可以移动的格子,大小相等,有字符串标示,其次要可以相应鼠标和键盘方向键的控制,可以自由移动,并且与此同时记录步数,最后在满足条件时弹出对话框并显示步数以及是否打破记录,关于打破

[留念贴] C#开发技术期末大作业——星月之痕

明天就要去上海大学参加 2015赛季 ACM/ICPC 最后一场比赛 —— EC-Final,在这之前,顺利地把期末大作业赶出来了. 在这种期末大作业10个人里面有9个是从网上下载的国内计算机水平五六流大学里学习编程,我感到压力很大. 但我依然选择作死——纯手工打造.庆幸的是,历时四天,翘课无数,现在基本完工了. 下载地址:http://pan.baidu.com/s/1pKx6OnL(还有一些小问题,但是逻辑上的BUG不存在了) 下载之后先解压,然后打开DestroyStars\Destroy

第一周大作业1

---恢复内容开始--- 田继平-软件工程-第一次作业 一.自我介绍大家好,我叫田继平,目前就读于东北师范大学信息科学与技术学院计算机技术专业,是一名在读的专硕研一学生,本科就读于北华大学计算机科学技术学院,专业是计算机科学与技术,籍贯吉林省榆树市.二.回答作业问题1.回想一下你曾经对计算机专业的畅想我高考后报考的是计算机科学与技术,当时对计算机技术基本了解为零,当时以为什么东西都会用到计算机,学计算机以后不会找不到工作,刚开学的时候对计算机一窍不通,甚至连优盘拔出来,要单击右键然后弹出都不会,

数据库终期大作业报告

需求分析 现代社会,心血管疾病成为了老年人群体中高发的慢性病,一个社区医生往往需要负责多位患者的诊断工作,如果每位患者都要频繁上门问诊,会给医生带来过大的工作压力,也很难顾及到全部患者. 在信息技术高度普及的当下,完全可以利用互联网思维解决问题,制作一个软件用于实现: l  医生随时掌握所负责病人的血压数据,并为病人提供专业诊断意见. l  病人随时上传血压数据,并从医生处获得治疗意见. 概要设计 1.数据库 数据存放在名为dochelper的MySQL数据库中. 数据库包含4张表:doctor

[现代信息检索]搜索引擎大作业

[现代信息检索]搜索引擎大作业 一.题目要求: 新闻搜索:定向采集3-4个体育新闻网站,实现这些网站信息的抽取.索引和检索.网页数目不少于10万条.能按相关度.时间.热度(需要自己定义)等属性进行排序,能实现相似新闻的自动聚类. 二.题目分析 题目分析:我们将任务分解为四个部分:新闻数据的爬取.倒排索引的构建.向量空间模型的实现 和 前端界面. 主要分为四个模块:网络爬虫.构建索引.文档评分.排序显示.其中模块与模块之间又包含一些子模块,包括:网页信息抽取.数据存储.文本分析.tf-idf 权重

编译原理大作业(用java编写小型GCC 编译器)

以前只用编译器编译程序,现在学完编译原理这门课以后,通过编译大作业,我对编译器的工作原理有了比较清晰的认识 编译器的工作原理 编译器 (Compiler) 是一种将由一种语言编写的程序转换为另一种编程语言的可执行程序. 现代软件对于编译器的需求远甚从前, 究其原因很简单: 作为中间层, 编译器是构建更高层抽象的基础设施. 编译器意欲将人类可阅读的高阶代码, 翻译为机器能运行的低阶代码. 现代编译器的主要工作流程为: 源代码(source code)→ 预处理器(preprocessor)→ 编译

数据库大作业--由python+flask

这个是项目一来是数据库大作业,另一方面也算是再对falsk和python熟悉下,好久不用会忘很快. 界面相比上一个项目好看很多,不过因为时间紧加上只有我一个人写,所以有很多地方逻辑写的比较繁琐,如果是想学习flask还是推荐之前的项目,地址:http://www.cnblogs.com/INnoVationv2/p/5837495.html 寒假回去我会重构下代码,然后再po出来. 不知道怎么做数据库大作业的也可以参考: 所有功能: 三类用户模式: 一.管理员 1.查看所有档案 2.修改档案信息