How to print V in c programming in 10X10 row and column in a optimized way?

Viewed 105

I printed V using * in specific rows and columns. I had lots of if statements. I am sharing my code below.

Is there any optimised way to print the V pattern in 10X10 row column? (without many if conditions)?

#include <stdio.h>

int main() {
    int row, column;
    for (row = 1; row <= 10; row++) {
        for (column = 1; column <= 10; column++) {
            if (row == 1 && (column == 1 || column == 10)
             || row == 3 && (column == 2 || column == 9)
             || row == 5 && (column == 3 || column == 8)
             || row == 7 && (column == 4 || column == 7)
             || row == 10 && column == 5)
                printf("*");
            else
                printf(" ");
        }
        printf("\n");
    }
    return 0;
}
5 Answers

A reasonable option when you need to output arbitrary amounts of spaces is to use printf string width specifier to left-pad with spaces:

printf("%*s*", spaces, "");

The above will output the empty string, padded up to a width of the integer value spaces, and then output a *. Note that the format string %*s means that you specify both a width and then a string as extra arguments. The * in that part has nothing to do with an actual *. We add that onto the end of the format string.

So, for the V shape, each line has two * characters on it, except the last line (if the width is odd). One way to do this intuitively is to track the position of the left and the right part of the V for each line, and then do the math for determining how much padding to add.

Example:

void v(int width)
{
    int l = 0, r = width;
    for (; l < r; l++, r--)
    {
        printf("%*s*%*s\n", l, "", r-l, "*");
    }
    if (l == r)
        printf("%*s*\n", l, "");
}

If you really want more condensed code, you can elect to roll that last line into the loop. In this case, when l == r you want to only output a single asterisk. Otherwise you want two. So you could output the string &"*"[l==r] -- that will mean that when l==r is true, you'll skip over the asterisk and it will look like an empty string (because you land on the NUL terminator).

Note this is not great style. It sacrifices readability for compactness.

void v(int width)
{
    for (int l = 0, r = width; l <= r; l++, r--)
    {
        printf("%*s*%*s\n", l, "", r-l, &"*"[l==r]);
    }
}

So, this is "efficient" in terms of compact code and not many function calls. If you instead are concerned about the format parsing of printf then you can avoid it entirely. Below, we use the same left/right bounds and just walk through each row using loops. This essentially does what our printf is doing internally, except it's more obvious what's going on:

void v(int width)
{
    int l = 0, r = width-1;
    for (; l <= r; l++, r--)
    {
        int x = 0;
        for (; x < l; x++) putchar(' ');
        putchar('*');
        if (x < r)
        {
            for (x++; x < r; x++) putchar(' ');
            putchar('*');
        }
        putchar('\n');
    }
}

Now for some fun...

As an exercise, here is the printf approach but with no loops (using recursion):

void vv(int width, int row) {
    if(width >= 0) {
        printf("%*s*%*s\n", row, "", width, &"*"[width==0]);
        vv(width-2, row+1);
    }
}

void v(int width) {
    vv(width, 0);
}

And here is that idea turned into an intentionally horrendous mess that looks cool. ;)

#include <stdio.h>
#define VV int
#define vV "*\0%*s%*s\n"

VV Vv( VV     v ,VV
 vv){if(v    -->0){
  printf     (vV+2,
   vv++     ,vV,v
   ,vV+     !v);
    Vv(--  v,vv
     );}} VV V
      (VV v){
       Vv(v,
        1);
         }

int main() {
    for (int v = 1; v < 12; v++) {
        printf("size %d\n", v);
        V(v);
    }
}

I don't think this is optimized but will be simpler and scalable with SIZE.

#include <stdio.h>
#define SIZE 10
#define MID ((SIZE-1)/2)                // midst position of SIZE
#define ABS(x) ((x)<0?-(x):(x))         // absolute value of x

int main()
{
    int i, j;
    for (i = 0; i < SIZE; i++) {
        for (j = 0; j < SIZE; j++) {
            if (i % 2 == 0 && ABS(j - MID) == MID - i / 2) putchar('*');
            else putchar(' ');
        }
        putchar('\n');
    }
    return 0;
}

[Explanation]
Assuming SIZE equals to 10, the value MID is calculated to be 4. Then the v shaped asterisks will be placed symmetrically wrt the 4th column.
Let's put numbers in columns (j) and rows (i) as follows:

012345678
*       * 0   ABS(0 - 4) == 4 - 0, ABS(8 - 4) == 4 - 0
          1   skipped as i & 2 != 0
 *     *  2   ABS(1 - 4) == 4 - 1, ABS(7 - 4) == 4 - 1
          3   skipped
  *   *   4   ABS(2 - 4) == 4 - 2, ABS(6 - 4) == 4 - 2
          5   skipped
   * *    6   ABS(3 - 4) == 4 - 3, ABS(5 - 4) == 4 - 3
          7   skipped
    *     8   ABS(4 - 4) == 4 - 4

The equations above are the conditions to put the asterisks. For instance, in the 0th row, we want to put it on 0th column and 8th. The condition j - 4 == +/- 4 or ABS(j - 4) == 4 will represent the conditions due to the symmetricity. If we generarize the condition across rows, we can describe it as i % 2 == 0 && ABS(j - MID) == MID - i / 2.

This code considers the relation between the row and the position of the *, if you are in the first row, then we want the column 0 and colum 9 to print *, then second row, we want column 1 and column 8 and so on. Thus, I used an iterator for the rows and iterator for columns to know in a concrete row which column I'm printing.

  #include <stdio.h>

int main()
{
    int matrix_size = 10; //Assuming is squared matrix 10x10
    int counter = 0;
    int i,j;
    for(i=0;i<(int)(matrix_size/2);i++) {
        for(j=0;j<matrix_size;j++) {
            if(j==i || j==(matrix_size-1-i)) {
                printf("*");
            }else{
                printf(" ");
            }
        }
        printf("\n");
    }
    
    return 0;
}

EDIT: compared to tshiono solution, I write the V in just 5 rows and he prints it in 10 rows but assuming an space line between each line. Boths solutions are ok depending on what u want.

For the V shape to be symmetric, the number of rows and columns should be odd. Here is a simpler method:

#include <stdio.h>
#include <stdlib.h>

int main() {
    for (int n = 11, row = 0; row < n; row++) {
        for (int column = 0; column < n; column++)
            putchar(" *"[2 * abs(column - n / 2) == n - 1 - row]);
        printf("\n");
    }
    return 0;
}

Output:

*         *

 *       *

  *     *

   *   *

    * *

     *

For a thicker V shape:

#include <stdio.h>
#include <stdlib.h>

int main() {
    for (int n = 11, row = 0; row < n; row++) {
        for (int column = 0; column < n; column++)
            putchar(" *"[abs(2 * abs(column - n / 2) - (n - 1 - row)) <= 1]);
        printf("\n");
    }
    return 0;
}

Output:

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

Other answers take into account the specific shape of V and optimize around that.

I suggest an optimized solution for any shape.

This involves a lookup table containing all the locations of * characters composing the shape.

struct { int row,col; } shape[] = {
   {1,1}, {1,10}, {3,2}, {3,9}, {5,3}, {5,8}, {7,4}, {7,7}, {10,5},
   {-1,-1}
};

The last location ({-1,-1}) has the same purpose as terminating '\0' for strings.

Related