是否有可能编写一个可以接受n维数组的函数?

5
我正在尝试编写一个函数,可以接受任何维度的数组并成功打印数组中的值。但是我无法向前移动,因为在声明函数时必须声明除左侧最外维以外的所有维度。是否有可能编写通用函数,可以接受任何维数的数组作为输入?
例如,该函数应能够接受二维数组、三维数组或n维数组,其中n是任意数字。

1
可能可以使用可变参数模板实现。 - Some programmer dude
你也许可以以某种方式使用模板,但那会使程序容易出错,特别是因为听起来你正在与团队合作。 - Cartier
@JoachimPileborg 这取决于生成是否是随机的还是预定义的; 可变参数模板适用于预定义而非随机的情况。 - Cartier
答案似乎也取决于这是一个C还是C++问题,因为我认为C中不存在模板。 - user3386109
6个回答

10

使用递归来处理每个维度和模板(在C++中),以下可能会有所帮助:

template <typename T>
void print(const T&e)
{
    std::cout << e << " ";
}

template <typename T, std::size_t N>
void print(const T (&a)[N])
{
    std::cout << "{";
    for (const auto& e : a) {
        print(e);
    }
    std::cout << "}" << std::endl;
}

用例:

int a[2][3][4];
print(a);

实时示例

(涉及it技术)

@RaydelMiranda:如果需要,for range 可以编写为 C++03 兼容(一个简单的 print(a[i]); 就可以完成任务)。 - Jarod42
@RaydelMiranda:for (std::size_t i = 0; i != N; ++i) { print(a[i]); } - Jarod42
我知道你可以这样写,但是你发布的代码只有在编译器支持C++11时才能编译通过。这不是批评,只是对读者的警告。 - Raydel Miranda
我会删除我的回答并点赞你的,我看到我接近了但还不够; p。 - Raydel Miranda
太好了。直到现在我还以为我们甚至在C++中也做不到。 - kadina
显示剩余2条评论

3
如果您想访问特定元素或操作数组,但又想动态创建矩阵,则可以使用指针通过在打印函数中传递维度来访问每个元素。
因此,如果您定义了一个多维数组为int [][],那么x = y[a][b]等同于x = *((int *)y + a * NUMBER_OF_COLUMNS + b); 有关更多详细信息,请查看此帖子:如何使用指针表达式访问C语言中的二维数组元素? 因此,如果您想打印整个矩阵或访问任何特定元素,可以像这样做:
#include <iostream>
using namespace std;

//the function print_2D_matrix receives 4 arguments: pointer to first element
//                                                   dimension of array arr, i.e. n x m
//                                                   index of the element to be printed, i.e. a and b
void print_2D_matrix(int *arr, int n, int m, int a, int b){
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++)
            printf("%d ", *(arr + (i * m) + j));
        printf("\n");
    }
    //go to the address just before a row, i.e. (a - 1) * NO_OF_COLUMNS 
    //then go to the address on b column, i.e. (a - 1) * NO_OF_COLUMNS + b
    //since we started from the base address, i.e. first element( arr[0][0] ), subtract 1 
    printf("arr[3][3] = %d\n", *(arr + ((a - 1) * m) + b - 1));    //print arr[a][b]
} 

int main() {
    int n, m;
    cin>>n>>m;
    int arr[n][m];

    for(int i = 0; i < n; i++)    //initialize the matrix
        for(int j = 0; j < m; j++)
            arr[i][j] = i * j;

    print_2D_matrix((int *) arr, n, m, 3, 3);

    return 0;
}

上述程序的输出结果(对于 n x m = 4 x 5)如下:

0 0 0 0 0
0 1 2 3 4
0 2 4 6 8
0 3 6 9 12
arr[3][3] = 4

3

如果您将数组编码为一维数组,然后自己计算单个索引,那么您肯定可以让程序像为可变数量维度的数组那样运行。

我最初的想法是从包含每个要使用的维度的范围的向量开始。

该向量中的元素数目就是您所拥有的维度数。


3

将数组作为指向数组元素类型的指针传递给函数,而不考虑数组的维度。您可以有进一步的参数来指定维数n和一个长度为n的数组(另一个数组)来指定每个维度中的元素数量。请注意,[]符号仅是执行指针加法的整洁方式。


0

我相信这违反了C标准的至少一个规则,但在实践中应该可以工作。请注意,它使用0作为任何级别数组的终止元素的哨兵值。

void print(void* p, int dim)
{
    if (dim == 1)
    {
        int* a = (int*) p;
        while (*a)
        {
            printf("%d ", *a++);
        }
        printf("\n");
    }
    else
    {
        void** a = (void**)p;
        while (*a)
        {
            print(*a++, dim - 1);
        }
    }
}

void test()
{
    int x0 [] = { 11, 12, 13, 14, 15, 0 };
    int x1 [] = { 21, 22, 23, 0 };
    int x2 [] = { 0 };
    int x3 [] = { 41, 42, 0 };
    int x4 [] = { 51, 52, 53, 0 };
    int* y0 [] = { x0, x3, 0 };
    int* y1 [] = { 0 };
    int* y2 [] = { x1, x2, x4, 0 };
    int** z [] = { y0, y1, y2, 0 };

    print(z, 3);
}

输出:

11 12 13 14 15
41 42
21 22 23

51 52 53

1
请在给负评时添加评论。 - MooseBoys
你可以添加一些 const - Jarod42

0
我已经编写了一个函数,可以打印任何n维可迭代容器:
template<typename Object, typename Iterable>
void Print(
    const Iterable& iterable,
    const string& separatorDimensions = "\n",
    const function<void(const Object&)>& funcPrintElem = [] (const Object& obj) {
        static_assert(
            is_arithmetic_v<Object> || is_same_v<remove_const_t<remove_pointer_t<Object>>, char>,
            R"(The object from the innermost range is not a built-in/c-string type, please provide a valid print element function.)"
            );
        cout << obj << ' ';
    }
) {
    if constexpr (ranges::range<Iterable>) {
        ranges::for_each(iterable, [&] (const auto& it) { Print(it, separatorDimensions, funcPrintElem); });
        cout << separatorDimensions;
    } else {
        funcPrintElem(iterable);
    }
}

该函数具有一个默认的std::function,可以打印任何内置类型,如intunsigned charlong long等,以及c字符串,如char*或const char*,如果您有另一个对象,如pairtuple或您的类的对象,您可以传递一个打印您的对象的函数。

您可以像这样使用该函数:(您必须明确告诉函数您的最内部对象,如下所示)

int main() {
    cout << "v: " << endl;
    vector<uint16_t> v { 1, 2, 3 };
    Print<uint16_t>(v);

    cout << endl << "ll: " << endl;
    list<list<const char*>> ll { { "a", "b" }, { "c", "d" } };
    Print<const char*>(ll);

    struct smth {
        int a;
        char b;
    };

    cout << endl << "smths: " << endl;
    vector<smth> smths { { 14, '0' }, { 18, '1' } };
    Print<smth>(smths, "\n", [] (const smth& obj) { cout << "a = " << obj.a << ", b = " << obj.b << endl; });

    return 0;
}

你可以在这里找到该函数,也许将来我会更新以支持更多功能。

你需要至少c++20才能运行该函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接