练习要求我创建一个程序,该程序接收整数n
并打印以下pattern高度为2*n
的<{p}}。
\ * /
\ *** /
\*****/
\***/
\*/
/*\
/***\
/*****\
/ *** \
/ * \
我已经做的是:
void arte(int n)
{
int i, barrasE, aux, espacobarrasE, ebE, espaco;
aux = n;
for(i = 1; i <= n; i++)
{
if(aux < n) //Prints the spaces on the superior part.
{
espacobarrasE = n - aux;
for(ebE = 0; ebE < espacobarrasE; ebE++)
printf(" ");
}
for(barrasE = 1; barrasE <= aux; barrasE++) //Prints the backslashes on the superior part.
{
printf("\\");
break;
}
for(espaco = 1; espaco < n; espaco++)
{
printf(" ");
}
aux = aux - 1;
printf("\n");
}
}
这只打印顶部的反斜杠,我不知道如何继续代码。我想知道这是否是一个很好的方法,以及继续代码的更好方法。
答案 0 :(得分:3)
我会分阶段开发解决方案,大致是这样的。我的解决方案坚持n
参数(我在代码中使用N
)是一个奇数。问题没有说明如果结果是偶数的话如何呈现结果。断言支持坚持。
#include <assert.h>
#include <stdio.h>
enum { FSLASH = '/', BSLASH = '\\' };
static inline void repeat_char(int num, char c) { for (int i = 0; i < num; i++) putchar(c); }
static void print_line(int l_blanks, char c1, int i_blanks, char c2, int nc, char c3)
{
assert(i_blanks % 2 == 0);
assert(nc % 2 == 1);
repeat_char(l_blanks, ' ');
putchar(c1);
repeat_char(i_blanks, ' ');
repeat_char(nc, c2);
repeat_char(i_blanks, ' ');
putchar(c3);
//repeat_char(l_blanks, ' ');
putchar('\n');
}
int main(void)
{
print_line(0, BSLASH, 4, '*', 1, FSLASH);
print_line(1, BSLASH, 2, '*', 3, FSLASH);
print_line(2, BSLASH, 0, '*', 5, FSLASH);
print_line(3, BSLASH, 0, '*', 3, FSLASH);
print_line(4, BSLASH, 0, '*', 1, FSLASH);
print_line(4, FSLASH, 0, '*', 1, BSLASH);
print_line(3, FSLASH, 0, '*', 3, BSLASH);
print_line(2, FSLASH, 0, '*', 5, BSLASH);
print_line(1, FSLASH, 2, '*', 3, BSLASH);
print_line(0, FSLASH, 4, '*', 1, BSLASH);
putchar('\n');
return 0;
}
repeat_char()
函数是一个非常简单的小循环,它以指定的次数打印指定的字符。通过使它成为static inline
,编译器很可能不会进行函数调用,而是将函数体放入调用代码中。
print_line()
函数将每一行描述为:
c1
nc
出现c2
(必须是奇数)c3
main()
中的代码调用该函数,并使用手动写出的适当参数。它生成输出:
\ * /
\ *** /
\*****/
\***/
\*/
/*\
/***\
/*****\
/ *** \
/ * \
这看起来像你在N = 5时所追求的。但是这个函数的参数列表对它们来说有很多规律性。必须有一种方法来生成调用,并将这些数字替换为表达式。这一观察结果导致第2阶段。
#include <assert.h>
#include <stdio.h>
enum { FSLASH = '/', BSLASH = '\\' };
static inline void repeat_char(int num, char c) { for (int i = 0; i < num; i++) putchar(c); }
static inline int max(int x, int y) { return (x > y) ? x : y; }
static inline int min(int x, int y) { return (x < y) ? x : y; }
static void print_line(int l_blanks, char c1, int i_blanks, char c2, int nc, char c3)
{
assert(i_blanks % 2 == 0);
assert(nc % 2 == 1);
repeat_char(l_blanks, ' ');
putchar(c1);
repeat_char(i_blanks, ' ');
repeat_char(nc, c2);
repeat_char(i_blanks, ' ');
putchar(c3);
//repeat_char(l_blanks, ' ');
putchar('\n');
}
static void driver_1(int N)
{
assert(N % 2 == 1 && N > 0);
for (int i = 0; i < N; i++)
{
int nb = max(0, (N-1-2*i)/2);
int db = min(2*i+1, 2*(N-i)-1);
print_line(i, BSLASH, 2*nb, '*', db, FSLASH);
}
for (int i = N-1; i >= 0; i--)
{
int nb = max(0, (N-1-2*i)/2);
int db = min(2*i+1, 2*(N-i)-1);
print_line(i, FSLASH, 2*nb, '*', db, BSLASH);
}
putchar('\n');
}
int main(void)
{
int N = 5;
assert(N % 2 == 1);
driver_1(N);
driver_1(N+2);
driver_1(N-2);
return 0;
}
repeat_char()
和print_line()
功能与以前相同。新函数driver_1()
包含两个循环,一个用于处理具有0,1,... N-1个前导空白的行,另一个用于处理具有N-1,N-2,... 0行的行空白。 min()
和max()
函数再次为static inline
,因此它们的使用不太可能导致函数调用开销。循环索引i
控制前导空格的数量。 nb
和db
的表达式计算输出的空白和星号数量。这两个循环中的表达式是相同的;差异在于计数(向上与向下)和斜线字符参数的顺序。
这会生成输出:
\ * /
\ *** /
\*****/
\***/
\*/
/*\
/***\
/*****\
/ *** \
/ * \
\ * /
\ *** /
\ ***** /
\*******/
\*****/
\***/
\*/
/*\
/***\
/*****\
/*******\
/ ***** \
/ *** \
/ * \
\ * /
\***/
\*/
/*\
/***\
/ * \
这表明这些函数适用于所请求的不同输出大小。
代码的最终版本使用driver_1()
中两个循环的对称性,并使用范围0
.. 2* N - 1
上的单个循环来生成对{{print_line()
的正确调用1}}。唯一的变化是在驱动程序函数中,重命名为driver_2()
(部分原因是它是在单个可执行文件中开发的,其中也包含driver_1()
)。同样,repeat_char()
和print_line()
函数不变;并且min()
和max()
也可以重复使用。
循环使用表达式确定i
中driver_1()
对应的值(严格来说,这是一个定义,而不是表达式,但它包含一个表达式)int i = min(j, 2*N-1-j);
。 j
一词有效; 2*N-1-j
一词倒计时;使用的值是这两者中较小的一个。 j == i
的测试允许正确选择第一个和最后一个字符。
#include <assert.h>
#include <stdio.h>
enum { FSLASH = '/', BSLASH = '\\' };
static inline void repeat_char(int num, char c) { for (int i = 0; i < num; i++) putchar(c); }
static inline int max(int x, int y) { return (x > y) ? x : y; }
static inline int min(int x, int y) { return (x < y) ? x : y; }
static void print_line(int l_blanks, char c1, int i_blanks, char c2, int nc, char c3)
{
assert(i_blanks % 2 == 0);
assert(nc % 2 == 1);
repeat_char(l_blanks, ' ');
putchar(c1);
repeat_char(i_blanks, ' ');
repeat_char(nc, c2);
repeat_char(i_blanks, ' ');
putchar(c3);
//repeat_char(l_blanks, ' ');
putchar('\n');
}
static void driver_2(int N)
{
assert(N % 2 == 1 && N > 0);
for (int j = 0; j < 2*N; j++)
{
int i = min(j, 2*N-1-j);
int nb = max(0, (N-1-2*i)/2);
int db = min(2*i+1, 2*(N-i)-1);
char c1 = (j == i) ? BSLASH : FSLASH;
char c3 = (j == i) ? FSLASH : BSLASH;
print_line(i, c1, 2*nb, '*', db, c3);
}
putchar('\n');
}
int main(void)
{
int N = 5;
assert(N % 2 == 1);
driver_2(N);
driver_2(N+2);
driver_2(N+4);
driver_2(N-2);
driver_2(N-4);
return 0;
}
这会产生输出(注意N = 1的几乎退化的情况):
\ * /
\ *** /
\*****/
\***/
\*/
/*\
/***\
/*****\
/ *** \
/ * \
\ * /
\ *** /
\ ***** /
\*******/
\*****/
\***/
\*/
/*\
/***\
/*****\
/*******\
/ ***** \
/ *** \
/ * \
\ * /
\ *** /
\ ***** /
\ ******* /
\*********/
\*******/
\*****/
\***/
\*/
/*\
/***\
/*****\
/*******\
/*********\
/ ******* \
/ ***** \
/ *** \
/ * \
\ * /
\***/
\*/
/*\
/***\
/ * \
\*/
/*\
所以,你有它。完整的开发周期分为3个阶段。得到一些有用的东西并证明它有效。然后使解决方案更加通用。
答案 1 :(得分:2)
有很多方法可以实现这一目标。 其中一个是以下
void print_pattern(int n) {
int padding=0;
int width=0;
char char_begin='\\', char_end='/';
assert(n>0);
for(int x=0; x<n*2; x++) {
if(padding==n) {
padding--;
char_begin='/';
char_end='\\';
}
width=(n*2)-padding;
for(int y=0;y<=width; y++) {
if(y==padding)
printf("%c",char_begin);
else
if (y==width)
printf("%c",char_end);
else
if (y>padding && y>=n-padding && y<=n+padding)
printf("*");
else
printf(" ");
}
printf("\n");
if(x<n)
padding++;
else
padding--;
}
}