在 C 中,如何编写 N 是可变的 N 维嵌套 for 循环

In C, how to write a N-dimensional nested for loop where N is variable

我需要写声明:

for ( int i1 = i1_min; i1 < width; ++i1 )
    for ( int i2 = i2_min; i2 < i2_max; ++i2 )
        for ( int i3 = i3_min; i3 < i3_max; ++i3 )
            ...
                for ( int iN = iN_min; iN < iN_max; ++iN )

怎么做?

你可以写一个递归函数loopn()来做到这一点:

void loopn_recurse (int *min, int *max, int *counters, size_t N, size_t n, void (*func)(int*, size_t)) {
  for (int i = min[n]; i < max[n]; ++i) {
    counters[n] = i;

    if (N - n > 1) {
      loopn_recurse(min, max, counters, N, n + 1, func);
    } else {
      // innermost algorithm
      func(counters, N);
    }
  }
}

void loopn (int *min, int *max, int *counters, size_t N, void (*func)(int*, size_t)) {
  assert(N > 0);
  loopn_recurse(min, max, counters, N, 0, func);
}

// example usage

void test (int *counters, size_t N) {
  for (size_t j = 0; j < N; ++j) {
    printf("%d ", counters[j]);
  }

  putchar('\n');
}

loopn((int[]){ 1, 2, 3, 4, 5 }, (int[]){ 2, 4, 6, 8, 10 }, (int[5]){}, 5, test);

Try it online!

如果您需要做的是真正的变量 N,那么 Patrick 的递归方法是一种可行的方法。

如果您尝试做的是固定变量N并且您试图避免重复输入for循环,您可以使用宏来保存一些击键:

#define LOOP(N) for (int i#N = i#N#_min; i#N < i#N#_max; ++i#N )

LOOP(1)
LOOP(2)
LOOP(3)
LOOP(4)
LOOP(5) {
   val = i1+i2+i3+i4+i5; // example calculation
}

可以将N维space表示为1维,有一个索引,如果需要可以从中计算出N个子索引。

下面我附上了这种 space 扁平化

的示例实现
#include <stdio.h>

int bonds[][2] = {
  {1, 2},
  {5, 10},
  {0, 3},
  {6, 8}
};

int get_index(int index_position, int current, int sizes[], int sizes_size) {
  int mod = 1;
  for(int i = index_position; i < sizes_size; i++) {
    mod *= sizes[i];
  }

  int div = mod / sizes[index_position];

  return (current % mod) / div;
}

int main(int argc, char** argv) {

  int sizes[] = {
    bonds[0][1] - bonds[0][0],
    bonds[1][1] - bonds[1][0],
    bonds[2][1] - bonds[2][0],
    bonds[3][1] - bonds[3][0]
  };

  int big_size = sizes[0] * sizes[1] * sizes[2] * sizes[3];

  for(int i = 0; i < big_size; i++) {
    /* get indexes */

    /*
    int i0 = ((i % (sizes[0] * sizes[1] * sizes[2] * sizes[3])) / (sizes[1] * sizes[2] * sizes[3])) + bonds[0][0];
    int i1 = ((i % (           sizes[1] * sizes[2] * sizes[3])) / (           sizes[2] * sizes[3])) + bonds[1][0];
    int i2 = ((i % (                      sizes[2] * sizes[3])) / (                      sizes[3])) + bonds[2][0];
    int i3 = ((i % (                                 sizes[3]))                                   ) + bonds[3][0];
    */

    int i0 = get_index(0, i, sizes, 4) + bonds[0][0];
    int i1 = get_index(1, i, sizes, 4) + bonds[1][0];
    int i2 = get_index(2, i, sizes, 4) + bonds[2][0];
    int i3 = get_index(3, i, sizes, 4) + bonds[3][0];

    printf("%d %d %d %d\n", i0, i1, i2, i3);
  }

  return 0;
}

bonds/sizes 数组的动态处理超出了此处的范围。该示例显示了如何从展平 space.

计算子索引