Mallocing 3维数组

时间:2015-12-13 14:57:32

标签: c malloc libjpeg

我必须使用3维数组,因为我想将pic划分为正方形并存储我阵列中每个正方形的RGB平均值。 我希望它的大小为tab[height][width][3], 所以我这样做了:

i = 0; j = 0; k = 0;

    float*** tab;
    tab = malloc((hauteur+1)*sizeof(float*));

    while(i <= hauteur){
        tab[i] = malloc((largeur+1)*sizeof(float**) );
        i++;
    }
    i = 0;
    while(i <= hauteur){
        j = 0;
        while (j <= largeur){
            tab[i][j] = malloc(3*sizeof(float***));
            j++;
        }
        i++;
    }

但在tab[1][30][2];之后我有一个段错误。

我的malloc是否有问题?

这很奇怪,因为当我使用以下内容声明tab时,它不会出现段错误: tab[hauteur][largeur][3]

(对不起:“hauteur”在法语中表示“高度”,“largeur”表示“宽度”。)

(如果您认为需要检查我的整个功能:http://pastebin.com/eqQXz8Ad;它是JPEG文件的编写者。)

3 个答案:

答案 0 :(得分:2)

您的malloc来电中的类型并不正确。我建议如下:

tab = malloc( (hauteur + 1) * sizeof *tab );       // sizeof (float **)
tab[i] = malloc( (largeur + 1) * sizeof *tab[i] ); // sizeof (float *)
tab[i][j] = malloc( 3 * sizeof *tab[i][j] );       // sizeof (float)

鉴于tab的声明,以下都是正确的:

Expression                Type
----------                ----
       tab                float ***
      *tab                float **
    tab[i]                float **
   *tab[i]                float *
 tab[i][j]                float *
*tab[i][j]                float

我通常建议使用目标表达式的sizeof,而不是显式类型;这样,如果您更改tab的类型(例如,从float更改为double),则无需触及malloc来电。

答案 1 :(得分:1)

你正在制作的是一个浮动指针数组的数组,而不是浮点数的三维数组。 您可能需要查看此Ambiguity in 2d array declaration in C。它解决了二维数组的类似问题。

也许您问题的解决方案可能如下:

float (*tab)[hauteur][largeur][3];    //declare a pointer to a real array

tab = malloc(hauteur * largeur * 3 * sizeof(float));    //Allocate room for threedimensional array

for (int i=0; i<hauteur; i++)
    for (int j=0; j<largeur; j++)
        for (int k=0; k<3; k++)
        {
            (*tab)[i][j][k] = (float)((i*100)+j*1000+k);    //Fill elements with something using threedimensional subscripting
        }
for (int i=0; i<hauteur; i++)
    for (int j=0; j<largeur; j++)
        for (int k=0; k<3; k++)
        {
            printf("[%d][%d][%d]=%f\n", i, j, k, (*tab)[i][j][k]);    //Check back data...
        }

<强> EDITED 看看评论,我发现这是不自然的&#39;使用指向数组表示法(*array)[a][b]...[n]的指针访问数组,即使此表示法明确报告声明中的整个维度。为了使用更友好,您可以使用下面的表格,其中包含众所周知的格式:

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

int largeur = 10;
int hauteur = 10;

int main(int argc, char *argv[])
{
    float (*tab)[largeur][3];    //declare a bidimensional array of pointers to our variable
                               //this fools the compiler acting as a one more dimension array of variable

    tab = malloc(hauteur * largeur * 3 * sizeof(float));    //Allocate room for threedimensional array

    for (int i=0; i<hauteur; i++)
        for (int j=0; j<largeur; j++)
            for (int k=0; k<3; k++)
            {
                tab[i][j][k] = (float)((i*100)+j*1000+k);    //Fill elements with something using threedimensional subscripting
                //This use the natural addressing...
            }
    for (int i=0; i<hauteur; i++)
        for (int j=0; j<largeur; j++)
            for (int k=0; k<3; k++)
            {
                printf("[%d][%d][%d]=%f\n", i, j, k, tab[i][j][k]);    //Check back data...
            }
}

由于 C 语言缺乏多维数组概念,这种技巧很有效。
C只知道数组,或者更好的是它应该是 string ,所以二维数组只是一个数组的数组。如果我们再添加一个维度,它就是一个数组数组的数组......等等我们添加的每个维度。
这定义了C中数组的内存布局以及编译器用于访问数据的寻址方法。因为数据在内存中流式传输以访问特定下标的值,所以编译器需要计算用于所有维度的空间,但最先是。

+++我修复了一个错误,现在样本可以在任何符合C99-C11标准的编译器下编译并运行。

答案 2 :(得分:0)

如果你非常关心效率,你应该考虑使用单个维度数组(如Frankie_C's answer中所示):

 int height = something_to_compute_height();
 int width = something_to_compute_width();
 double *arr = malloc(height*width*3*sizeof(double));
 if (!arr) { perror("malloc"); exit(EXIT_FAILURE); }

(顺便说一句,即使我们都是母语为法语的人,我们也可以尝试在问题和代码中使用英语)

然后你可以定义一个宏来轻松说出arr

中的一些元素
#define ELEM_ARR(a,i,j,k) a[i*width*height+j*width+k]
#define ARR(i,j,k) ELEM_ARR(arr)

(你已经明白了,细节可能会有所不同)

由于cache位置的原因,这可能比指针数组的指针数组更有效,因为你只需要一次分配。

谨慎选择row-major或专栏访问权限以适应最常用的访问模式。

如果height&amp; width特定于每个数组,您可以在struct中使用一些flexible array member作为最后一个。

根据经验,只有当所有维度(可能是最后一个维度)都是编译时常量时,在C中使用多维数组才有用。 double arr3d[3][4][5];;否则,最好有一个单维数组并自己进行索引计算。

顺便说一句,如果你非常关心性能,你可能会担心OpenCLOpenMP(而且两者通常都更喜欢单维数组)。