Home > Enterprise >  C program to print a specific star pattern
C program to print a specific star pattern

Time:01-06

*****
 ***
  *
 ***
*****

For odd no. of rows only. The no. of rows is variable. We have to print this star pattern in c using nested loops.

#include <iostream>
using namespace std;
int main()
{
    int trows, rowno = 1;
    cout << "Enter total no. of rows";
    cin >> trows;
    while (rowno <= (trows   1) / 2) {
        int space = 1;
        while (space <= (rowno - 1)) {
            cout << ' ';
            space = space   1;
        }
        int star = 1;
        while (star <= (2 * (trows - rowno) - (trows   1) / 2)) {
            cout << '*';
            star = star   1;
        }
        cout << endl;
        rowno = rowno   1;
    }
    rowno = ((trows 1)/2) 1;
    while (rowno <= trows) {
        int space = 1;
        while (space <= trows - rowno) {
            cout << ' ';
            space = space   1;
        }
        int star = 1;
        while (star <= 2 * rowno - trows) {
            cout << '*';
            star = star   1;
        }
        cout << endl;
        rowno = rowno   1;
    }
    return 0;
}

The program ran correctly for the total no. of rows 5 or 7. But it gives a distorted shape for total no. of rows greater than 7.

CodePudding user response:

Here's a simplified version that works for any odd sized number of rows:

void printstar(const int totalRows)
{
 for (int col = 0; col < totalRows;   col)
 {
    const int totalStarsThisRow = abs((totalRows / 2) - col)*2 1;
    
    // Write needed spaces
    for (int row = 0; row < (totalRows - totalStarsThisRow)/2;   row)
    {
        cout << ' ';
    }

    // Write Stars
    for (int row = 0; row < totalStarsThisRow;   row)
    {
        cout << '*';
    }
    cout << '\n';
  }
}

CodePudding user response:

Generally, your code is far more complicated than it needs to be, and you're making it even more complicated by ignoring how the language works. Just count from zero. This code also shows that you're attempting to brute force the solution. There are patterns to be taken advantage of that you don't. Sit and think about the problem before writing any code. The coding quickly becomes a technical detail and not the primary challenge.

Let's examine your shape. You state that input will always be an odd number, n. You need to print n rows. The first row contains n stars. You decrease the number of stars by 2, or drop down to the next odd number. The shape is symmetric.

Break the problem down. Can you print a square?

Here's the main() that we'll be using for testing purposes:

int main() {
  print_shape(5);
  std::cout << "\n\n";
  print_shape(7);
  std::cout << "\n\n";
  print_shape(21);
}

As we progress through this answer, all three shapes need to always be correct. Testing on just one case is asking for a bad time when you're expected to pass multiple cases.

And here's the function for printing the squares:

void print_shape(int rows) {
  for (int row = 0; row < rows;   row) {
    for (int column = 0; column < rows;   column) {
      std::cout << '*';
    }
    std::cout << '\n';
  }
}

Pretty straightforward so far. Now, can we modify print_shape() to print the correct number of stars per row?

Our inner for loop controls how many stars get printed, so that's where we should start. We need to consider a pattern between our row number and how many stars are required. We'll use the case where n = 5 as an example.

Row 0: 5
Row 1: 3
Row 2: 1
Row 3: 3
Row 4: 5

Well, for positive numbers, the expression 5 - 2*rowNumber works. But it falls apart when we get to the bottom half. However, note the symmetry of the number of stars. What if we number our rows symmetrically?

Row -2: 5
Row -1: 3
Row  0: 1
Row  1: 3
Row  2: 5

Now, a new pattern that holds for all rows should be sticking out. abs(rowNumber) * 2 1 is how many stars we need to print. The next question, how we do know where to start our row numbering? Integer division and symmetry come to our rescue again. With small changes to both loop conditions, we are now printing the correct number of stars on every row for every case.

void print_shape(int rows) {
  int startingNum = rows / 2;
  for (int row = -startingNum; row <= startingNum;   row) {
    for (int column = 0; column < std::abs(row) * 2   1;   column) {
      std::cout << '*';
    }
    std::cout << '\n';
  }
}

So now all that's left is the spaces. And again, we just need to think about it for a bit. First, what spaces do we actually need to print? Do we need to bother printing trailing spaces? (Hint: No)

Let's put a table together for the number of spaces that are required at the beginning each row.

Row -2: 0
Row -1: 1
Row  0: 2
Row  1: 1
Row  2: 0

A very similar pattern almost emerges. What if we make the table a bit fancier?

        Spaces Stars
Row -2:   0      5
Row -1:   1      3
Row  0:   2      1
Row  1:   1      3
Row  2:   0      5

It takes some thinking to see this one, and we have to remember that we have a total number of rows that we can consider as well. But putting all of our information together, (totalRows - numStars) / 2 is the pattern that we want.

And because we only need to print the spaces before the stars, we add a separate loop to our function. I'm also going to pull some calculations out and change some names becuase they no longer make sense.

void print_shape(int rows) {
  int startingNum = rows / 2;
  for (int row = -startingNum; row <= startingNum;   row) {
    int numStars = std::abs(row) * 2   1;
    int numSpaces = (rows - numStars) / 2;
    for (int spaces = 0; spaces < numSpaces;   spaces) {
        std::cout << ' ';
    }
    for (int star = 0; star < numStars;   star) {
      std::cout << '*';
    }
    std::cout << '\n';
  }
}

And that will print your shape, if and only if you pass an odd number. So we should guarantee that we do just that.

int main() {
  int input;
  bool oddNumberWasEntered = false;

  do {
    std::cout << "How many rows? ";
    std::cin >> input;

    if (is_odd(input)) {
      oddNumberWasEntered = true;
    } else {
      std::cerr << "Must enter an odd number!\n";
    }
  } while (!oddNumberWasEntered);
  print_shape(input);
}

is_odd() is a one-liner function I wrote.

An example:

❯ ./a.out 
How many rows? 4
Must enter an odd number!
How many rows? 20
Must enter an odd number!
How many rows? 21
*********************
 *******************
  *****************
   ***************
    *************
     ***********
      *********
       *******
        *****
         ***
          *
         ***
        *****
       *******
      *********
     ***********
    *************
   ***************
  *****************
 *******************
*********************

From the comments, I really like the idea of building correct sized strings and just printing those at each row. I consider it a more elegant solution as it shortens the code but doesn't lose any readability. I won't add that code to this answer, but I want to say that solution is only possible if you took the time to examine the problem, and find the same patterns.

There is also further input validation that I'm not bothering with, like ensuring the number is positive, or that a number was even entered. The goal of this homework was less about writing code, and more about sitting and thinking about a problem.

  • Related