您的位置:首页 > 编程语言 > C语言/C++

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

2015-05-05 15:40 435 查看

序言

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

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

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

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

好的代码?

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

狂热于语言技巧 死记运算符优先级,死钻语言特性的行为就是走火入魔,语言是为我们服务的,好用的特性就用,不好用的特性应当避免。以前以为一个人知道越多的语言特性就越懂一门语言,现在才明白懂如何用一门语言比探究语言本身更重要。

误以为代码越难懂越好 曾以为只有自己能看懂的程序才算高大上,肆无忌惮地使用“
#
”、“
##
”、“
#@
”预处理运算符,滥用那些鲜为人知的宏替换的技巧。不仅降低了自己写代码的效率,还增加了别人阅读的时间,到最后写出的代码连自己也看不懂。

盲目追求运行效率 曾参加智能车比赛,为了提高车速,误以为变量名改短,数组展开成简单变量,循环展开…等就能提高程序运行速度,简直愚蠢之极。(想象力太丰富不一定是好事,要多看书,少瞎想)

不愿分享代码 曾以为代码是自己辛勤劳动所得,如果给了别人就没有价值了。现在才明白代码就像一件艺术品,没有人看它,它也就没有价值了。

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

不追求平仄交替,只求抒发情感,表达思想

不追求辞藻华丽,只求通俗易懂,老妪能解

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

重写代码!

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

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

最后附上代码:

/*
* Student Information Manager
* https://baidut.github.io/ | Released under MIT license
* Copyright (c) 2015 Zhenqiang.Ying <yingzhenqiang@gmail.com>
*/

#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("打开文件失败!");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言 编程