views:

1494

answers:

16

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? I want to find an answer to this as this a challenge question

+5  A: 

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...

andremo
Code or it didn't happen!
spoulson
There, I fixed it.
ephemient
+4  A: 

You did not forbid fork().

mouviciel
But that would almost certainly be considered recursion.
paxdiablo
+14  A: 

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();
    ...
}
Gamecat
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.
paxdiablo
It's possible to wrap it in macros
vava
+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.
Steve Jessop
+4  A: 

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 :)

rslite
+5  A: 

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;
}
Kinopiko
I have already posted this as a comment before you. Cheers.. -:)
Vadakkumpadath
Oh, I'm sorry but I didn't notice it.
Kinopiko
I detect a buffer overflow "feature".
spoulson
+5  A: 

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.

Technowise
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.
phoebus
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.
Technowise
Isn't setjmp/longjmp just syntactic sugar for goto? Seems as a recruiter, I'd forbid the use of that too.
mrduclaw
mrduclaw: the term "syntactic sugar" implies that you could implement setjmp/longjmp using goto. You can't. setjmp/longjmp allow non-local jumps.
Laurence Gonsalves
@Laurence Gonsalves, ah nice. I didn't realize goto had that restriction in C. It still seems that this is a circumvention of the rules, at least in the spirit of the challenge.
mrduclaw
Allowing setjmp/longjmp makes everything way too easy. Actually, I would forbid using any keyword or any ASCII character altogether.
Daniel Daranas
Well, phoebus, maybe your answer is the correct answer :). Q: How would you do this ? A: I wouldn't
Bahbar
Now, this is a real example of a question that should not be asked in an interview.
Aamir
I would consider asking you this question in an interview if you had claimed to be a "C guru who knows the standard library inside-out."
finnw
The question at the link (FAQ) doesn't explicitly prohibit 'goto'. That makes me assume that 'goto' is prohibited under the "any kind of loops" clause. But that would also outlaw 'longjmp'.
AndreyT
This explains how outsourcing to certain countries has gained such a poor reputation; because the code produced is rubbish.
Rob
+10  A: 

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 );
}
Vadakkumpadath
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.
itsadok
It'll be larger than 4GB, no? 2^32 * (28 bytes) = 120GB.
Matt B.
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 -:)
Vadakkumpadath
+12  A: 

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;
}
epatel
Nice one, emulating a goto with setjmp/longjmp. Most whippersnappers don't even know those functions exist :-) +1.
paxdiablo
+16  A: 
#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.

qrdl
wow. that blew my mind. sneaky: use somebody else's loop...
Daren Thomas
qsort use "for" or "while" internally, so your idea breaks the rule.
EffoStaff Effo
@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.
paxdiablo
pretty hard? come on, what is a challenge?
EffoStaff Effo
A: 

cant we user recursive functions?

xyz
+15  A: 

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);
}
Kjetil Jorgensen
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
@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. :)
Kjetil Jorgensen
A: 

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

Steve Jessop
see "Modern C++ Design: Generic Programming and Design Patterns Applied" section 6.6.1 Problems with atexit.
EffoStaff Effo
btw, my atexit proposal got vote -2, stop trying it
EffoStaff Effo
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.
Steve Jessop
Maybe your code was voted down because it doesn't compile, rather than because it uses atexit.
Steve Jessop
should i give the complete code? i'll just give ideas.
EffoStaff Effo
A: 

@Kjetil Jorgensen

I am searching for the answer why "read(pipefds[0], &b, 1);" is required?

Could you please explain or point me to some Doc ?

prasadr
Without the deadlock created by the call to read, the program will just exit without printing anything. The actual printing is based on a repeating timer which raises the signal SIGALRM on regular intervals. Each time the signal is raised, the program interrupts regular execution to run the signal-handler. So, in order for output to appear, we need the program to wait for a while. The call to read will not return until we write something to pipefds[1], so it's sort-of a way of doing while (1); without using while (and as a bonus the scheduler can put the task in IO wait instead of hogging cpu)
Kjetil Jorgensen
Thanks for the explanation.The intent of read(...) is now clear.So we are relying on the exit() to flush standard I/O buffers. Cool Idea :)
prasadr
+1  A: 

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");
   }
}
Bob
+1  A: 

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

int main() {
    return system("seq 7");
}
epatel
A: 
    /// <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");
        }
    }
Pritam Karmakar