“把数字转化为七段数码管形式并打印”——怎样用c实现?
#include <stdio.h>
bool brush[11][78]; //from: show
int No_=0; //from: add
void draw_stroke(int No_,int n)
{ //master:add
int i;
int a0 = No_ * 11;
switch(n) //(stroke n)
{
case 1: for(i=0;i<4;++i)brush[i+1][a0]=1;break;
case 2: for(i=0;i<4;++i)brush[i+1][a0+9]=1;break;
case 3: for(i=0;i<4;++i)brush[i+6][a0]=1;break;
case 4: for(i=0;i<4;++i)brush[i+6][a0+9]=1;break;
case 5: for(i=0;i<8;++i)brush[0][a0+1+i]=1;break;
case 6: for(i=0;i<8;++i)brush[5][a0+1+i]=1;break;
case 7: for(i=0;i<8;++i)brush[10][a0+1+i]=1;break;
}
}
bool f1(char* s,int i)
{ //master: has_stroke
return *(s+i-1)-'0';
}
bool has_stroke(char letter,int i)
{ //master: add
switch(letter)
{ case '0':return f1("1111101",i);
case '1':return f1("0101000",i);
case '2':return f1("0110111",i);
case '3':return f1("0101111",i);
case '4':return f1("1101010",i);
case '5':return f1("1001111",i);
case '6':return f1("1011111",i);
case '7':return f1("0101100",i);
case '8':return f1("1111111",i);
case '9':return f1("1101111",i);
case ' ':return f1("0000000",i);
default:printf("No num or space");
}
return 0; //dead code
}
void add(char letter)
{ //master: do_brush
if(No_>=10)
{ printf("here's a too-long line");
return ;
}
else
{
int i;
for(i=1;i<=7;++i)if(has_stroke(letter,i))draw_stroke(No_,i);
++No_;
}
}
void do_brush(char* s)
{ //master: show
char R;
while(1)
{ R=*s++;
if(R=='\0')break;
add(R);
}
}
void print_mat(bool* mat,int a,int h)
{ //master: print_brush
//need: mat, a, h
int x,y;
for(y=0;y<h;++y)
{ for(x=0;x<a;++x)
{ if(*(mat+y*a+x))printf("%%");else printf(" ");
}
printf("\n");
}
printf("\n");
}
void print_brush()
{ //master: show
print_mat(*brush,78,11);
}
void show(char* s)
{ //master: main
//need: few numbers;
do_brush(s);
print_brush();
}
int main()
{ //
show("12345");
}
这段代码是挺长时间前写的了,以至于我翻出来的时候都觉得陌生。main函数只有一行——我不知道这种风格是否普遍,但我觉得这是个很好的参照。这段代码我是从最后一个函数往上写的,整个过程很自然——需要某个功能,就创建一个通用的函数,然后传递特定的参数给它。但是阅读起来不免有些奇怪,这也是今天我敲代码时遇到的问题。我学的第一门编程语言是python,所以我一直信奉“代码应当看起来自然”。对于这个简单的小程序,倒着读也并非不自然,但有几个问题——
- 这个程序对于一行以上的数字会出现bug
- 对于main和show函数,行数都极其少,有必要放进一个函数吗?它们根本不会被再次使用。(还有2个这样的函数)
- 当一个函数引用了多个函数,阅读的时候就会跳来跳去。
第一条根本不是缺点,这是这种模式的优点。bug可以确认在某个函数里,在函数中排错就可以了。对于第二条,有一种做法是不分成函数,而是分割代码块,在一旁写注释。显然引用函数可能会让速度变慢(写这篇文章是因为在python中遇到了这一问题),尤其是在循环中,但是大块的代码同样让人不舒服。理论上可以用宏——然而我并不熟悉宏。但是这好像不是问题的核心——“少量代码该装在函数里吗?”事实上,注释加折叠可以完美解决,但是我用的geany不支持——我也不知道有什么编辑器支持 (戛然而止) 好吧,是可以折叠。但是原问题还可以问:短代码该折叠吗?比如show函数,注释比函数体还长。我当然坚持观点:有写的必要。我想也许存在一些即使对于稍长的代码也不加注释的人——我知道注释不是必须,混乱的代码才需要注释(《程序员的修炼之道》),但是仅靠标识符并不完全能体现信息——当两个函数先后使用,无论哪一个的名称、形式都不一定能直观地体现出整体效果。而我们解决问题的时候,也做不到一下子就把问题拆散。我们拆解的每一步都有存在的意义,注释包含着我们思考的信息。当然我得去体验一下传说中vim的代码折叠了——c#的折叠格式并不让人喜欢,虽说只是细节——另外第三个问题随之解决了一半,代码块可以折叠,但函数必须在使用前定义,并不能折叠。这是个小细节,或许已经有某个语言发展出了这个特性?我不知道。或许,根本不是语言的问题,而是编辑器的函数跳转问题?…… 所以,自己扩展编辑器的特性大概是个很好的选择,听说vim之类就有这功能,不如下个emacs试试看?当然自己写个编辑器估计也可以,但是说起来我写这篇文章的原因就是—— 我在用python写一个命令行编辑器。
(2017-12-30 于地球)