如何访问具有多个括号的一维数组以提高可读性?
How to access 1D arrays with multiple brackets for readability?
我有一个庞大的代码,它使用一个由指针管理的 3D 数组。类似于:
int *** tab;
tab = malloc(m*sizeof(int**));
for(i= 1..n) tab[i] = malloc(n*sizeof(int*));
... etc...
之后,元素通过以下方式访问:
tab[i][j][k] = ...
但由于此结构存在特定问题,我想将制表符声明为连续数组,但在代码中仍使用带有 3 个括号的语法。编译器将在内部像这样替换它们:
tab[i][j][k] = ... => tab[i*m*n+j*m+k] = ...
所以只用一个指针解引用访问数组。我不想更改源代码(没有 sed)。
例如,我可以通过在堆栈中声明选项卡来做到这一点:
int tab[n][m][l];
但不幸的是,如果 m
和 n
是运行时变量,这将不起作用。
要实现这一点,您可以先分配完整的 "tab"
int* tab = malloc(sizeof(int)* i * j * k);
这将为您提供数据。该指针将作为数组的所有者。
之后,您可以通过构建指向 tab 变量的访问指针数组来创建“3d”数组。这将导致你有一个 int*** access;
,它的所有内部指针都指向 tab
的正确部分,允许你通过 access
.[=17 访问 tab
=]
这假设您坚持使用 C 风格代码。
如果您希望使用 C++ 样式执行此操作:
参见:What is the most efficient way to initialize a 3D vector?
这个 post 为使用 std::vector
做同样的事情提供了一个很好的起点
对于尺寸为 n
x m
的二维 int
数组,您可以这样做(在 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()
.
来完成所有事情
您已将其标记为 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.
当然,所有这些都将访问具有单一遵从的元素。但是计算索引涉及许多乘法,这些乘法也不是特别便宜的操作。有必要进行测试以确定哪个更多 efficient/effective.
C++ 方法是将 3D 数组包含在 class 中以获得 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& val(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]
,你可以使用辅助 Arr2D class 能够在 2D 上提供 view数组:
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]
...
在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]
,在这两种情况下都省略了最左边的维度。
#define SUB(x,y,z) ((x)*m + (y))*n + (z)
. . . . .
tab[SUB(i,j,k)] = ....
我有一个庞大的代码,它使用一个由指针管理的 3D 数组。类似于:
int *** tab;
tab = malloc(m*sizeof(int**));
for(i= 1..n) tab[i] = malloc(n*sizeof(int*));
... etc...
之后,元素通过以下方式访问:
tab[i][j][k] = ...
但由于此结构存在特定问题,我想将制表符声明为连续数组,但在代码中仍使用带有 3 个括号的语法。编译器将在内部像这样替换它们:
tab[i][j][k] = ... => tab[i*m*n+j*m+k] = ...
所以只用一个指针解引用访问数组。我不想更改源代码(没有 sed)。
例如,我可以通过在堆栈中声明选项卡来做到这一点:
int tab[n][m][l];
但不幸的是,如果 m
和 n
是运行时变量,这将不起作用。
要实现这一点,您可以先分配完整的 "tab"
int* tab = malloc(sizeof(int)* i * j * k);
这将为您提供数据。该指针将作为数组的所有者。
之后,您可以通过构建指向 tab 变量的访问指针数组来创建“3d”数组。这将导致你有一个 int*** access;
,它的所有内部指针都指向 tab
的正确部分,允许你通过 access
.[=17 访问 tab
=]
这假设您坚持使用 C 风格代码。
如果您希望使用 C++ 样式执行此操作:
参见:What is the most efficient way to initialize a 3D vector?
这个 post 为使用 std::vector
对于尺寸为 n
x m
的二维 int
数组,您可以这样做(在 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()
.
您已将其标记为 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.
当然,所有这些都将访问具有单一遵从的元素。但是计算索引涉及许多乘法,这些乘法也不是特别便宜的操作。有必要进行测试以确定哪个更多 efficient/effective.
C++ 方法是将 3D 数组包含在 class 中以获得 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& val(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]
,你可以使用辅助 Arr2D class 能够在 2D 上提供 view数组:
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]
...
在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]
,在这两种情况下都省略了最左边的维度。
#define SUB(x,y,z) ((x)*m + (y))*n + (z)
. . . . .
tab[SUB(i,j,k)] = ....