1

C にポインター変数があります。参照int ***aとして関数に渡してい&aます。関数では、 type のポインター変数を取得していますint ****a。このようにメモリを割り当てています。

*a=(int***)malloc(no1*sizeof(int**));
some loop from 0 to no1
    (*a)[++l]=(int**)malloc((no1+1)*sizeof(int*));
some loop from 0 to no1
    (*a)[l][h]=(int*)malloc(2*sizeof(int));

これは、メモリを割り当てたときだけです。実際のプログラムは与えられていません。ここでエラーはありません。しかし、私がこれを行うとき:

(*a)[l][h][0]=no1;

「セグメンテーション違反」エラーが発生し、その理由がわかりません。

更新: メモリのみを割り当てるサンプル プログラムを作成しました。これにより、「セグメンテーション違反」エラーも発生しています。

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

void allocate(int ****a)
{
    int i,j,k;
    if(((*a)=(int***)malloc(5*sizeof(int**)))==NULL)
    {
        printf("\nError in allocation of double pointer array\n");
        exit(0);
    }
    for(i=0;i<5;i++)if(((*a)[i]=(int**)malloc(4*sizeof(int*)))==NULL)
    {
        printf("\nError in allocation of single pointer array on index [%d]\n",i);
        exit(0);
    }
    for(i=0;i<5;i++)
        for(j=0;j<4;i++)
            if(((*a)[i][j]=(int*)malloc(3*sizeof(int)))==NULL)
            {
                printf("\nError in allocation of array on index [%d][%d]\n",i,j);
                exit(0);
            }
    for(i=0;i<5;i++)
        for(j=0;j<4;i++)
            for(k=0;k<3;k++)
                (*a)[i][j][k]=k;
}

main()
{
    int ***a;
    int i,j,k;
    allocate(&a);
    for(i=0;i<5;i++)
        for(j=0;j<4;i++)
            for(k=0;k<3;k++)
                printf("\na[%d][%d][%d]  = %d ",i,j,k,a[i][j][k]);
}
4

3 に答える 3

4

申し訳ありませんが、率直に言うと、これは 3D 配列を処理する恐ろしい方法ですmalloc()。うん!:o)

(HPC コミュニティで) これを行う従来の方法は、1 次元配列を使用し、自分でインデックス計算を行うことです。indexinx 平面x方向にj反復し、ny 鉛筆y方向にk反復し、nzセルをz方向に反復するとします。次に、鉛筆にnz要素があり、平面にnz*ny要素があり、「レンガ」全体にnz*ny*nx要素があります。したがって、構造全体を次のように反復処理できます。

for(i=0; i<nx; i++) {
    for(j=0; j<ny; j++) {
        for(k=0; k<nz; k++) {
            printf("a(%d,%d,%d) = %d\n", i, j, k, a[(i*ny+j)*nz+k]);
        }
    }
}

この構造の利点はmalloc()、入れ子になった呼び出しを大量に呼び出すのではなく、への 1 回の呼び出しで割り当てることができることです。

int *a;
a = malloc(nx*ny*nz*sizeof(int));

この構造x=a[i][j][k]には 3 つのレベルの間接性があります。メモリからアドレスを取得する、a、オフセットを追加する、i、メモリからそのアドレスを取得a[i]する、 、オフセットを追加する、 、jメモリからそのアドレスを取得するa[i][j]、 、オフセットを追加する、k、および (最後に) データをフェッチしますa[i][j][k]。これらの中間ポインターはすべて、キャッシュラインと TLB エントリーを浪費しています。

構成x=a[(i*ny+j)*nz+k]には、2 つの追加の整数乗算を犠牲にして、 1レベルの間接性があります。データ。

さらに、データ アクセス パターンに基づいてトリプル インダイレクション方式のパフォーマンスを向上させる方法は、基本的にまったくありません。実際にすべてのセルにアクセスしている場合、インデックス計算のオーバーヘッドの一部を回避するために、このようなことを行うことができます。

ij = 0;
for(i=0; i<nx; i++) {
    ii=i*ny;
    for(j=0; j<ny; j++) {
        ij=(ii+j)*nz;
        for(k=0; k<nz; k++) {
            printf("a(%d,%d,%d) = %d\n", i, j, k, a[ij+k]);
        }
    }
}

何をしているかによっては、これもうまくいかない可能性があり、アクセスパターンによっては、より適切な代替レイアウトとインデックス作成方法 (モートンやアーネントイフェルのインデックス作成など) がすべて存在します。私は 3D デカルト グリッド表現やインデックス作成について完全な論文を書こうとしているわけではなく、単に「3 つ星」ソリューションが多くの理由で非常に悪いことを示しているだけです。

于 2013-09-02T20:52:48.570 に答える
0

使用(*a)[l][h][0]することで、ポインターではなくプレーンな int を逆参照しようとしています。

直接使用a[l][h][0]して任意の値を割り当てます。

于 2013-09-02T19:28:41.790 に答える