14

I want to write a C function that will print 1 to N one per each line on the stdout where N is a int parameter to the function. The function should not use while, for, do-while loops, goto statement, recursion, and switch statement. Is it possible?

13
  • 13
    If it's a challenge question and we give you an answer, the challenge will be spoiled. Commented Oct 14, 2009 at 8:23
  • 27
    printf("1 to N"); Commented Oct 14, 2009 at 8:30
  • 1
    Maybe it's possible with macros? Commented Oct 14, 2009 at 8:38
  • 6
    Does system(("MyExe %d",N-1)) count as recursion ? :P Commented Oct 14, 2009 at 8:55
  • 5
    Use inline assembly, and you're done. Commented Oct 14, 2009 at 9:22

16 Answers 16

17
#include <stdlib.h>

int callback(const void *a, const void *b) {
    static int n = 1;

    if (n <= N)
        printf("%d\n", n++);

    return 0;
}

int main(int argc, char *argv) {
    char *buf;
    /* get N value here */

    buf = malloc(N);  // could be less than N, but N is definitely sufficient
    qsort(buf, N, 1, callback);
}

I think it doesn't count as recursion.

Sign up to request clarification or add additional context in comments.

3 Comments

qsort use "for" or "while" internally, so your idea breaks the rule.
@Effo, by your reasoning, any solution that uses printf() is also invalid since it undoubtedly used a loop of some sort to process the format string. That's going to make printing the line out pretty hard.
pretty hard? come on, what is a challenge?
15

With blocking read, signals and alarm. I thought I'd have to use sigaction and SA_RESTART, but it seemed to work well enough without.

Note that setitimer/alarm probably are unix/-like specific.

#include <signal.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

volatile sig_atomic_t counter;
volatile sig_atomic_t stop;

void alarm_handler(int signal)
{
  printf("%d\n", counter++);
  if ( counter > stop )
  {
    exit(0);
  }
}

int main(int argc, char **argv)
{
  struct itimerval v;
  v.it_value.tv_sec = 0;
  v.it_value.tv_usec = 5000;
  v.it_interval.tv_sec = 0;
  v.it_interval.tv_usec = 5000;
  int pipefds[2];
  char b;

  stop = 10;
  counter = 1;

  pipe(pipefds);

  signal(SIGALRM, alarm_handler);

  setitimer(ITIMER_REAL, &v, NULL);

  read(pipefds[0], &b, 1);
}

2 Comments

Not standard C but I won't vote you down since anyone bizarre enough to come up with this solution, is probably psychotic enough to track me down and cause serious harm :-)
@paxdiablo: yes, fear my nerd physique! Also, adding insult to injury, C99 states that calling i.e. printf within a signal-handler might not be entirely defined. :)
15

N is not fixed, so you can't unrole the loop. And C has no iterators as far as I know.

You should find something that mimics the loop.

Or thinking outside the box:

(for example N is limited to 1000, but it is easy to adapt)

int f(int N) {
    if (N >= 900) f100(100);
    if (N >= 800) f100(100);
    if (N >= 700) f100(100);
    ...

    f100(n % 100);
}

int f100(int N) {
    if (N >= 90) f10(10);
    if (N >= 80) f10(10);
    if (N >= 70) f10(10);
    ...

    f(n % 10);
}

int f10(int N) {
    if (N >= 9) func();
    if (N >= 8) func();
    if (N >= 7) func();
    ...
}

3 Comments

Yhis seems the best solution to date, each new level of function gives you a tenfold space increase. This should get you to 2^63-1 pretty quickly.
It's possible to wrap it in macros
+1. All the other solutions use something in the standard libraries that is in some way goto-like or loop-like (longjmp, the signal queue, the atexit stack, the loop in qsort). This doesn't even make it to the libraries (except for the actual I/O code which needs to be added to complete the code), so as a solution it's robust to simple requirements changes.
13

I'd go for using longjmp()

#include <stdio.h>
#include <setjmp.h>

void do_loop(int n) {
  int val;
  jmp_buf env;

  val = 0;

  setjmp(env);

  printf("%d\n", ++val);

  if (val != n)
    longjmp(env, 0);  
}

int main() {
  do_loop(7);
  return 0;
}

2 Comments

Nice one, emulating a goto with setjmp/longjmp. Most whippersnappers don't even know those functions exist :-) +1.
This blew me off my feet. Awesome.
11

You can do this by nesting macros.

int i = 1;

#define PRINT_1(N) if( i < N ) printf("%d\n", i++ );
#define PRINT_2(N) PRINT_1(N) PRINT_1(N)
#define PRINT_3(N) PRINT_2(N) PRINT_2(N)
#define PRINT_4(N) PRINT_3(N) PRINT_3(N)
:
:
#define PRINT_32(N) PRINT_31(N) PRINT_31(N)

There will be 32 macros in total. Assuming size of int as 4 bytes. Now call PRINT_32(N) from any function.

Edit: Adding example for clarity.

void Foo( int n )
{
    i = 1;

    PRINT_32( n );
}


void main()
{
    Foo( 5 );
    Foo( 55 );
    Foo( 555 );
    Foo( 5555 );
}

3 Comments

Just remove N from the macro parameters and you're good to go. I'm pretty sure that the resulting 4GB source file will kill the compiler, but theoretically it should work.
It'll be larger than 4GB, no? 2^32 * (28 bytes) = 120GB.
Thanks all; I know this idea is not practical, but it is logical... I don't think there is a compiler that is having enough heap to compile this code. This might be a code supposed to be done by 2050 -:)
7

You can use setjmp and logjmp functions to do this as shown in this C FAQ

For those who are curious to why someone have a question like this, this is one of the frequently asked questions in India for recruiting fresh grads.

11 Comments

So a standard recruiting question is "how do you do something mundane without using any methods that you should use, and instead doing it in an unnecessarily byzantine and complex way, for no reason at all?" Gee, how applicable.
Yes, that is kind of a 'standard' recruiting question here. But most of the companies who ask such questions are not even actually recruiting them for a C programmer job, and in most cases, the person who is asking such a question has no real programming experience.
mrduclaw: the term "syntactic sugar" implies that you could implement setjmp/longjmp using goto. You can't. setjmp/longjmp allow non-local jumps.
Allowing setjmp/longjmp makes everything way too easy. Actually, I would forbid using any keyword or any ASCII character altogether.
This explains how outsourcing to certain countries has gained such a poor reputation; because the code produced is rubbish.
|
5

write all possible output to a string first, and null terminate it where the output should stop.
this is a rather dirty solution, but given the limitations, all I can think of,
except for using assembler, off course.

char a[]="1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n"/*...*/;
main(n,v)char**v;{n=atoi(v[1]);
#define c(x)(n>x?n-x:0)
a[n+c(1)+c(9)+c(99)+c(999)+c(9999)+c(99999)+c(999999)+c(9999999)/*+...*/]=0;
puts(a);}

Given that MAX_INT==2147483647 on popular architectures, we only need to go up to +c(999999999). Typing out that initial string might take a while, though...

Comments

4

You did not forbid fork().

1 Comment

But that would almost certainly be considered recursion.
4

If you know the upper limit of N you can try something like this ;)

void func(int N)
{
    char *data = " 1\n 2\n 3\n 4\n 5\n 6\n 7\n 8\n 9\n10\n11\n12\n";
    if (N > 0 && N < 12)
        printf("%.*s", N*3, data);
    else
        printf("Not enough data. Need to reticulate some more splines\n");
}

Joke aside, I don't really see how you can do it without recursion or all the instructions you mentioned there. Which makes me more curious about the solution.

Edit: Just noticed I proposed the same solution as grombeestje :)

Comments

4

This does it:

int main ()
{
printf ("1 to N one per each line\n");
return 0;
}

Here is another one:

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

int main (int c, char ** v) {
    char b[100];
    sprintf (b, "perl -e 'map {print \"$_\\n\"} (1..%s)'", v[1]);
    system (b);
    return 0;
}

3 Comments

I have already posted this as a comment before you. Cheers.. -:)
Oh, I'm sorry but I didn't notice it.
I detect a buffer overflow "feature".
2

Another thingy (on linux) would be to do as below where 7 is N

int main() {
    return system("seq 7");
}

Comments

1

This takes the integer N from the command line and prints out from 1 to N

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

int total;
int N;

int print16(int n)
{
    printf("%d\n",n+0x01); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x02); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x03); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x04); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x05); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x06); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x07); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x08); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x09); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x0A); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x0B); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x0C); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x0D); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x0E); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x0F); total++; if (total >= N) exit(0);
    printf("%d\n",n+0x10); total++; if (total >= N) exit(0);
}

int print256(int n)
{
    print16(n);
    print16(n+0x10);
    print16(n+0x20);
    print16(n+0x30);
    print16(n+0x40);
    print16(n+0x50);
    print16(n+0x60);
    print16(n+0x70);
    print16(n+0x80);
    print16(n+0x90);
    print16(n+0xA0);
    print16(n+0xB0);
    print16(n+0xC0);
    print16(n+0xD0);
    print16(n+0xE0);
    print16(n+0xF0);
}

int print4096(int n)
{
    print256(n);
    print256(n+0x100);
    print256(n+0x200);
    print256(n+0x300);
    print256(n+0x400);
    print256(n+0x500);
    print256(n+0x600);
    print256(n+0x700);
    print256(n+0x800);
    print256(n+0x900);
    print256(n+0xA00);
    print256(n+0xB00);
    print256(n+0xC00);
    print256(n+0xD00);
    print256(n+0xE00);
    print256(n+0xF00);
}

int print65536(int n)
{
    print4096(n);
    print4096(n+0x1000);
    print4096(n+0x2000);
    print4096(n+0x3000);
    print4096(n+0x4000);
    print4096(n+0x5000);
    print4096(n+0x6000);
    print4096(n+0x7000);
    print4096(n+0x8000);
    print4096(n+0x9000);
    print4096(n+0xA000);
    print4096(n+0xB000);
    print4096(n+0xC000);
    print4096(n+0xD000);
    print4096(n+0xE000);
    print4096(n+0xF000);
}

int print1048576(int n)
{
    print65536(n);
    print65536(n+0x10000);
    print65536(n+0x20000);
    print65536(n+0x30000);
    print65536(n+0x40000);
    print65536(n+0x50000);
    print65536(n+0x60000);
    print65536(n+0x70000);
    print65536(n+0x80000);
    print65536(n+0x90000);
    print65536(n+0xA0000);
    print65536(n+0xB0000);
    print65536(n+0xC0000);
    print65536(n+0xD0000);
    print65536(n+0xE0000);
    print65536(n+0xF0000);
}

int print16777216(int n)
{
    print1048576(n);
    print1048576(n+0x100000);
    print1048576(n+0x200000);
    print1048576(n+0x300000);
    print1048576(n+0x400000);
    print1048576(n+0x500000);
    print1048576(n+0x600000);
    print1048576(n+0x700000);
    print1048576(n+0x800000);
    print1048576(n+0x900000);
    print1048576(n+0xA00000);
    print1048576(n+0xB00000);
    print1048576(n+0xC00000);
    print1048576(n+0xD00000);
    print1048576(n+0xE00000);
    print1048576(n+0xF00000);
}

int print268435456(int n)
{
    print16777216(n);
    print16777216(n+0x1000000);
    print16777216(n+0x2000000);
    print16777216(n+0x3000000);
    print16777216(n+0x4000000);
    print16777216(n+0x5000000);
    print16777216(n+0x6000000);
    print16777216(n+0x7000000);
    print16777216(n+0x8000000);
    print16777216(n+0x9000000);
    print16777216(n+0xA000000);
    print16777216(n+0xB000000);
    print16777216(n+0xC000000);
    print16777216(n+0xD000000);
    print16777216(n+0xE000000);
    print16777216(n+0xF000000);
}

int print2147483648(int n)
{
   /*
    * Only goes up to n+0x70000000 since we
    * deal only with postive 32 bit integers
    */
   print268435456(n);
   print268435456(n+0x10000000);
   print268435456(n+0x20000000);
   print268435456(n+0x30000000);
   print268435456(n+0x40000000);
   print268435456(n+0x50000000);
   print268435456(n+0x60000000);
   print268435456(n+0x70000000);
}


int main(int argc, char *argv[])
{
   int i;

   if (argc > 1) {
      N = strtol(argv[1], NULL, 0);
   }

   if (N >=1) {
      printf("listing 1 to %d\n",N);
      print2147483648(0);
   }
   else {
      printf("Must enter a postive integer N\n");
   }
}

Comments

1
int x=1;

void PRINT_2(int);

void PRINT_1(int n)
{ if(x>n)
    return;
  printf("%d\n",x++);
  PRINT_2(n);  
}

void PRINT_2(int n)
{ if(x>n)
    return;
  printf("%d\n",x++);
  PRINT_1(n);  
}

int main() 
{   int n;
    scanf("%d",&n);
    if(n>0)
      PRINT_1(n);
    system("pause");
}

Comments

1
 #include "stdio.h"

 #include "stdlib.h"

 #include "signal.h"

 int g_num;

 int iterator;

 void signal_print()

 {

        if(iterator>g_num-1)

                exit(0);

        printf("%d\n",++iterator);

 }

 void myprintf(int n)

 {

     g_num=n;

        int *p=NULL;

     int x= *(p); // the instruction is reexecuted after handling the signal

 }

 int main()

 {

        signal(SIGSEGV,signal_print);

        int n;

        scanf("%d",&n);

        myprintf(n);

        return 0;

 }

Comments

0

I'm very disappointed that this doesn't work. To me, the phrase "a function is called after any previously registered functions that had already been called at the time it was registered" suggests that it is possible to register atexit handlers after they have started to be called. That is, a handler can register another handler. Otherwise, how is it even possible for there to exist a function which has been called at the time another function is registered? But for me the call to atexit is returning 0 success, but not actually resulting in another call. Anyone know why, have I made some silly error?

#include "stdio.h"
#include "stdlib.h"

int count = 0;
int limit = 10;

void handler() {
    printf("%d of %d\n", ++count, limit);
    if (count < limit) atexit(handler);
}

int main(int argc, char **argv) {
    if (argc > 1) limit = atoi(argv[1]);
    atexit(handler);
}

By the way, not recursion because atexit doesn't call its parameter, it queues it to be called later. Obviously the C runtime contains a loop to call atexit handlers, but that loop exists whether you actually register any atexit handlers or not. So if this program contains a loop, so does every C program ;-)

3 Comments

see "Modern C++ Design: Generic Programming and Design Patterns Applied" section 6.6.1 Problems with atexit.
Thanks for that. Summary: the standard was inadequate, and didn't specify what should happen. The standard has been corrected. My compiler does not incorporate the correction, but if it did then this code would work.
Maybe your code was voted down because it doesn't compile, rather than because it uses atexit.
-1
    /// <summary>
    /// Print one to Hundred without using any loop/condition.
    /// </summary>
    int count = 100;
    public void PrintOneToHundred()
    {
        try
        {
            int[] hey = new int[count];
            Console.WriteLine(hey.Length);
            count--;
            PrintOneToHundred();
        }
        catch
        {
            Console.WriteLine("Done Printing");
        }
    }

2 Comments

He's also not allowed to use recursion
Also, why create a new array[count] and print the length, why not just print count and skip the array altogether?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.