tags:

views:

299

answers:

4

I'm trying to figure out a simple way to handle dynamic nested loops level. Consider the following function that takes in 2 parameters: #num of loops, and max value.

void PrintLoop(int maxloop, int maxvalue)

PrintLoop(1,2); 
// output
0
1

PrintLoop(2,2);
// output
0, 0
0, 1
1, 0
1, 1

PrintLoop(3,2);
// output
0, 0, 0
0, 0, 1
0, 1, 0
0, 1, 1
1, 0, 0
1, 0, 1
1, 1, 0
1, 1, 1

Etc...

Is there a way to write a function that can generate this "dynamic nested loops" behavior?

Thanks for any help

+6  A: 

Yes, it is possible, and to implement this a concept of "recursion" is often used:

void PrintLoop(int maxloop, int maxvalue)
{
   if (maxloop<=0) return ;
   // print something here...
   for (int i=0;i<maxmalue;i++){
      PrintLoop(maxloop-1, maxvalue);
   }
}
Pavel Shved
Well, recursion is a *means* to implement this, not the name of the concept.
Konrad Rudolph
Recursion is the way to go, yes. But I miss any print statements...
Stephan202
@Stephan202, of course, I *could* write the statements, but something tells me, that it's a homework, so I'd better stick to giving general advice...
Pavel Shved
A: 

In Ada you could do a DECLARE block after getting the user input; then set your loop to go from 1 .. Read_In_Loop_Control_Value and then a nested loop to print integers from 1 .. Read_In_Number_Per_Line value.

Tony
+5  A: 

Pavel's answer shows how to perform recursion. However, a function which takes only two arguments (number of loops and maximum value) does not have enough context to actually print the numbers as in your example. For that, you'll have to keep track of some extra information. One way to do this, is the following:

void _print_loop(int *values, int width, int cur_col, int max) {
  if (cur_col == width) {
    for (int i = 0; i < width; i++) {
      printf("%d%c", values[i], (i < width - 1) ? ' ' : '\n');
    }
  } else {
    for (int i = 0; i < max; i++) {
      values[cur_col] = i;
      _print_loop(values, width, cur_col + 1, max);
    }
  }
}

void print_loop(int width, int max) {
  int values[width];
  memset(values, 0, width * sizeof(int));
  _print_loop(values, width, 0, max);
}

Now print_loop(3, 2) behaves as expected.

Edit: actually, one can write a two-argument function to do this, through the use of static variables which are initialized upon receiving a positive width argument. After this initialisation stage the function then performs its recursion using negative values. Obviously, the resulting code is horrible, but I'll post it anyway, for the sake of completeness:

void print_loop(int width, int max) {
  static int max_width;
  static int *values;

  if (width > 0) {
    max_width = width;
    if ((values = calloc(width, sizeof(int))) == NULL) {
      perror("calloc");
      exit(EXIT_FAILURE);
    }   
    print_loop(-width, max);
    free(values);
  }
  else if (width == 0) {
    for (int i = 0; i < max_width; i++) {
      printf("%d%c", values[i], (i < max_width - 1) ? ' ' : '\n');
    }   
  }
  else {
    for (int i = 0; i < max; i++) {
      values[-width - 1] = i;
      print_loop(width + 1, max);
    }   
  }
}
Stephan202
Thanks for your detailed answer. I expected that this problem has to be solved using recursions.Although, I was hoping that there might be a mechanism to do it purely using iterations. The programming languages need some update :)
Vu Duy
There *is* a pretty straight forward way to do it without using recursion. See my comment to your original question.
Bart Kiers
A: 

You can use recursion or you can explicitly store each loop's state and manage the states in a single loop.

In this case it means storing an array of counters. Each execution of the main loop advances the innermost counter and all outer counters whose inner neighbours 'carry over'. The highest counter acts as a guard.

void printloop(int maxloop, int maxvalue) {
    unsigned int counters[maxloop+1];  // C99 for the win
    memset(counters, 0, sizeof(counters));

    while(!counters[maxloop]) {
        int i;
        char *sep="";
        for(i=maxloop; i-->0;) {
            printf("%s%d",sep,counters[i]);
            sep=",";
        };
        printf("\n");
        for(i=0; counters[i]==maxvalue; i++)  // inner loops that are at maxval restart at zero
            counters[i]=0;
        ++counters[i];  // the innermost loop that isn't yet at maxval, advances by 1
    }
}
Rafał Dowgird