我进入大一的时候写过一些输出图形的小程序,现在想想以前写的程序是比较混乱的,就以输出三角形为例.
我以前是这样写的:
int main()
{
int i, j, n;
printf("Please enter the number of col(1~20):\n");
while(1) {
scanf("%d",&n);
if(1<=n && n<=20) {
break;
} else {
printf("out of range(1~20),please retype:\n");
}
}
for(i=0; i<n; i++) {
for(j=i; j<n-1; j++)
printf(" ");
for(j=0; j<2*i+1; j++)
printf("*");
printf("\n");
}
return 0;
}
功能上完全没有什么问题,但是如果站在软件工程的角度来看,就可以发现这个程序把图形的逻辑形成与输出都混在一起,完全没有经过设计。
比较好的做法是把图形参数的获取与图形的逻辑形成,图形的输出分别分开,这样比较易于理解。
根据新的设计方案,我重新编写了代码
/******************************************************************************
* 程序思想把三角形的参数获取和图形的逻辑形成,图形的输出分开, *
* 这样就只需要关心后面两部分,稍加变动就可以输出各种图形 *
*******************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
typedef struct {//无标识名的结构体申明
int row;
int col;
int *p;
} canvas; //画布结构
int prepare_canvas(canvas *p_cns, /* in/out */
int row, /* in */
int col); /* in */
void get_option(int *row, /* out */
int *col); /* out */
void draw(canvas *p_cns); /*in/out */
void show(const canvas *p_cns);
void release_canvas(canvas *p_cns); /*in/out*/
/* 提供一个宏,方便访问画布上的像素点 */
#define CANVAS_PIXEL(p_cns, i, j) \
*((p_cns)->p + (i) * (p_cns)->col + (j))
int main(int argc, char *argv[]) {
int rt, row, col;
canvas cns;
get_option(&row, &col);
rt = prepare_canvas(&cns, row, col);
if (rt != 0) {
printf("fail to prepare_canvas!\n");
return NULL;
}
draw(&cns); //描点逻辑
show(&cns); //输出逻辑
release_canvas(&cns);//释放结构体空间
return 0;
}
//确定画布的大小
void get_option(int *row, int *col) {
int n;
do {
printf("enter the number of lines:\n");
scanf("%d", &n);
if (n < 1 || n > 20) {
printf("out of range(3~20), please re-enter.\n");
} else {
*row = n;
*col = 2 * n -1;
break;
}
} while (1);
}
//准备画图
int prepare_canvas(canvas *p_cns, int row, int col) {
p_cns->row = row;
p_cns->col = col;
p_cns->p = (int*)malloc(row * col * sizeof(int));//为画布分配空间
if (p_cns->p == NULL) {
printf("fail to malloc the canvas!\n");
return -1;
}
memset(p_cns->p, ' ', row * col * sizeof(int));//将画布上的'像素点'都置为空白
return 0;
}
void draw(canvas *p_cns) { //生成图形逻辑,我们的focus点
int row, col;
for (row = 0; row < p_cns->row; row++) {
for(col =p_cns->row-1-row ; col <= p_cns->row-1+row; col++) {
CANVAS_PIXEL(p_cns, row, col) = '*';
}
}
}
void show(const canvas *p_cns) { //图形的通用输出逻辑,此后无须关注
int row, col;
for (row = 0; row < p_cns->row; row++) {
for (col = 0; col < p_cns->col; col++) {
printf("%c", CANVAS_PIXEL(p_cns, row, col));
}
printf("\n");
}
}
void release_canvas(canvas *p_cns) {
if (p_cns->p != NULL) {
free(p_cns->p);
}
}
这样即使要输出菱形,也只需要改变get_option() 和draw()函数,方便了很多