1

A follow up question to: Print 1 to 1000 with out using loop A question that was asked today and is a duplicate of an older question showing a code snippet of a recursion of the main function :

This code means to count to 10 without using any loops, it does it by recursing on the main functions pointer and when it reaches the needed amount of prints it changes the pointer to the exit function.

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

void main(int j) {
  printf("%d\n", j);
  (&main + (&exit - &main)*(j/10))(j+1);
}

Note i changed the number of times the value will be printed, I do understand that the subtraction of function pointers is UB but still I compiles and ran this function with:

./mainexit 547

And for some reason the values that are beeing printed are from 2 to 10. when i start the program with ./mainexit 1 it will print until j reaches 10 and then the reference will be for exit but when I run the program with 547 from the beginning the first function in the recursion that is being called located at address 57*&exit so it should do really weird stuff but instead it prints normally. any ideas on how the function returns to the main?

Community
  • 1
  • 1
antonpuz
  • 3,256
  • 4
  • 25
  • 48

2 Answers2

4

You can do this nonsense like this:

/* Count from 1 to 10 using recursive main call */

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

int main(int argc, char *argv[])
{
  int r;
  if(argc>=11)
    return EXIT_SUCCESS;

  printf("argc=%d\n", argc);
  r = main(argc+1, NULL);
  return r;
}

And you can call

$./countmain

and get:

argc=1
argc=2
argc=3
argc=4
argc=5
argc=6
argc=7
argc=8
argc=9
argc=10

or call

$./countmain a b c d 4 4

and get:

argc=7
argc=8
argc=9
argc=10

But of course it would be much better if you just do something like:

/* Count from 1 to 10 using recursive function call */

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

void reccount(int to);

int main(int argc, char *argv[])
{
  int to;
  if(argc==2)
    to=atoi(argv[1]);
  else
    to=10;

  reccount(to);

  return EXIT_SUCCESS;
}

void reccount(int to)
{
  if(to==0)
    return;

  reccount(to-1);
  printf("to=%d\n", to);
  return;
}

Now you type:

$ ./reccount.x
to=1
to=2
to=3
to=4
to=5
to=6
to=7
to=8
to=9
to=10

Or you can set the limit as:

$ ./reccount.x 2
to=1
to=2

Now, back to your question:

warning: ‘main’ takes only zero or two arguments [-Wmain]
warning: return type of ‘main’ is not ‘int’ [-Wmain]

If exit had a prototype like main, i.e., int exit(int x, char **y) you could do the trick by adding a conditional like this in the begin of the code:

if(argc==2 && argv!=NULL)
  j=atoi(argv[1]);
else
  j=argc;

and then calling them as:

(&main + (&exit - &main)*(j/10))(j+1, NULL);

Example:

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

int myexit(int j, char **p)
{
  exit(j);
}

int main(int argc, char **argv)
{
  int j;
  if(argc==2 && argv!=NULL)
    j=atoi(argv[1]);
  else
    j=argc;
  printf("%d\n", j);
  (&main + (&myexit - &main)*(j/10))(j+1, NULL);
}

But as it stands, you just cant properly read argv from command line.

DrBeco
  • 11,237
  • 9
  • 59
  • 76
3

The parameter j is not used in the way you think.

When you launch the command, the first argument of main is the number of arg of the command line. So launching with ./mainexit 547 just pass 2 as the first value of the first call to main. And the loop is built so that it calls exit when j reaches 10.

So the value of your arg is not useful, try ./mainexit hello it will give you the same result!

Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69