C - print a specific template
The exercise asks me to create a program that takes an integer n
and prints the following pattern with height 2*n
.
\ * / \ *** / \*****/ \***/ \*/ /*\ /***\ /*****\ / *** \ / * \
What I have already done:
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");
}
}
This only prints backslashes on top and I have no idea how to continue the code. I would like to know if this is a good way to do this, and what is the best way to continue the code.
source to share
I would develop the solution in stages, something like this. My solution insists on the parameter n
(which I am using n
in the code) is an odd number. The question does not show how to present the result if it is even. Persistence is reinforced by affirmations.
Stage 1 - print line function
#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;
}
The function repeat_char()
is a very simple loop that prints the specified character a specified number of times. Having done it static inline
, there is a good chance that the compiler will not call the function, but will place the body of the function in the calling code.
The function print_line()
characterizes each line as follows:
- zero or more leading spaces.
- one occurrence
c1
- zero or more internal spaces (this must be an even number)
-
nc
occurrencesc2
(it must be an odd number) - zero or more internal spaces again
- one occurrence
c3
- in other cases, it may be helpful to add trailing spaces; who commented
- in these other cases the function will not print a newline
The code in c main()
calls this function with the appropriate hand-written arguments. It generates output:
\ * / \ *** / \*****/ \***/ \*/ /*\ /***\ /*****\ / *** \ / * \
Sounds like you are for N = 5. But these function argument lists have a lot of regularity for them. There must be a way to generate calls with numbers replaced by these expressions. This observation leads to stage 2.
Stage 2 - two loops
#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;
}
Functions repeat_char()
and have print_line()
not changed before. The new function driver_1()
contains two loops, one for processing lines with 0, 1, ... N-1 headings, and the other for processing lines with N-1, N-2, ... 0 leading spaces. Functions over min()
and max()
over static inline
, so using them is unlikely to cause overhead function calls. The cycle index,, i
controls the number of leading blanks. Expressions for nb
and db
calculate the number of spaces and asterisks to display. These expressions are the same in both loops; the differences are in the direction of counting (up and down) and the order of the forward slash character arguments.
This generates the output:
\ * / \ *** / \*****/ \***/ \*/ /*\ /***\ /*****\ / *** \ / * \ \ * / \ *** / \ ***** / \*******/ \*****/ \***/ \*/ /*\ /***\ /*****\ /*******\ / ***** \ / *** \ / * \ \ * / \***/ \*/ /*\ /***\ / * \
This demonstrates that the functions work with requested requests of different sizes.
Stage 3 - single cycle
The final version of the code uses the symmetries of the two loops in driver_1()
and uses one loop in the range 0
.. 2* N - 1
to generate the correct call print_line()
. The only changes to the driver functions were renamed to driver_2()
(in part because they were developed in a single executable that also had driver_1()
). Again, function repeat_char()
and print_line()
do not change; and min()
and max()
used again.
The loop determines the value matched i
in driver_1()
using an expression (strictly that a definition, not an expression, but contains an expression) int i = min(j, 2*N-1-j);
. The term is j
counted; term is 2*N-1-j
counted; the value used is the lesser of the two. The test for j == i
allows you to correctly select the first and last character.
#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;
}
This generates an output (note the almost degenerate case for N = 1):
\ * / \ *** / \*****/ \***/ \*/ /*\ /***\ /*****\ / *** \ / * \ \ * / \ *** / \ ***** / \*******/ \*****/ \***/ \*/ /*\ /***\ /*****\ /*******\ / ***** \ / *** \ / * \ \ * / \ *** / \ ***** / \ ******* / \*********/ \*******/ \*****/ \***/ \*/ /*\ /***\ /*****\ /*******\ /*********\ / ******* \ / ***** \ / *** \ / * \ \ * / \***/ \*/ /*\ /***\ / * \ \*/ /*\
So this is it. Full development cycle in 3 stages. Get something that works and demonstrate that it works. Then make the solution more general.
source to share
There are many ways to accomplish this. One of them is the following
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--;
}
}
source to share