且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

在C中的运行时生成嵌套循环

更新时间:2022-06-23 02:22:49

您可以通过构造一些数据来充当迭代器并将其视为要迭代的单个对象来完成此操作.该数据将为您要迭代的每个维度包含一个单独的计数器,并且将通过自身在每个维度上进行迭代的函数对其进行初始化,测试和递增.这是一个使用简单数组作为计数器的示例.

You can do this by constructing some data to act as an iterator and treating it as a single thing that is iterated. That data will contain a separate counter for each dimension you wish to iterate, and it will be initialized, tested, and incremented by functions that themselves iterate over each dimension. Here is an example using a simple array for the counters.

#include <string.h>


//  Initialize counters to their start values.
static void InitializeCounters(long N, long *Counters, const long *Starts)
{
    memcpy(Counters, Starts, N * sizeof *Counters);
}


//  Return 1 if there are more values to iterate, 0 otherwise.
static int MoreToIterate(long N, long *Counters, const long *Ends)
{
    return Counters[0] < Ends[0];
}


//  Increment the counters, lexicographic (dictionary/odometer) style.
static void IncrementCounters(long N, long *Counters, const long *Starts,
    const long *Ends)
{
    /*  Increment each dimension (except the first will be special).  If it
        rolls over its end, reset it to its start and go on the next dimension.
        If it does not roll over, stop there.
    */
    for (long i = N-1; 0 < i; --i)
        if (++Counters[i] < Ends[i])
            return;
        else
            Counters[i] = Starts[i];

    /*  For dimension zero, do not reset it, so MoreToIterate can see it
        finished.
    */
    ++Counters[0];
}


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


static void _Noreturn Usage(char *argv[])
{
    fprintf(stderr, "Usage: %s <N>\n", argv[0]);
    exit(EXIT_FAILURE);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
        Usage(argv);

    char *end;
    long N = strtol(argv[1], &end, 0);
    if (*end != '\0')
        Usage(argv);

    if (N < 0)
        Usage(argv);

    long *Counters = malloc(N * sizeof *Counters);
    long *Starts   = malloc(N * sizeof *Starts);
    long *Ends     = malloc(N * sizeof *Ends);
    if (!Counters || !Starts || !Ends)
    {
        fprintf(stderr, "Error, unable to allocate memory.\n");
        exit(EXIT_FAILURE);
    }

    //  Initialize start and end values as desired.
    for (long i = 0; i < N; ++i)
    {
        Starts[i] = 0;
        Ends[i]   = i+1;
    }

    for (   InitializeCounters(N, Counters, Starts);
            MoreToIterate(N, Counters, Ends);
            IncrementCounters(N, Counters, Starts, Ends))
    {
        for (long i = 0; i < N; ++i)
            printf("%ld ", Counters[i]);
        printf("\n");
    }

    free(Ends);
    free(Starts);
    free(Counters);
}

使用参数"3"执行时的示例输出为:

Sample output when executed with argument "3" is:


0 0 0 
0 0 1 
0 0 2 
0 1 0 
0 1 1 
0 1 2