在C中动态设置数组访问模式

我想在C(99)中做这样的事情:

int n = compute_size_of_matrices(); int T = compute_number_of_matrices(); float matrices[][n][n] = malloc( sizeof(float) * n*n* T ); //[sic!] 

观察第一维中缺少的大小。 我想动态设置维度的大小,以便执行以下操作

 /* Load each matrix with the unit matrix */ for( int t = 0; t < T; t++ ) for( int i = 0; i < n; i++ ) for( int j = 0; j < n; j++ ) matrices[t][i][j] = (i==j)?1.:0.; 

当然,我可以简单地将’矩阵’分配为一维数组并使用一些索引魔法,但显然上面对数组的访问模式更方便。 特别是,除了记住动态数组大小的一些开销之外,编译器没有技术黑魔法。 是否有GCC的编译器扩展,某些方言function或类似function允许我执行上述操作?

与此相反,为了避免歧义,上述任务的常用C代码如下所示:

 int n = compute_size_of_matrices(); int T = compute_number_of_matrices(); float* matrices = malloc( sizeof(float) * n*n* T ); //[sic!] for( int t = 0; t < T; t++ ) for( int i = 0; i < n; i++ ) for( int j = 0; j < n; j++ ) matrices[t*n*n + i*n + j] = (i==j)?1.:0.; 

在实际示例中,单字母变量可能具有更多的声音名称,这很快会使这样的代码片段变得笨拙。

最好的我找到了

保留matricies的数组大小属性(虽然不是矩阵列表 ),并允许您使用本机索引表示法

  int n=5, T=2; float (*a)[n][n] = calloc(T,sizeof(float[n][n])); // <== initializes to 0! for (size_t t=0; t 

指向2d数组的指针的声明是棘手的部分,但是calloc (见下文)负责为你进行零初始化,所以你只设置非零元素。

当然,有趣的部分来自于你试图传递这些东西......但如果你小心你的声明并使用c99你可以制作任何一个

 void foo(int n, float (*a)[n][n]) { // ... } void bar(int t, int n, float a[t][n][n]) { // ... } 

工作。 (实际上gcc会让你逃脱,除非你使用-std=c89 -pendantic ......)

第二好,但它将与ansi-c一起使用

你当然可以使传统版本(丑陋的手索引)更容易阅读。

 int n = compute_size_of_matrices(); int T = compute_number_of_matrices(); float* matrices = calloc(T, sizeof(float) * n*n); // <== initializes to 0! for( int t = 0; t < T; t++ ) for( int i = 0; i < n; i++ ) matrices[t*n*n + i*n + i] = 1; // <== only set the 1's 

好吧,这似乎是一个好主意......

唉c不会让你这么做

  int n=5, T=2; float matrices[T][n][n] = {}; // <== ***ERROR!!!*** 

这将让你保持matricies的“arrays性”,甚至更清晰。

它慢吗?

因为calloc将使用一些高度优化的系统内存写入器设置为0,所以你不会受到很大的速度影响。

RE:第一个方向缺少尺寸

您可以省略数组中第一个维度的原因是因为编译器可以根据您在初始化期间传递的值的数量来确定大小。

例:

 int arr[] = { 0,1 }; // arr size is 2 int arr[][2] = { {0,1}, {0,1} }; // arr size is 2, // each element points to an array of size 2 

等……

另一个案例:

 float * arr = calloc(float, sizeof(float) * n); 

在这里,你为n浮点数和arr点分配了连续内存。 您可以通过指针算术或数组下标来访问元素,该数组下标为您执行指针算术运算。

在所有情况下,一旦定义了数组(在声明之后的下一行或指针指向实际存储器),就确定数组的每个维度的大小。

编译器不记得大小,如果你使用数组外的数组下标,你正在访问不属于数组的内存…