Problem Statement:
The Christmas tree is comprised of the following Parts Stand Each Part is further comprised of Branches. Branches are comprised of Leaves.
How the tree appears as a function of days should be understood. Basis that print the tree as it appears on the given day. Below are the rules that govern how the tree appears on a given day. Write a program to generate such a Christmas tree whose input is number of days.
Rules
1.If tree is one day old you cannot grow. Print a message "You cannot generate christmas tree"
2.Tree will die after 20 days; it should give a message "Tree is no more"
3.Tree will have one part less than the number of days.
E.g.
On 2nd day tree will have 1 part and one stand.
On 3rd day tree will have 2 parts and one stand
On 4th day tree will have 3 parts and one stand and so on.
4.Top-most part will be the widest and bottom-most part will be the narrowest.
5.Difference in number of branches between top-most and second from top will be 2
6.Difference in number of branches between second from top and bottom-most part will be 1
Below is an illustration of how the tree looks like on 4th day
Input Format:
First line of input contains number of days denoted by N
Output Format:
Print Christmas Tree for given N
OR
Print "You cannot generate christmas tree" if N <= 1
OR
Print "Tree is no more" if N> 20
Constraints:
0<= N <=20
Sample Input and Output
Input: 2
Output:( below)
The code:
#include<stdio.h>
int main(){
int i,j,leaves=1,day,rest,branches,max_leaves;
scanf("%d",&day);
//Check for exceptions
if(day<=1){
printf("You cannot generate christmas tree");
return 0;
}
else if(day>20){
printf("Tree is no more");
return 0;
}
// printf("Heres Your Christmas Tree:\n\n");
// For first part
branches=day+1;
max_leaves = 1+(branches-1)*2; // Arithmetic Progression
for(i=1;i<=branches;i++){
for(j=i;j<=max_leaves/2;j++){
printf(" ");
}
for(j=1;j<=leaves;j++){
printf("*");
}
printf("\n");
leaves=leaves+2;
}
// For remaining parts
branches=branches-2;
for(rest=1;rest<=day-2;rest++){
leaves=3;
for(i=2;i<=branches+1;i++){
for(j=i;j<=max_leaves/2;j++){
printf(" ");
}
for(j=1;j<=leaves;j++){
printf("*");
}
printf("\n");
leaves=leaves+2;
}
branches--;
}
// For stand
for(i=1;i<=2;i++){
for(j=1;j<=max_leaves/2;j++){
printf(" ");
}
printf("*\n");
}
return 0;
}
The code is working fine as can be checked on IDEOne.
1 Answer 1
Keep the scope of variables to a minimum
Since C99 we are allowed to mix declaration and code. At the moment, you have i
, j
, rest
and so on in scope, even if day
is out of the specification. That can lead to hard to find errors, for example if we accidentally use i++
where i
isn't used.
Late declaration makes it easier to copy our code into other blocks also, but more on that later. So instead, let's push the declaration as late as possible and limit the scope:
#include<stdio.h>
int main(){
int day;
scanf("%d",&day);
//Check for exceptions
if(day<=1){
printf("You cannot generate christmas tree");
return 0;
}
else if(day>20){
printf("Tree is no more");
return 0;
}
// printf("Heres Your Christmas Tree:\n\n");
// For first part
int leaves=1;
int branches=day+1;
int max_leaves = 1+(branches-1)*2; // Arithmetic Progression
for(int i=1;i<=branches;i++){
for(int j=i;j<=max_leaves/2;j++){
printf(" ");
}
for(int j=1;j<=leaves;j++){
printf("*");
}
printf("\n");
leaves=leaves+2;
}
// For remaining parts
branches=branches-2;
for(int rest=1;rest<=day-2;rest++){
leaves=3;
for(int i=2;i<=branches+1;i++){
for(int j=i;j<=max_leaves/2;j++){
printf(" ");
}
for(int j=1;j<=leaves;j++){
printf("*");
}
printf("\n");
leaves=leaves+2;
}
branches--;
}
// For stand
for(int i=1;i<=2;i++){
for(int j=1;j<=max_leaves/2;j++){
printf(" ");
}
printf("*\n");
}
return 0;
}
Use whitespace to scan code quickly
Now that we've introduced late declarations, let us add some whitespace between operators. Gone are the days where bytes in source code where expensive. Unless you intend write-only code, make code easy to read. Debugging is much nicer in well-written and spaced code:
#include <stdio.h>
int main() {
int day;
scanf("%d", &day);
// Check for exceptions
if (day <= 1) {
printf("You cannot generate christmas tree");
return 0;
} else if (day > 20) {
printf("Tree is no more");
return 0;
}
// printf("Heres Your Christmas Tree:\n\n");
// For first part
int leaves = 1;
int branches = day + 1;
int max_leaves = 1 + (branches - 1) * 2; // Arithmetic Progression
for (int i = 1; i <= branches; i++) {
for (int j = i; j <= max_leaves / 2; j++) {
printf(" ");
}
for (int j = 1; j <= leaves; j++) {
printf("*");
}
printf("\n");
leaves = leaves + 2;
}
// For remaining parts
branches = branches - 2;
for (int rest = 1; rest <= day - 2; rest++) {
leaves = 3;
for (int i = 2; i <= branches + 1; i++) {
for (int j = i; j <= max_leaves / 2; j++) {
printf(" ");
}
for (int j = 1; j <= leaves; j++) {
printf("*");
}
printf("\n");
leaves = leaves + 2;
}
branches--;
}
// For stand
for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= max_leaves / 2; j++) {
printf(" ");
}
printf("*\n");
}
return 0;
}
By the way, your text editor should provide some automatic format feature. I formatted the code with clang-format -style="{BasedoNStyle: llvm, IndentWidth: 4}"
, since that's very similar to your variant.
Don't repeat yourself
Now that we have easy to read code, we can see that there are repeating patterns, namely
for(int k = init; k <= stop; k++) {
printf("some string");
}
We have at least five occurrences. So let's write a small function:
void repeat_string(int times, const char* str) {
for(int i = 0; i < times; ++i) {
printf("%s",str);
}
}
Let's replace all occurrences of your loop with the function:
#include <stdio.h>
void repeat_string(int times, const char* str) {
for(int i = 0; i < times; ++i) {
printf("%s",str);
}
}
int main() {
int day;
scanf("%d", &day);
// Check for exceptions
if (day <= 1) {
printf("You cannot generate christmas tree");
return 0;
} else if (day > 20) {
printf("Tree is no more");
return 0;
}
// printf("Heres Your Christmas Tree:\n\n");
// For first part
int leaves = 1;
int branches = day + 1;
int max_leaves = 1 + (branches - 1) * 2; // Arithmetic Progression
for (int i = 1; i <= branches; i++) {
repeat_string(max_leaves / 2 - i, " ");
repeat_string(leaves, "*");
printf("\n");
leaves = leaves + 2;
}
// For remaining parts
branches = branches - 2;
for (int rest = 1; rest <= day - 2; rest++) {
leaves = 3;
for (int i = 2; i <= branches + 1; i++) {
repeat_string(max_leaves / 2 - i, " ");
repeat_string(leaves, "*");
printf("\n");
leaves = leaves + 2;
}
branches--;
}
// For stand
for (int i = 1; i <= 2; i++) {
repeat_string(max_leaves / 2; " ");
printf("*\n");
}
return 0;
}
Again, it's easier too read. Also, any optimization we find for repeat_string
will now help at all five call sites. Great.
Exercises:
- Write
repeat_character(int n, char c)
, which prints a single characterc
a total ofn
times. If we look closely, we can see that the branches look very similar:
for (int i = 1; i <= branches; i++) { // <--- repeat_string(max_leaves / 2 - i, " "); // <--- repeat_string(leaves, "*"); // <--- printf("\n"); // <--- leaves = leaves + 2; // <--- } // For remaining parts branches = branches - 2; for (int rest = 1; rest <= day - 2; rest++) { leaves = 3; for (int i = 2; i <= branches + 1; i++) { // <--- repeat_string(max_leaves / 2 - i, " "); // <--- repeat_string(leaves, "*"); // <--- printf("\n"); // <--- leaves = leaves + 2; // <--- } branches--; }
Write a function that draws a single part, e.g. a trapezoid or pyramid width a given width, height, and so on.
Mark read-only values and locations with const
We denoted the str
as const char*
in order to make sure that we don't accidentally change string's contents. In the same spirit, we can add const
to max_leaves
:
...
const int max_leaves = 1 + (branches - 1) * 2; // Arithmetic Progression
...
Now typos like max_leaves /= 2
will get cought by the compiler.
Use 0...(n-1) as range, not 1...n
Your ranges use start = 1; i <= end; start++
. Since we often work with arrays in C++ and arrays start with 0
, it's more common to work with start = 0; start < end; start++
. Keep that in mind for future code.
Other remarks
You mix leaves
, branches
and max_leaves
, but their exact meanings are lost for the unprepared reader. Some additional comments can be helpful.
Other than that, the missing whitespace and therefore code structuring was my biggest criticism, but that's a minor point that can get fixed quickly.
Here's the complete code:
#include <stdio.h>
void repeat_string(int times, const char *str) {
for (int i = 0; i < times; i++) {
printf("%s", str);
}
}
void repeat_character(int times, char c) {
// Exercise 1
}
void draw_part(int height, int start_width, int max_width) {
// Exercise 2
}
int main() {
int day;
scanf("%d", &day);
// Check for exceptions
if (day <= 1) {
printf("You cannot generate christmas tree");
return 0;
} else if (day > 20) {
printf("Tree is no more");
return 0;
}
// printf("Heres Your Christmas Tree:\n\n");
// For first part
int branches = day + 1;
const int max_leaves = 1 + (branches - 1) * 2; // Arithmetic Progression
// For first part
draw_part(branches, 1, max_leaves);
// For remaining parts
branches -= 2;
for (int rest = 0; rest < day - 2; rest++) {
draw_part(branches, 3, max_width);
branches--;
}
// For stand
for (int i = 0; i < 2; i++) {
repeat_string(max_leaves / 2; " ");
printf("*\n");
}
return 0;
}
-
\$\begingroup\$ For an arbitrary string
printf(str);
is a problem should the string contain a%
. Suggestprintf("%s", str);
orfputs(str, stdout);
\$\endgroup\$chux– chux2018年07月30日 17:55:38 +00:00Commented Jul 30, 2018 at 17:55 -
\$\begingroup\$ The "Mark read-only variables with const" has merit, yet the discussion mixes up the
const
-ness of what a pointer references to and the object itself.const int max_leaves
is likechar* const str
, notconst char* str
. \$\endgroup\$chux– chux2018年07月30日 18:00:02 +00:00Commented Jul 30, 2018 at 18:00
Explore related questions
See similar questions with these tags.