user2220832
user2220832

Reputation: 13

Any ways to make this shorter?

The output is supposed to be in this fashion

I
IN
IND
INDI
INDIA
INDIA
INDI
IND
IN
I

I was wondering if there is anyway to make my program shorter.

Maybe use 2 while loops or 2 for loops instead of 4.

#include<iostream>
#include<conio.h>
using namespace std;
void main()
{
    char a[]={'I','N','D','I','A'};
    int r,c;
    for(r=1;r<=5;r++)
    {
        for(c=0;c<r;c++)
            cout<<a[c]<<" ";
        cout<<endl;
    }

    for(r=5;r>=0;r--)
    {
        for(c=0;c<r;c++)
            cout<<a[c]<<" ";
        cout<<endl;
    }
    _getch();
}

Upvotes: 0

Views: 431

Answers (8)

Cassio Neri
Cassio Neri

Reputation: 20523

The "cheating" ;-) but very short solution is

#include <cstdio>
int main() {
    puts("I\nIN\nIND\nINDI\nINDIA\nINDIA\nINDI\nIND\nIN\nI\n");
}

Yet another solution based on TonyK's beautiful idea (works in C and C++):

#include <stdio.h>
int main() {
    for (int i = 1; i < 11; ++i)
        printf("%.*s\n", i < 6 ? i : 11 - i, "INDIA") ;
}

Update: (After TonyK's comment):

If you want spaces, then replace the printf above with this

printf("%.*s\n", 2*(i < 6 ? i : 11 - i), "I N D I A ");

Update: A solution with no loop:

#include <stdio.h>
int main(int i, char**) {
    return printf("%.*s\n", i < 6 ? i : 11 - i, "INDIA") - 1 && main(i + 1, 0);
}

Detailed explanations for the benefit of beginners follow.

The most important point is that this is an "academic" exercise. The code is obscure and one should refrain from writing serious code like this.

The standard doesn't fix a particular signature for the function main. It only says that it must return an int and the compiler must accept two particular forms:

  1. int main();
  2. int main(int argc, char** argv);

I'm using the second one. The more popular form int main(int argc, char* argv[]) is equivalent to (2). Indeed, in general, an array of T used as a function argument is implicitly converted to pointer to T. In this example, char* argv[] is an array of pointer to char which becomes a pointer to pointer to char. The above program is not using the second parameter though (it's either ignored or given a NULL, i.e. 0 value).

Instead of doing a loop, the program calls main recursivelly. Actually, this is illegal but the major compilers turn a blind eye to it (at most GCC gives a warning if you ask it to be pedantic with option -Wpedantic). When the program is called from the command line with no arguments the operating system calls main passing 1 (which is 1 + the number of arguments) and a pointer to pointer to char which, as said, is ignored by this program. Hence, i = 1 at the first call.

Subsequently, main potentially calls itself incrementing i each time. In summary, main is sequentially called with i being 1, 2, 3, 4, ...

It's easy to see that for this sequence of values for i, the expression i < 6 ? i : 11 - i evaluates to 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 0, ... (This can also be expressed by 5.5 - abs(5.5 - i) as per Drew Dorman's solution but using the ternary operator avoids the need to #include <cmath> which saves a line ;-) These numbers are the quantity of characters of "INDIA" that should be displayed at each time.

The call printf("%.s\n", j, "INDIA"), where j = i < 6 ? i : 11 - i, displays the first j characters of "INDIA" followed by a new line and returns the number of characters effectivelly printed (including the new line), i.e. j + 1. Taking away 1 yields j.

We recall now an important point of the semantics of a && b, for integers a and b. If a == 0, then b is not evaluated. Otherwise, b is evaluated. For us, a = printf("%.*s\n", j, "INDIA") - 1 (i.e. a = j) and b = main(i + 1, 0).

Now, let's put these pieces together.

1. Initially, i = 1 and j = 1. The call to printf outputs "I\n" and returns 2. Taking away 1, gives a = 1 != 0. Therefore, b = main(2, 0) is evaluated (that is, main(2, 0) is called).

2. Well, for this second call to main, we have i = 2, j = 2, printf displays "IN\n", a = 2 != 0 and b = main(3, 0) is evaluated.

Repeating this argument, at each call to main we have:

3. i = 3, j = 3, "IND\n" is printed, a = 3 != 0 and main(4, 0) is called.

4. i = 4, j = 4, "INDI\n" is printed, a = 4 != 0 and main(5, 0) is called.

5. i = 5, j = 5, "INDIA\n" is printed, a = 5 != 0 and main(6, 0) is called.

6. i = 6, j = 5, "INDIA\n" is printed, a = 5 != 0 and main(7, 0) is called.

7. i = 7, j = 4, "INDI\n" is printed, a = 4 != 0 and main(8, 0) is called.

...

10. i = 10, j = 1, "I\n" is printed, a = 1 != 0 and main(11, 0) is called.

11. i = 11, j = 0, "\n" is printed, a = 0. Now main(12, 0) is not exectued and the main returns

Notice that main in step 1 calls main in step 2, which calls main in step 3, ... which calls main in step 11. Therefore, main in step 11 returns to main in step 10, which returns to main in step 9, ..., which returns to main in step 1. Finally, main in step 1 returns to the operating system.

If you are interested in even more obfuscated code, see present and past winners of the IOCCC. Enjoy!

Upvotes: 2

A.Danesh
A.Danesh

Reputation: 854

Another solution based on TonyK's answer. You can enter your desired string.

#include <stdio.h>
#include <string.h>
int main() {
    char s[100];
    gets(s);
    for (int i = 0; i < strlen(s) * 2; i++)
        printf ("%.*s\n", i < strlen(s) ? i + 1: 2 * strlen(s) - i, s);
}

http://ideone.com/Zsg5Lu

Upvotes: 0

Grijesh Chauhan
Grijesh Chauhan

Reputation: 58271

You can do like this:

void main()
{
  char a[]={'I','N','D','I','A'};
  int r,c;

  int x = 0;  // initially x is 0 
  int l = 5;
  for(r=1;r<= 11 ;r++)  //loop runs for 5*2 + 1 times
  {
     if(r>=6){
       x = l - r % 6;  //set x to remaining length 
       l--;
     }
     for(c=0;c< (r % 6) + x; c++)  // add x 
         cout<<a[c]<<" ";
     cout<<endl;
  }
}

and you can find it working here.

Upvotes: 0

Johnny Mnemonic
Johnny Mnemonic

Reputation: 3912

Here is an example using two loops:

#include<iostream>

using namespace std;
int main()
{
  char a[]={'I','N','D','I','A'};
  int arr_length=5;
  bool two_times=false;//if you want to output INDIA twice
  for(int i=2*arr_length-1; i>=1; i--)
  {
      for(int j=0; j<arr_length-abs(arr_length-i); j++)
      {
            cout << a[j];
      }
      if(i==arr_length && !two_times){ two_times=true; i++;}//if you want to output INDIA twice
      cout << endl;
  }
  return 0;
}

Output:

I
IN
IND
INDI
INDIA
INDIA
INDI
IND
IN
I

Upvotes: 0

Drew Dormann
Drew Dormann

Reputation: 63775

Shorter.

#include <iostream>
#include <cmath>

int main()
{
    char a[]={'I','N','D','I','A'};
    for(int r=1;r<=10;r++)
    {
        int c = 5.5 - std::abs(5.5 - r);
        std::cout << std::string(a, 0, c) << std::endl;
    }
}

Upvotes: 1

TonyK
TonyK

Reputation: 17114

This is nice and short, if you have C++11:

#include <stdio.h>
#include <initializer_list>
int main() {
    for (int i : {1,3,5,7,9,9,7,5,3,1})
        printf ("%.*s\n", i, "I N D I A") ;
}

I put it on ideone at this link.

Upvotes: 10

Anton Kizema
Anton Kizema

Reputation: 1092

smth like this: Anyway, 2 loops is hard thing)

 int i=1;
bool ind=0;
     for(r=0;r<10;r++)
      {
if (ind == 0){
          for(c=0;c<i;c++)
              cout<<a[c]<<" ";
    i++; }


    if (ind == 1){
          for(c=0;c<i;c++) cout<<a[c]<<" ";
    i--;
        }
    if (i % 5 == 0) ind=1;
        cout<<endl;
      }

Upvotes: 0

Misch
Misch

Reputation: 10840

You could use substr.

Additionally, if you want to add spaces between the characters (as it's in your code right now) you could do that once for the whole word and then work on that modified string:

input = "INDIA";
modifiedInput = ...; // Figure out a way to get "I N D I A " here
for (int i = 1; ...)
    cout << substr(modifiedInput, 0, 2 * i) << endl;
...

Upvotes: 0

Related Questions