“把数字转化为七段数码管形式并打印”——怎样用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 于地球)