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);
}
}