如何访问具有多个括号的一维数组以提高可读性?

问题描述 投票:0回答:6

我有一个使用指针管理的 3D 数组的庞大代码。比如:

int *** tab;
tab = malloc(m*sizeof(int**));
for(i= 1..n) tab[i] = malloc(n*sizeof(int*));  
... etc...

然后可以通过以下方式访问元素:

tab[i][j][k] = ...

但是由于此结构的具体问题,我想将 tab 声明为连续数组,但在代码中仍然使用带有 3 个括号的语法。编译器将在内部替换它们,如下所示:

tab[i][j][k] = ...  =>  tab[i*m*n+j*m+k] = ...

因此,仅通过一次指针取消引用即可访问该数组。我不想更改源代码(没有 sed)。

例如,我可以通过在堆栈中声明选项卡来做到这一点:

int tab[n][m][l];

但不幸的是,如果

m
n
是运行时变量,则这不起作用。

c++ c multidimensional-array c-preprocessor square-bracket
6个回答
5
投票

C++ 方法是将 3D 数组包含在类中以拥有 natural 访问器:

struct Arr3D
{
    int *arr;
    const int n, m, p; //size of the tab in 3 dimensions

public:
    Arr3D(int n, int m, int l): n(n), m(m), p(l) {
        arr = new int[n * m * p];
    }

    ~Arr3D() {
        delete[] arr;
    }

    int& operator()(int i, int j, int k) {   // read-write accessor
        // optionaly test for 0<=i<n...
        return arr[k + p * (j + i * m)];
    }
};

您只需使用以下命令即可创建和使用数组:

Arr3D * parr = new Arr3D(3,4,5); // dynamic allocation
Arr3D arr(3, 4, 5);              // automatic allocation
...
arr(1,2,3) = 5;
int i = arr(2,0,1);

或者,如果您想保留语法

tab[i][j][k]
,则可以使用能够在 2D 数组上提供 view 的辅助 Arr2D 类:

struct Arr2D
{
    int *arr;
    const int n, m; //size of the tab in 2 dimensions
    const bool is_view;

public:
    Arr2D(int n, int m): n(n), m(m), is_view(false) {
        arr = new int[n * m];
    }
    Arr2D(int *arr, int n, int m): arr(arr), n(n), m(m), is_view(true) {}

    ~Arr2D() {
        if (! is_view) delete[] arr;
    }

    int * operator[] (int i) {
        return arr + i * m;
    }
};

struct Arr3D
{
    int *arr;
    const int n, m, p; //size of the tab in 3 dimensions

public:
    Arr3D(int n, int m, int l): n(n), m(m), p(l) {
        arr = new int[n * m * p];
    }

    ~Arr3D() {
        delete[] arr;
    }

    Arr2D operator[](int i) {
        return Arr2D(arr + i * p * m, m, p);
    }
};

您现在可以简单地使用

arr[i][j][k]
...


4
投票

要实现此目的,您可以首先分配完整的“选项卡”

int* tab = malloc(sizeof(int)* i * j * k);

这将为您提供您的数据。该指针将作为数组的所有者。

之后,您可以通过构建 tab 变量的访问指针数组来创建“3d”数组。这将导致您拥有一个

int*** access;
,其所有内部指针都指向
tab
的正确部分,允许您通过
tab
访问
access

这假设您坚持使用 C 风格代码。

如果您希望使用 C++ 风格来执行此操作:

参见:初始化 3D 矢量最有效的方法是什么?

这篇文章为使用

std::vector

做同样的事情提供了一个很好的起点

2
投票

在 C(C99 或 C11)中,维度可变的

tab
数组可以作为函数参数传递,只要其维度也在前面的参数中传递即可。这是一个例子来说明我的意思:

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

int sum3d(unsigned int dim_n, unsigned int dim_m, unsigned int dim_l,
          int tab[dim_n][dim_m][dim_l])
{
    int total = 0;
    int n, m, l;

    for (n = 0; n < dim_n; n++)
    {
        for (m = 0; m < dim_m; m++)
        {
            for (l = 0; l < dim_l; l++)
            {
                total += tab[n][m][l];
            }
        }
    }
    return total;
}

int main(void)
{
    unsigned int dim_n, dim_m, dim_l;
    unsigned int n, m, l;
    int tot;

    dim_n = 10;
    dim_m = 5;
    dim_l = 4;

    int (*tab)[dim_m][dim_l] = calloc(dim_n, sizeof(*tab));
    if (!tab)
    {
        fprintf(stderr, "Memory allocation failure!\n");
        exit(1);
    }
    for (n = 0; n < dim_n; n++)
    {
        for (m = 0; m < dim_m; m++)
        {
            for (l = 0; l < dim_l; l++)
            {
                tab[n][m][l] = 1;
            }
        }
    }

    printf("total = %d\n", sum3d(dim_n, dim_m, dim_l, tab));
    return 0;
}

在函数

sum3d
中,
tab
可以声明为
int tab[][dim_m][dim_l]
int (*tab)[dim_m][dim_l]
,在这两种情况下都忽略最左边的维度。


1
投票

您已将其标记为 C 和 C++,因此可能有不同的解决方案。

C 溶液的形式为

#include <stdlib.h>    /*  assumed */

int* tab = malloc(sizeof(int)*n*m*l);

tab[i*m*n+j*m+k] = 42;

free(tab);   /* when done */

这个 C 解决方案从技术上讲可以在 C++ 中使用(尽管需要将

(int *)
类型转换为
malloc()
的结果)。然而,在 C++ 中,这是不鼓励的,有利于

int* tab = new int[n*m*l];

tab[i*m*n+j*m+k] = 42;

delete [] tab;    // when done

更好的 C++ 方法是使用标准库

#include <vector>

std::vector<int> tab(n*m*l);

tab[i*m*n+j*m+k] = 42;

//  tab will be automatically released when it passes from scope.

当然,所有这些都将通过单一引用来访问元素。但计算索引涉及大量乘法,这些运算也不是特别便宜。有必要进行测试以确定哪个更有效。


0
投票

对于维度为

int
x
n
的二维
m
数组,您可以这样做(在 C 中):

size_t n;
size_t m;
...
// base all sizeof() calls directly on array so it's
// trivial to change the type from int to something else
int **array = malloc( n * sizeof( *array ) );
array[ 0 ] = malloc( n * m * sizeof( **array ) );
size_t rowSize = m * sizeof( **array );
for ( size_t i = 1; ii < m; ii++ )
{
    array[ i ] = array[ i - 1 ] + rowSize;
}

将其扩展到三个维度相当容易(添加错误检查也是如此......)

真正的技巧是通过单个调用

malloc()
来完成所有事情。


0
投票
#define SUB(x,y,z) ((x)*m + (y))*n + (z)

         . . . . .

tab[SUB(i,j,k)] = ....
© www.soinside.com 2019 - 2024. All rights reserved.