C 如何分配数组起始负索引

C 如何分配数组起始负索引,c,C,我正在尝试分配一个3D阵列u[-nx/2:nx/2-1][-nx/2:nx/2-1][-nx/2:nx/2-1] int nx = 512; double *** u = (double ***)malloc(nx * sizeof(double**)); for (int i = -nx/2; i < nx/2; i++) { u[i] = (double **)malloc(nx * sizeof(double *)); for

我正在尝试分配一个3D阵列u[-nx/2:nx/2-1][-nx/2:nx/2-1][-nx/2:nx/2-1]

    int nx = 512;
    double *** u = (double ***)malloc(nx * sizeof(double**));

    for (int i = -nx/2; i < nx/2; i++) {
        u[i] = (double **)malloc(nx * sizeof(double *));
        for (int j = -nx/2; j < nx/2; j++) {
            u[i][j] = (double *)malloc(nx * sizeof(double));
        }
    }
intnx=512;
双***u=(双***)malloc(nx*sizeof(双***));
for(int i=-nx/2;i

这是正确的方法吗?如果不是,我应该如何更改它?

不,这不正确。你可以通过把每个指针放在它表示的维度中间:
intnx=512;
双***u=(双***)malloc(nx*sizeof(双***))+nx/2;
for(int i=-nx/2;i
但这是不寻常的和令人困惑的,需要进行大量单独的分配,并且必须在解除分配步骤中撤消

考虑一个具有访问器的块:

#定义NX 512
/*如果nx是动态的,则只需加倍*即可,并手动计算索引*/
双[NX][NX][NX]*u=malloc(sizeof(*u));
双数组(双[NX][NX][NX]const*u,int i,int j,int k){ 返回u[i+NX/2][j+NX/2][k+NX/2]; } 无效数组_集(双[NX][NX][NX]*u,int i,int j,int k,双值){ u[i+NX/2][j+NX/2][k+NX/2]=值; }
不,那不正确。你可以通过把每个指针放在它表示的维度中间:
intnx=512;
双***u=(双***)malloc(nx*sizeof(双***))+nx/2;
for(int i=-nx/2;i
但这是不寻常的和令人困惑的,需要进行大量单独的分配,并且必须在解除分配步骤中撤消

考虑一个具有访问器的块:

#定义NX 512
/*如果nx是动态的,则只需加倍*即可,并手动计算索引*/
双[NX][NX][NX]*u=malloc(sizeof(*u));
双数组(双[NX][NX][NX]const*u,int i,int j,int k){ 返回u[i+NX/2][j+NX/2][k+NX/2]; } 无效数组_集(双[NX][NX][NX]*u,int i,int j,int k,双值){ u[i+NX/2][j+NX/2][k+NX/2]=值; }
首先,所有C数组的索引值范围为
0
元素计数-1
。总是

当您使用malloc时,我假定
nx
的值仅在运行时定义。这排除了静态数组大小,因此排除了使用cute
arr[x][y][z]
语法,如中所示:

#define NX 512

double arr[NX][NX][NX];

void foo(void)
{
   ...
   arr[z1][y1][x1] += 2 * arr[z2][y2][x2];
   ...
}
这反过来意味着,要使3D阵列的功能具有
nx
不同的三维值,您需要分配一个大小为
nx\u cubed=nx*nx*nx
的线性存储区域。要正确计算该值
nx_cubed
,需要检查整数溢出

此外,还需要将有符号的
int
坐标值正确转换为基于0的索引范围中使用的无符号
size\t

if (nx < 0) {
    fprintf(stderr, "negative value of nx\n");
    exit(EXIT_FAILURE);
}

const size_t unx = nx;
const size_t nx_cubed = unx * unx * unx;
/* TODO: Complete check for overflows */
if (nx_cubed < unx) {
    fprintf(stderr, "nx_cubed overflow\n");
    exit(EXIT_FAILURE);
}
现在的问题是从
x
y
z
值计算数组索引,每个值的范围从
-nx/2
nx/2-1
。我建议编写一个函数,将该范围映射到
0
nx-1
范围,然后根据三个基于0的值计算适当的线性指数。同样,应执行适当的整数溢出检查

size_t array3index(const size_t nx, const int x, const int y, const int z) {
   const size_t half_nx = nx/2;
   /* zero based 3D coordinates,
    * this probably triggers some signedness warnings */
   const size_t x0 = half_nx + x;
   const size_t y0 = half_nx + y;
   const size_t z0 = half_nx + z;
   if ((x0 >= nx) || (y0 >= nx) || (z0 >= nx)) {
     fprintf(stderr, "Signed coordinate(s) out of range: (%d, %d, %d)\n",
             x, y, z);
     exit(EXIT_FAILURE);
   }
   const size_t idx = nx * (nx * z0 + y0) + x0;
   /* Assuming that we have already checked that nx*nx*nx does not
    * overflow, and given that we have checked for x0, y0, z0 to be
    * in the range of 0 to (nx-1), the idx calculation should not
    * have overflown here. */
   return idx;
}
然后您可以访问3D阵列,如

const i1 = array3index(nx, x1, y1, z1);
const i2 = array3index(nx, x2, y2, z2);

buf[i1] += 2*buf[i2];

考虑到
array3index
中需要的计算量,我将检查直接在
0
nx-1
域中进行数组迭代是否更有意义,如果您在计算中实际需要范围值,则仅将其转换为
-nx/2
nx/2-1
范围值。

首先,所有C数组的索引值范围为
0
元素计数-1
。总是

当您使用malloc时,我假定
nx
的值仅在运行时定义。这排除了静态数组大小,因此排除了使用cute
arr[x][y][z]
语法,如中所示:

#define NX 512

double arr[NX][NX][NX];

void foo(void)
{
   ...
   arr[z1][y1][x1] += 2 * arr[z2][y2][x2];
   ...
}
这反过来意味着,要使3D阵列的功能具有
nx
不同的三维值,您需要分配一个大小为
nx\u cubed=nx*nx*nx
的线性存储区域。要正确计算该值
nx_cubed
,需要检查整数溢出

此外,还需要将有符号的
int
坐标值正确转换为基于0的索引范围中使用的无符号
size\t

if (nx < 0) {
    fprintf(stderr, "negative value of nx\n");
    exit(EXIT_FAILURE);
}

const size_t unx = nx;
const size_t nx_cubed = unx * unx * unx;
/* TODO: Complete check for overflows */
if (nx_cubed < unx) {
    fprintf(stderr, "nx_cubed overflow\n");
    exit(EXIT_FAILURE);
}
现在的问题是从
x
y
z
值计算数组索引,每个值的范围从
-nx/2
nx/2-1
。我建议编写一个函数,将该范围映射到
0
nx-1
范围,然后根据三个基于0的值计算适当的线性指数。同样,应执行适当的整数溢出检查

size_t array3index(const size_t nx, const int x, const int y, const int z) {
   const size_t half_nx = nx/2;
   /* zero based 3D coordinates,
    * this probably triggers some signedness warnings */
   const size_t x0 = half_nx + x;
   const size_t y0 = half_nx + y;
   const size_t z0 = half_nx + z;
   if ((x0 >= nx) || (y0 >= nx) || (z0 >= nx)) {
     fprintf(stderr, "Signed coordinate(s) out of range: (%d, %d, %d)\n",
             x, y, z);
     exit(EXIT_FAILURE);
   }
   const size_t idx = nx * (nx * z0 + y0) + x0;
   /* Assuming that we have already checked that nx*nx*nx does not
    * overflow, and given that we have checked for x0, y0, z0 to be
    * in the range of 0 to (nx-1), the idx calculation should not
    * have overflown here. */
   return idx;
}
然后您可以访问3D阵列,如

const i1 = array3index(nx, x1, y1, z1);
const i2 = array3index(nx, x2, y2, z2);

buf[i1] += 2*buf[i2];
考虑到
array3index
中需要的计算量,我将检查直接在
0
nx-1
域中进行数组迭代是否更有意义,如果您在计算中实际需要范围值,则仅将其转换为
-nx/2
nx/2-1
范围值。

否。 C中的数组实际上只是普通/平面内存块,它总是基于0,并且总是在